Unity2019.4.0でも動かしたので追記しました
ドキュメント
https://docs.unity3d.com/2019.3/Documentation/Manual/UnityasaLibrary.html
なお、WindowsやUWPでも使えるようになったようです
先日ベータ版が出たUnity 2019.3で、iOS/AndroidネイティブからUnityの機能を呼び出せる、Unity as a Libraryが使用できるようになりました。
Unity 2019.3では、UnityをJavaで書かれたAndroidネイティブアプリやObjective-Cで書かれたiOSネイティブアプリから制御できるライブラリとして使用できるようになります。たとえばAR機能だけUnityを使って既存のネイティブアプリに挿入するなど。https://t.co/tdqfZrz5ss pic.twitter.com/FwVU2D2hEG
— ユニティ・テクノロジーズ・ジャパン (@unity_japan) August 30, 2019
例えば家具のショッピングアプリに、家具配置のシミュレーションをするAR機能を付けたいとします。ショッピングの機能は通常はネイティブで作成されています。(Unityでも不可能ではないですが得意とする機能ではありません)
すると、現状ではAR機能もiOS/Androidのネイティブで作成する必要がありますが、SceneKitやSceneformでAR機能を構築するのはなかなか大変ですし、扱える技術者も比較的少ないと思われます。なので、AR機能だけを3Dを扱うのが得意なUnityで作成することができれば、クロスプラットフォームで作れますし、うまくいけばコストも安くなるはずです。
ということでなかなか注目の機能だと思うのですが、まずは理解のためにチュートリアルをやってみました。
ネイティブアプリからUnityを呼び出すUnity as a Library、写経レベルでは動いた。XcodeからUnityのシーンを呼び出して遷移するような動きみたい。(もっと深い連携ができるかはまだよくわからない)https://t.co/TfDaecT2aO pic.twitter.com/hPGdb4Rp8z
— とりカシュ (@torikasyu) September 1, 2019
基本的には下記に従って進めれば動きますが、少し補足しています。
Unity用のサンプルプロジェクトとXcode用のサンプルプロジェクトをダウンロード&解凍して、UssLExampleというフォルダを作成してどちらも入れておきます。
ここからサンプルプロジェクトをcloneします。
Unity用のサンプルプロジェクト「UnityProject」を見ると、Pluginsフォルダにネイティブとのブリッジを行うObjective-Cのコードが入っています。それ以外は通常のUnityのiOS用プロジェクトと大差はありません。
iOS用のXcodeプロジェクトを見ると、UIをコードで作成して、UnityFrameworkを呼び出してメッセージを送信しているような内容になっています。
Unityプロジェクトを開いてiOSビルドを行います。
僕の環境では、開いたときにPackage Managerでエラーが発生しました。
理由が不明なのでひとまずRemoveしました。
※2019.4で実行したらエラーは発生しませんでした
iOSのビルド先はAssetなどと同一の階層にiOSBuildという名前で指定しますが、これはいつものiOSビルドと特に変わるとことはありません(Unity as a Library特有の何かはありません)
ワークスペース(プロジェクトをまとめる機能)を新規作成して、「NativeiOSApp」以下の「NativeiOSApp.xcodeproj」と、Unityのビルド結果のiOSBuildフォルダ以下にある「Unity-iPhone.xcodeproj」を追加します(File > Add Files)
NativeiOSAppの方のプロジェクト設定で、Embedded Binariesに、Unityで生成した「Unity-iPhone/Products/UnityFramework.framework」を追加します。
この時、Linked Frameworks and LibrariesにもUnityFramework.frameworkが自動的に追加されてしまいますが、不要なので削除します。
Unity2019.4とXcode11.5の組み合わせでは削除は必要ありませんでした。
これにより、ネイティブ側でUnityの機能が参照できる状態になります。
NativeCallProxy.hは、もともとUnityプロジェクトのPluginsに存在したネイティブプラグインになります。Libraries > Plugins > iOS以下にあるので、選択して、右側にあるインスペクタのTarget Membershipで「UnityFramework」にチェックを入れて「Public」を選択します。これにより、ネイティブアプリからNativeCallProxyを通じてメッセージを受け取れるようになるみたいです。
Unity側のプロジェクトのDataフォルダがネイティブ側からも使用できるようにするため、Dataフォルダを選択して、同じくTarget Membershipで「UnityFramework」を選択します。
MainApp > main.mmに
[ufw setDataBundleId: "com.unity3d.framework"];
を追加します。正常にメモリの開放が行われるようにするためです。
これで準備が完了したので「NativeiOSApp」を実行しますが、前提として実機でしか動作しません(シミュレータで起動するとエラーとなります)。
これはUnity側の設定がDevice SDKになっているためだと思われます(シミュレータで動かすことも不可能ではないと思うのですがまだ試していません)
また、下記部分でコンパイルエラーが出たのでひとまずコメントアウトしました。
[UnityFrameworkLoad() unloadApplicaion: true];
※2019.4で実行したらエラーは発生しませんでした
仕組みとしては、初めにネイティブの画面が起動して、initボタンでUnityをライブラリから起動しています。
また、ネイティブで作成したUIButtonから、Unityライブラリにメッセージを送信しています。
新たにメッセージを定義して送信するテストをしてみました。
Cubeスクリプトにメソッドを追加して(なんとprivateでも呼ぶことができます)、iOS側にもボタンを用意して、下記の要領でメッセージを送信します。(ChangeColorを新たに作成したメソッドの名前にします)
Unityに緑に変えるメソッドを追加して、ネイティブ側でそれを呼ぶボタン(Set Green)を追加したら動いた。基本的なメッセージは遅れそう。
返り値とか非同期とか考えると沼な予感するw pic.twitter.com/zAYrcAfQyA
— とりカシュ (@torikasyu) September 1, 2019
こうして見ると意外とシンプルな感じはしますが、そもそものUnityFramework部分をinitする仕組みなどのライフサイクル部分が未解明ですので引き続き見ていきたいと思います。
コメント
This is in fact already possible for PC, and has been for some time now, though admittedly it isn t well documented. We are planning to include documentation for how to embed Unity as a library for desktop platforms soon. Stay tuned.