20
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Unity】Androidの「アクティビティを保持しない」オプションは使ってはいけない

Last updated at Posted at 2015-08-24

結論

Unityで作ったAndroidアプリを実行する時に、Androidの開発者向けオプションの中にある「アクティビティを保持しない」オプションを使うととても危険です。
ダメ。ゼッタイ。

「アクティビティを保持しない」オプションの存在理由

通常Androidはアプリの中にアクティビティ(画面)が複数あり、アクティビティを切り替えることで画面遷移を行います。とこらが最前面以外のアクティビティはメモリ不足などのために、いつでも破棄される可能性があります。また最前面のアクティビティでも、画面回転で再生成されます。そのため開発者はアクティビティがいつでも破棄されて、いつでも生成していいように実装する必要があります。

しかしながら常にメモリ不足の状態にすることはできないため、アクティビティ保持のstrictモードとして「アクティビティを保持しない」オプションがあります。このオプションを有効にすることで、常に最前面以外のアクティビティがすぐに破棄されるようになります。

Unityで「アクティビティを保持しない」を使うとどうなる?

Unityは通常単一アクティビティのため、通常このオプションが設定されていても影響ありません。強いて言えば一時的なバックグラウンドでも容赦なく破棄されるため、再ロードが発生します。

ではどういう時に問題になるかと言えば、アプリ内でUnityの以外のためにアクティビティを用意し、それを実行中の切り替える必要がある場合です。このような場合、「アクティビティを保持しない」を付けたまま他のアクティビティに遷移するとアプリが突然死(再起動)します。

Unityと「アクティビティを保持しない」で突然死する理由

それはUnityのメインアクティビティである、UnityPlayerNativeActivityの中の処理に原因があります・・・

UnityPlayerNativeActivity.java
public class UnityPlayerNativeActivity extends NativeActivity {
  protected UnityPlayer mUnityPlayer;
  protected void onDestroy() {
    this.mUnityPlayer.quit();
    super.onDestroy();
  }
}
UnityPlayer.java
public class UnityPlayer extends FrameLayout implements a.a {
  public void quit() {
    // 前略
    kill();
  }
  
  protected void kill() {
    Process.killProcess(Process.myPid());
  }
}

_人人人人人人_
> 突然の死 <
 ̄Y^Y^Y^Y^Y ̄

はい、アクティビティが破棄されるOnDestroyのタイミングで「自殺」しています。
つまり

  1. 他のアクティビティに遷移する
  2. UnityPlayerNativeActivityが破棄される
  3. OnDestoryのなかで自分のプロセスを殺す
  4. 開こうとしていた他のアクティビティもろとも死ぬ

という流れになります。

回避方法

考えうる回避方法としては、

  1. UnityPlayerNativeActivityを継承して誤魔化す
  2. Unity以外のアクティビティを別プロセスで動かして巻き添えを回避
  3. 別のアクティビティを開く前にSettings.System.getInt(getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) を見て有効だったら開かない

などを考えました。
1番はAndroidにはSuperNotCalledExceptionなるものがあるので、super.OnDestroyを呼ばないことは難しそうなのと、迂回処理を書くのが難しいので却下。
2番はAndroidManifest.xmlに書くだけですのでお手軽な一方、メモリ空間が別になるので今回の用途からは却下。
ということで結局3番のシステム設定を見て危ないオプションが有効だったら別アクティビティを開かずにエラーとするようにしました。

そもそも・・・

今回のオプションは開発者向けであるので、本来サポート対象外です。
しかしながら開発者自身が有効にしたまま忘れてバグとして扱ったり、一般ユーザーでも「メモリ不足を解消する」という紹介を元に有効にしてしまうことが考えられるため、このオプションが付いている可能性は考慮してあげる必要がありそうです。

筆者自身は付けていなかったものの、他人からのバグ指摘に1日ぐらい時間を費やして調査し上記問題を発見したため、同じ問題にハマる人を出さないためにここに備忘録として書きました。

20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?