Iterating over SwiftUI views delivered in a Swift Package
The idea was iterate on shiny new SwiftUI code in a package. Turns out Xcode 11 Previews (as of beta 2) need some sheananigans to achieve that.
Straightforward Approach
Here we’ll try to have all the SwiftUI code in a package and continue development of a package enjoying live Views rendering.
Problem 1: SwiftUI Previews can not be rendered in an environment that does not have codesigning
Solution:
- create the package, close it Xcode — because a package can not be opened in two Xcode editors simultaneously
- create separate Xcode project with a terget that can be built for the platforms of interest (an iOS Framework, for example). We’ll need this wrapper-project only for rendering the package’s SwiftUI views
- drop the package into wrapper project, include into target dependency list
- now you can create SwiftUI wrapper view in the wrapper target
Now you can import the package into wrapper file and make sure it can be built.
Problem 2: Package is imported as module, so only public stuff can be seen from wrapper
Solution:
1. mark SwiftUI structs in the package aspublic
2. write constructors for Views in the package — you can’t use generated constructors of SwiftUI structs because they are generated as internal
Now you can see the rendered preview of a View.
Problem 3: you can not pin Preview of a View from wrapper target and edit code View from package
Solution: the most similar to on-demand rendering workflow I’ve succeeded to achieve was
- open two editors on one screen
- Editor one: canvas + editor, wrapper View from wrapper target
- Editor two: editor only, View from package
Now you can edit View from package, Cmd+B in order to build the target and pull changes from packet into the wrapper, then click on Resume button in the canvas in order to re-render wrapper View
Problem 4: you will not have build errors marked in the package editor and canvas will give “Failed to build active scheme” error
Solution:
- write code without errors
More Correct Approach
The easier approach will be to create a taget project first, develop everything we need as part of the project using live rendering as much as we want, then create a Package 📦 and drop the needed code to the package.