Using SwiftUI Previews in Cocoapods framework libraries
In this article I will demonstrate you step by step how you can use SwiftUI previews not in Xcode application project but rather custom framework project (used for example with Cocoapods)
SwiftUI previews in Xcode 12 doesn’t work by default with dynamic libraries set as Mach-O Typ eand return error message like below.
Project target need to set this setting as excutable. But the problem is we want to have framework that is used for example as cocapods podspec used by other applications.
- You need to add another application target to such Xcode project like below
Thi new application project will be empty app with minimal code required, just Info.plist, some simple SwiftUI App implementation without any View, AppIcon.xcassets with App Icon set. You can also set AppDelegate in our App via @UIApplicationDelegateAdaptor to have access to UIApplicationDelegate implementation and do there some application wide resource loading ex. translations stored in plist filed loaded to dictionaries.
@main
struct DaystromPreviewApp: App {@UIApplicationDelegateAdaptor(AppDelegate.self)
private var delegate var body: some Scene {
WindowGroup { }
}
}
2. If Views/app needs to relay on external modules it should have this modules added to Podfile and install via pod install. Here you should use Podfile with multiple targets (or abstract target to inherit common Pods between multiple targets)
pod ‘RxSwift’, ‘~> 6.0’target ‘Daystrom’ doendtarget ‘DaystromPreview’ doend
3. Each View which we want to preview in Xcode should be added to this new app target
4. We also need to add to this app target all files that our View depends on.
Especially we need to add SwiftGen generated files with Localizations, Assets, Colors etc. we need to add all xcassets like Colors.xcassets, Assets.xcassets We need to add Localization.plist Resources required by your views depends on your project.
5. For ViewModels we need to define protocols like SomeViewModelProtocol to enable implementing simplified mock view models that will be injected in our previed views.
protocol SomeViewModelProcol: ObservableObject { }
final class SomeViewModel: SomeViewModelProtocol { }final class MockSomeViewModel: SomeViewModelProtocol { … }struct SomeView<VM: SomeViewModelProtocol>: View { … }struct SomeView_Previews: PreviewProvider { static var previews: some View {
SomeView(viewModel: MockSomeViewModel()
}
}
This way we are able to replace complex view model implementation that usually crashes our views with simplified mock view models that supply simplified preview data for our views.
6. The best place to place this Mock models, Mock viewModels, Mock services is Preview Content directory. This directory then should be added as Development Assets in Xcode project both in Framework and App targets.
Finally we can enjoy previews of our views in Xcode framework modules.
This solution enables to work with multiple cocoapods libraries that has dependencies to another libraries.