Unity の Android 版ビルドに複数アクティビティを含めたら問題が発生した話

fb-icon

某 Unity アプリに導入したプラグインの都合で、アクティビティ(※)を複数搭載した際にハマった不具合があるので、その解決方法を書きます。

※ Android アプリで「アクティビティ」とは、 Web アプリでいうところのページに近い概念です。 → アクティビティ (外部)

概要

  1. UnityPlayerActivity から、某プラグインの独自アクティビティを呼びます。
  2. HOME キーを押して一旦アプリを終了します。
  3. アプリの起動アイコンを押します。
  4. UnityPlayerActivity が前面に出ます (元々某プラグインの独自アクティビティが前面に出てたにも関わらず)。
  5. Unity アプリのマネージドコードではプラグインアクティビティからの返答を待っていたのですが、そのアクティビティは応答ないままどっかいったので永遠に待ち続けることに…

原因

率直にいえば Unity と Android の仕様(

具体的に説明すると、 UnityPlayerActivity の起動モード (launchMode ※) が singleTask に指定されているために起こる現象の様です。
UnityPlayerActivity が別のアクティビティを呼び出しているときにアプリの起動アイコンを押すと、 UnityPlayerActivity が前面に出ます。しかも元々呼び出し中だった子アクティビティは全部破棄されてしまいます。
※ launchMode の挙動についてはこちらのページが詳しいです→ Y.A.M の 雑記帳: Android launchMode の違い (外部)

ちなみに launchModesingleTask になるのは、以下のメタデータがマニフェストに入ってると Unity によって勝手に launchMode が設定されます。

<meta-data android:name="unityplayer.UnityActivity" android:value="true" />

これ外すと別の不具合が発生するので、外すのはやめておきます。

解決するプラグイン作った

それでも上記の不具合を解決したくて色々と試行錯誤を重ねた結果、以下のプラグインができました!
LibLauncherProxy (GitHub)

仕組みの雑な説明

  1. アプリの起動アイコンを押すと、通常の UnityPlayerActivity ではなく LauncherProxyActivity が起動します。
  2. LauncherProxyActivity は、すでに UnityPlayerActivity が起動しているかどうか確認します。
  3. If UnityPlayerActivity がすでに起動中
    • If Android 3 以上 ∧ REORDER_TASKS パーミッションある

      Else

      • UnityPlayerActivity のタスクの最前面に出ていたアクティビティに空のインテントを投げることで前面に出るのを願います。

    Else

    • LauncherProxyActivity が受け取ったインテントを(原形をとどめつつ)チョチョイと加工して UnityPlayerActivity に投げます。

ちなみに UnityPlayerActivity ではなく独自(またはプラグイン由来)のアクティビティを使用してる場合、そのマニフェストに <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> が入ってると LibLauncherProxy はそのアクティビティを探してくれます。

参考 (外部リンク)