SwiftUIアプリにUaaLを組み込む ── Viewのライフサイクル管理方法の紹介
こんにちは!AnotherBallのiOSチームです。
以前の記事では、モバイルチームがAvvyのマルチリポジトリ構成を紹介しました。Kotlin Multiplatform (KMP) と Unity as a Library (UaaL)のビルド、配布、そして5つのリポジトリ間の連携について、全体像をお伝えしました。
Avvyの技術面で面白いところはUaaLとNativeの自然な組み込みにあると思います。今回の記事では、iOSに焦点を絞って、SwiftUIアプリの中にどのようにUaaLの画面を管理しているかを解説します。
前提:UnityとNativeの役割
Avvyの設計思想として、Unityは2Dアバターに関する機能のみを持つようにしています。Unityはアバターの描画やアバターのカスタマイゼーション(着せ替え)のUIを担っています。それ以外の機能やUIはNative側で実装して、Nativeの機能を最大限に使えるようにし、配信アプリらしい体験を提供できるように設計しました。
UaaLの制約:インスタンスは1つだけ
UaaLを使う上で大きな制約があります。Unityランタイムの複数インスタンスの読み込みはサポートされていないため、UaaLのViewは画面上に1つしか表示できません。同時に2つ表示しようとすると、片方が描画されません。
Avvyでは配信画面、アバターホーム、ガチャなど、複数の画面でアバターを表示しています。そのため、画面遷移のたびにUaaLのViewを付け替え、二つ同時に画面に存在しないようにする必要があります。しかし、各画面でこのライフサイクルを意識するのは煩雑で、意図しない不具合の可能性が高まります。
そこで、SwiftUIで専用View「UnityView」を作成して、管理を集約し、各画面からは通常のViewと同じ感覚で使えるようにしました。
配信画面の構成
例として配信画面を取り上げて解説します。配信画面ではUnityは一番下のレイヤーでアバターのレンダリングのみを担当し、NativeUIがその上にオーバーレイされています。
グレー色はUnityのアバターの描画領域で、黄色がNativeのオーバーレイです。Unityの領域はAvvyのiOSアプリではUnityViewと名付けています。SwiftUI側から見ると、通常のViewと同じようになります:
1 | UnityView(displayType: .liveStream) // UnityでロードしたいSceneを指定 |
Unityのライフサイクルを一切気にせず、画面を開く・閉じるだけでアバターの表示・非表示が切り替わります。
UnityViewの実装
UnityViewはUIViewControllerRepresentableで、内部にUnityViewControllerを持っています。なぜUIKitのViewControllerが必要かというと、UnityFrameworkが提供する描画ViewがUIKitのUIViewだからです。
例えばアバターホーム画面から配信画面をモーダルで表示した場合、UnityのViewを自動で最前の画面に付け替える必要があります。UnityViewControllerはviewWillAppear/viewWillDisappearのライフサイクルでこれを実現しています:
1 | public struct UnityView: UIViewControllerRepresentable { |
画面が表示されるとき(viewWillAppear)にUnityのViewを追加し、非表示になるとき(viewWillDisappear)にViewを外します。極めてシンプルな実装ですが、これだけで UnityのUIViewが一つのみ存在することを担保できます。
なお、View入れ替え処理と同時に、AvvyアプリではUnityの一時停止、再開も行なって、バッテリー消費とリソース負荷を抑えています。
まとめ
UaaLをNativeアプリに組み込む際、「同時に表示できるViewは1つだけ」という制約がありますが、UIViewControllerのライフサイクルを使ってViewの付け替えとリソース管理を自動化し、SwiftUIの UnityView としてラップすることで、それらを意識することなくアバター表示ができるようにしました。この構成により、AvvyはアバターアプリでありながらNativeアプリとしての操作感を保てています。
次回は、本記事に登場した「DisplayType」を使ってUnityに指定のSceneをロードさせる仕組みなど、NativeとUnityがどのようにコミュニケーションをしているかについてご紹介したいと思います。
We’re Hiring
AnotherBallでは、テスタブルでメンテナブルなアーキテクチャを大切にしており、同じ志を持つエンジニアを常に探しています。こうした仕事に興味があれば、ぜひお話しましょう!