小さなUnityネイティブプラグインパッケージ

Software Engineerの ぽけば です。今回はUnityによるclient開発で使用しているネイティブプラグイン(の一部)について触れたいと思います。

clusterとネイティブプラグイン

clusterは様々なプラットフォームに対してクライアントを提供しており、各プラットフォームで最大のユーザー体験を得られるように日々調査・開発・改善を行っています。

cluster内のバーチャル空間内の機能(inroom)は 「本日クラスターに入社したUnity Engineerが読む記事」の紹介 にも書かれている通りUnityで実装されていますが、inroomの中にはUnityでは提供されていないネイティブな機能やデバイスに依存した機能も提供しており、そういった機能を実装する際にはUnityネイティブプラグインを用いています( cf. UnityネイティブプラグインのM1 Mac対応 )。

「Unityネイティブプラグインを用いています」と簡単に書いていますが、実際にネイティブプラグインを組み込んで開発するかどうかは慎重な検討を経て行われます。ネイティブコードを用いて実装すると開発コストやメンテナンスコストの増加に繋がるため、基本的にはUnityが提供する機能やC#による実装で完結することが望ましいと考えているためです。そのため、ネイティブプラグインを活用するかどうかはいくつかの判断基準があります。

  • Unityが提供する機能だけでは実現できないか、著しい開発コストが必要になる
  • 比較的安価なコストで望ましい機能を実現できる

メンテナンス面での課題

inroomのいくつかの機能に用いられているネイティブプラグインですが、主にメンテナンス性の面でいくつかの課題がありました。

  • /Assets/Plugins 下に置かれていたライブラリがなんの機能に紐づいているかわかりづらい
  • どの機能でネイティブプラグインを用いているか実装を読まないと把握できない
  • (特にiOSやAndroidで)使用しているAPI versionが把握しづらい

また(一部の本当に小さな)Android向け実装ではAndroidJavaClassなどを利用しており、Pluginsディレクトリを眺めただけではネイティブコード呼び出しが行われているか把握できない部分がありました。

こうした問題を解決するため、clusterのUnity ProjectではNativeLibsというパッケージを用意しネイティブプラグインに関するコードを集約することしました。

NativeLibs: 小さなネイティブプラグインパッケージ

NativeLibsは比較的小規模なネイティブプラグインを集めたパッケージで、各プラットフォームのネイティブコードやそれらをC#から呼び出すための薄いラッパークラスが用意されています。

v2.31でリリースされたスマホ版の触覚フィードバック(Mobile Haptics) を例にNativeLibsの構成を図示すると次のようになります。

NativeLibsの構成

各ネイティブコードやそのラッパークラスのディレクトリに機能名を採用することで、どの機能でどういったネイティブプラグインを用いているか把握できるようにしています。また、ラッパークラス用のnamespaceは ClusterVR.NativeLibs.{PLATFORM}.{FEATURE_NAME} という形式でどのプラットフォーム・機能向けのクラスか一目でわかるようにしています。新たにネイティブプラグインを追加する際は、FooFeatureのようにPluginsやRuntimeにFooFeature用のディレクトリを用意することになります。

NativeLibsはネイティブコードを呼び出すことだけを責務としているため、ネイティブコードを呼び出すためのラッパークラスでは基本的にネイティブコードのAPIをそのまま公開する形を採用しています。こうすることでNativeLibsのメンテナンス頻度を抑えつつ、inroomでどのようなプラットフォーム依存のAPIを利用しているか把握しやすいようにしています。

また、図内のRuntime下に用意されるネイティブコード呼び出しクラスではcluster独自のドメイン知識を持たせず、Unityが提供する機能についてもAndroidJavaClassとAndroidJavaObjectに限定して利用するようにしています。これによりcluster独自の実装については呼び出し側で完結できるようになりました。

NativeLibsで管理しないもの

NativeLibsは比較的小さなネイティブプラグインを管理するために生み出されたパッケージです。そのため、次のようなネイティブプラグインは管理対象外となっています。

外部サービス向けのネイティブプラグインは独立したパッケージとして提供されていることがほとんどなので、NativeLibs下で管理する必要はありません。

outroomとinroomでやり取りが必要な処理はclusterのドメイン知識を持ち込む必要があり、NativeLibsの趣旨から外れてしまうため別途パッケージが用意されています。

巨大な機能については今のところ実績がありませんが、いくつもの実装が必要な巨大機能は独立したパッケージを用意すべきだと考えています。

おわりに

今回は小さなUnityネイティブプラグイン群を管理するためのNativeLibsを紹介しました。とはいえ、NativeLibsはあくまで現時点での管理方法です。より良いユーザー体験を提供するための開発環境向上を目指して、管理方法は今後も変遷を続けることでしょう。

クラスターでは、各プラットフォーム上でより良い体験を生み出す中で、開発体験向上を試行し開発を加速させるメンバーを募集しています。興味を持たれた方はぜひ採用情報・採用事例をご覧ください。

https://recruit.cluster.mu/engineer/