KitchHike Tech Blog

KitchHike Product, Design and Engineering Teams

React Native アプリでSwiftUI を利用する方法について調べてみた

はじめに

最近、React Native Meets SwiftUI - Better Programming - Medium という記事が目に止まりました。今回はこの記事について調べてみました。React Native でSwitfUI のコンポーネントを利用する話です。 このトピックについて調べることにしたのは、純粋に技術的な興味からです。プロダクト開発的には、コストをかけてまでReact Native アプリからSwiftUI を使いたい場面は今の時点ではほぼ無いでしょう。ただし技術者としては、連携の仕組みを知っておくと他で何かの役に立つことがあるかもしれません。 今回調べてみて分かったのは、React Naive からSwiftUI を利用する方法は、一部はReact Native やSwiftUI のドキュメントに記載されている要素によって実現され、残りは独自の実装によって実現されるということです。

React Native で SwiftUI を扱うための仕組み

冒頭の記事では、ボタンをタップする度にカウントの表示が更新されるアプリの実装を紹介しています。 筆者の環境では Podfile を少し変更して、アプリを動作させることができました。

ReactNativeWithSwiftUITutorial

記事の中で紹介されているクラスは以下の4つです。これらのクラスが連携して、SwiftUI のコンポーネント (記事中の SwiftUIButton ) とReact Native との接続が成されます。

  • SwiftUIButtonManager
  • SwiftUIButtonProxy
  • UIHostingController
  • SwiftUIButton (SwiftUI のView)

SwiftUIButtonProxy

実装のポイントについて解説

具体的なコードについては、冒頭の記事をご覧ください。

基本的なReact Native の仕組みを利用

RCTViewManagerRCT_EXPORT_MODULE といった仕組みを利用して、JavaScript 側とネイティブ側view を連携させています。 ネイティブUI コンポーネントとReact Native との連携については、React Native の公式ドキュメントが参考になります。 Native UI Components · React Native

SwiftUI の仕組みを利用

SwiftUIButtonProxy の実態は UIHostingController のインスタンスです。現状はReact Native からSwiftUI を直接扱う仕組みが無く、ここではUIKit 経由でSwiftUI を利用する実装となっています。 UIKit とSwiftUI との連携については、Apple のチュートリアルが参考になります。 Interfacing with UIKit — SwiftUI Tutorials | Apple Developer Documentation

独自のマクロを定義

Objective-C がJavaScript からプロパティを受け取り、Swift がプロパティをSwiftUI のビューにセットするために、RCT_EXPORT_SWIFTUI_PROPERTYRCT_EXPORT_SWIFTUI_CALLBACK という独自のマクロを定義しています。これらは開発者がprop のカスタムセッターを作成できる、React Native の RCT_CUSTOM_VIEW_PROPERTY マクロに依存しているとのことです。 また、prop を UIHostingController に渡すためにはこれだけで十分でなく、view:proxy のペアをキーバリューストレージ (ネイティブのNSMutableDictiaonary のインスタンス) に保存するアイデアが必要だったようです。 そして、Objective-C からSwiftUI にprop を渡すために、SwiftUIButtonProxycountonCountChange のプロパティを定義しています。

ここまでの筆者の理解を図にすると、以下のようになりました。

React Native Meets SwiftUI

所感

React Native からSwiftUI を使うことは可能

React Native からSwiftUI のコンポーネントを利用することができるということが分かりました。

props の受け渡しに関する実装は複雑

React Native とObjective-C の基本的な連携のコードだけでなく、カスタムマクロやReact Native とObjective-C, SwiftUI との制約を回避するようなコードを書く必要があり、実装は複雑という印象を受けました。 開発時のデバッグも大変かもしれません。

Xcode 上でプレビューも出来たが中途半端

記事執筆時点では、SwiftUI の previews のコードを自分で追加することでXcode 上でUI のプレビューが表示できました。

// SwiftUIButton.swift
struct SwiftUIButton_Previews: PreviewProvider {
  static var previews: some View {
    SwiftUIButton()
  }
}

Xcode SwiftUI previews

ただしSwiftUI canvas のライブモードを利用しても、Xcode 上でprops のカウントが繰り上げられる挙動を再現することが出ませんでした。

SwiftUI のメリットの一つは、ソースコードとGUI の相互反映によるインタラクティブな開発体験です。今回はそれを得ることができませんでした。 (回避策としては、事前に他のプロジェクトでSwiftUI のコンポーネントを作っておいて、接続部分の実装だけReact Native アプリへの移植時に書くという開発フローが考えられます。)

現場で使えるのか

実際の開発現場で、React Native を使っていて、それに並行してSwiftUI でUI を開発する場面というのは考えにくいです。React Native アプリとSwiftUI 連携させる時というのは、既にSwiftUI で開発したUI コンポーネントを持っていて、それをどうしてもReact Native で使いたい時ということになるでしょう。(それもかなりのレアケースな気がしますが。) また、Xcode (SwiftUI, Swift) のバージョンアップやReact Naive のバージョンアップの影響で、実装したコードが動かなくなるという状況がありうるでしょう。運用する上で辛いことが起きるかもしれません。 今後のReact Native にアーキテクチャの変更が予定されており、開発者としてはその動向も見ていきたいところです。

まとめ

  • React Native からSwiftUI のコンポーネントを利用することはできる
  • 接続箇所の実装が多く必要。知識の分野はまたがるが、基本を押さえれば概ね対応できる雰囲気がある
  • わざわざReact Native アプリからSwiftUI を使いたい場面は今の時点では無さそう。今後SwiftUI の資産が増えたら状況が変わるかも

We're Hiring

キッチハイクでは、React Native アプリエンジニアを募集中です!

www.wantedly.com www.wantedly.com