はじめに
AkkeyTV という動画視聴アプリはこの記事執筆段階で UIKit と SwiftUI を用いて開発されています。
iOS13 未満は UIKit で構築された UI をロードし、 iOS13 以降では SwiftUI で構築された UI をロードするため、分岐処理が必要になります。また、1画面のために2パターンの UI 設計をする必要があるため、開発効率的にはよくありません。
ただ、 SwiftUI で設計する能力は今後必要になるため、勉強も兼ねて UIKit と SwiftUI の混合環境を選んでいます。
この混合環境を実現する上で学んだことをここにまとめたいと思います。
SwiftUI.framework の weak link
Carthage などでライブラリを追加した場合、 Xcode でパスの設定も行うと思います。Apple が提供する framework に関してはこれを行わなくても import して呼び出すことができます。これが Auto Link です。
これが iOS13 未満の端末でアプリを起動した際にも動いてしまうため、 SwiftUI が実装されているアプリはクラッシュしてしまいます。
解決方法ですが、明示的に SwiftUI.framework
を weak link
として設定してあげることで対応可能です。
Build Phases > Link Binary With Libraries > SwiftUI.framework [Optional]
UIHostingController
SwiftUI で設計されたものを UIKit 側から触るときは UIHostingController
を使用します。
SwiftUI で設計された SwiftUIView() というものを定義している場合、以下のように画面遷移を記述することができます。
guard #available(iOS 13.0.0, *) else { return }
let vc = UIHostingController(rootView: SwiftUIView())
self.present(vc, animated: true)
また、「すでに表示されてたら画面遷移処理を行わない」といった処理を行うときも UIHostingController
を用いて対応可能です。
guard #available(iOS 13.0.0, *) else { return }
let vc = UIHostingController(rootView: SwiftUIView())
let frontVC = ...
if !(frontVC is UIHostingController<SwiftUIView>) {
self.present(vc, animated: true)
}
*Representable
UIKit で設計されたものを SwiftUI 側から触るときは *Representable に準拠させてあげます。具体的には、 UIViewController
は UIViewControllerRepresentable
に、 UIView
は UIViewRepresentable
に準拠させてあげます。
UIKit で設計された AkkeyView() というものを定義している場合、以下のようにプレビューさせることができます。
import UIKit
#if canImport(SwiftUI) && DEBUG
import SwiftUI
@available(iOS 13, *)
struct AkkeyViewPreviews: PreviewProvider {
static var previews: some View {
Group {
AkkeyView()
.previewLayout(.fixed(width: 414, height: 100))
.previewDevice(PreviewDevice(rawValue: "iPhone XS Max"))
}
}
static var platform: PreviewPlatform? = .iOS
}
@available(iOS 13, *)
extension AkkeyView: UIViewRepresentable {
typealias UIViewType = AkkeyView
func makeUIView(context: Context) -> AkkeyView {
return .init()
}
func updateUIView(_ uiView: AkkeyView, context: Context) {
// Make parameter change for preview
}
}
#endif
さいごに
SwiftUI 導入を手助けする方法をいくつか考えていますので、よかったら参考にしてみてください。
AkkeyLab/AutoPreviewable
UIKit で設計された画面をプレビューするクラスを自動生成させる
AkkeyLab/XcodePreviewsTemplate
UIKit のクラスファイルを作成するときにプレビューするクラスを自動生成させる
AkkeyLab/StoryboardPreviewsBySwiftUI
実際のプロダクトに XcodePreviews を導入してみた