[HoloLens]アプリ拡張機能の作成

2021/06/18に公開

「アプリ拡張機能」と言ういわゆるプラグイン機能で後から UWP アプリに機能を追加できることが分かったので HoloLens でも動作するか試してみました。

結論としては、きちんとプラグインとしてアプリに後から機能を追加することができたため、サンプルとして以下で公開しています。
https://github.com/HiromuKato/HoloLensExtensionSample

実行結果

拡張機能をホストするアプリとなる HoloLens アプリには手を入れず、拡張機能となるアプリがインストールされているかいないかで動作が変わっています。

https://twitter.com/hi_rom_/status/1405738435978031117?s=20?conversation=none

https://twitter.com/hi_rom_/status/1405738562159472642?s=20?conversation=none

確認環境

  • Unity 2019.4.27f1
  • MRTK v2.7.0

ドキュメント

参照したドキュメントは以下になります。

アプリ拡張機能の作成とホスト

手順としては概ねドキュメントの通りに進めれば問題ありませんが、1点はまりどころがありました。

はまりどころ

ドキュメントからリンクが張られている 数学拡張機能のコードサンプル が正常に動作しませんでした。

サンプルをそのままビルドして実行すると、初回は正しく累乗の計算が行われますが、2回目以降は NaN が表示されます。

NaN

また、拡張機能はタスクマネージャーで見てみると、バックグラウンドプロセスとして残り続けるので、一度この状態になると次アプリを起動しても最初からNaNが表示されます。従って、再度動作確認する場合には MathExtension のタスクを終了する必要があります。

Task Manager

サンプルが動かないことには始まらないため、まずはこちらを調べました。

原因としては、ホスト側の ExtensionManager.cs の Invoke メソッドを見ると、コネクションが毎回クローズされる実装になっているためのようでした。

Invoke

拡張機能側である MathExtension プロジェクトの App.xaml.cs の OnBackGroundActivated メソッドがボタンを押すたびに毎回呼ばれていましたが、具体的な処理を行う OnAppServiceRequestReceived は呼ばれていませんでした。これは args.TaskInstance の値が毎回変わっているためとなります。対策としてはコネクションを確立したらクローズしないように変更するか、毎度初期化処理を行うような変更を行えば良いと思います。

OnBackgroundActivated

今回は以下のように後者の対応をしました。(こちらこちらを見ると登録したイベントの解除はしなくてよいのかな?)

protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    base.OnBackgroundActivated(args);

    IBackgroundTaskInstance taskInstance = args.TaskInstance;
    taskInstance.Canceled += OnAppServicesCanceled;

    AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    _appServiceDeferral = taskInstance.GetDeferral();
    _appServiceConnection = appService.AppServiceConnection;
    _appServiceConnection.RequestReceived += OnAppServiceRequestReceived;
    _appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
}

以上を踏まえた上でHoloLensでも動作するように対応をしています。

アプリ拡張機能側の実装

アプリ拡張機能は数学拡張機能のコードサンプルをそのまま利用出来ます。今回は累乗の計算部分を乗算に変更したので、Package.appxmanifest を以下のような内容にしました。

      <Extensions>
        <uap:Extension Category="windows.appService">
          <uap:AppService Name="com.sample.multiplyservice" />
        </uap:Extension>
        <uap3:Extension Category="windows.appExtension">
          <uap3:AppExtension Name="Sample.com.MathExt" Id="multiply" DisplayName="x*y" Description="Exponent" PublicFolder="Public">
            <uap3:Properties>
              <Service>com.sample.multiplyservice</Service>
            </uap3:Properties>
          </uap3:AppExtension>
        </uap3:Extension>
      </Extensions>

あとは(ARM または ARM64 で)ビルドして HoloLensにデプロイするだけです。デプロイした後は一度実行する必要があります(とくに UI の実装はしていないので何もないウィンドが描画されるだけです)。一度実行したら消して問題ありません。

ホストアプリ側の実装

HoloLens で操作する Unity アプリにホスト機能を実装します。

数学拡張機能のコードサンプルの ExtensionManager クラスをベースに一部修正したものになりますので、詳細については GitHub をご参照ください。注意点としては、HoloLens アプリでは Unity から出力した UWP のプロジェクト内にある Package.appxmanifest を修正する必要がある点です。

Unity から UWP プロジェクト出力後、ExtensionHost フォルダ配下の Package.appxmanifest (の </uap:VisualElements> 下あたりに)に以下を追加しています。

      <Extensions>
        <uap3:Extension Category="windows.appExtensionHost">
          <uap3:AppExtensionHost>
            <uap3:Name>Sample.com.MathExt</uap3:Name>
          </uap3:AppExtensionHost>
        </uap3:Extension>
      </Extensions>

HoloLens にデプロイして起動すると、自動的にプラグインが読み込まれるようにしています。サンプルではログ出力しているので、読み込み処理の流れや拡張機能の名前などを確認できるようになっています。

HoloLens

終わりに

まずはそもそもプラグインとして作ったものが HoloLens で動くのかという検証としての内容のため、乗算をするための数値が決め打ちだったり UI の作りこみ等はしていませんが、きちんと動作することが確認出来ました。あとは、数値を入力できるようにして様々な演算をプラグインとして追加することもできるでしょうし、拡張機能を管理する機能もあるため、プラグインの有効・無効化を動的に制御するといったことも可能になると思います。

参考

Discussion