44
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftAdvent Calendar 2019

Day 13

SwiftUI と UIKit 混合環境で開発を行うときの tips 集

Last updated at Posted at 2019-12-12

はじめに

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.frameworkweak 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 に準拠させてあげます。具体的には、 UIViewControllerUIViewControllerRepresentable に、 UIViewUIViewRepresentable に準拠させてあげます。
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 を導入してみた

44
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
35

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?