Help us understand the problem. What is going on with this article?

Android Q でアプリを強制的に再起動する方法

More than 1 year has passed since last update.

概要

Android Q では、従来よく使われていた AlarmManager によるアプリ強制再起動が使えなくなりました。
この記事ではその代替手段である Activity によるアプリ強制再起動について説明します。

問題

従来、アプリを強制的に再起動するために次のような方法がありました。

  1. AlarmManager を使ってメインの Activity を数秒後に起動するように設定
  2. アプリのプロセスを Kill する。

具体的には次のようなコードです。

private void restartApp() {
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT);
    AlarmManager am =
            (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    // 1秒後に MainActivity を起動
    am.setExact(AlarmManager.RTC, System.currentTimeMillis() + 1000, pi);
    // 現在のプロセスを Kill する
    android.os.Process.killProcess(android.os.Process.myPid());
}

この方法は Android Q では使えなくなりました。
この制限は Android Q で動くすべてのアプリに適用されます。targetSdkVersion は関係ありません。

これは『Android Q におけるバックグラウンドでの Activity 起動の制限』が原因です。

Android Issues にこの問題に関するチケットが起票されています。これに対し、Android チームは「Android Q では AlarmManager による再起動は利用できなくなった」とコメントしています

解決方法

Android Q からは Activity によるアプリ強制再起動が利用できます。

概要は次の通りです。

  1. 再起動を実行する RestartActivity を定義する
  2. RestartActivity が別プロセスで起動するように宣言する
  3. メインプロセスから RestartActivity を起動させる
  4. RestartActivity で再起動処理をする
    1. RestartActivity が起動したらメインプロセスを Kill する
    2. メインプロセスを Kill したら、MainActivity を起動する
    3. RestartActivity を終了する

RestartActivity を定義する

RestartActivity を定義します。
RestartActivity を起動する Intent にメインプロセスの PID を保持しておきます。

package com.x.androidapprestart;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class RestartActivity extends Activity {
    public static final String EXTRA_MAIN_PID = "RestartActivity.main_pid";

    public static Intent createIntent(Context context) {
        Intent intent = new Intent();
        intent.setClassName(context.getPackageName(), RestartActivity.class.getName());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // メインプロセスの PID を Intent に保存しておく
        intent.putExtra(RestartActivity.EXTRA_MAIN_PID, android.os.Process.myPid());
        return intent;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ... (省略) ...     
    }
}

別プロセスで起動するように宣言する

AndroidManifest.xml に RestartActivity の宣言を追加します。
この時、別プロセスで起動させるために android:process に任意のプロセス名を指定します。

<activity
  android:name=".RestartActivity"
  android:excludeFromRecents="true"
  android:exported="false"
  android:launchMode="singleInstance"
  android:process=":restart_process"
  android:theme="@android:style/Theme.Translucent.NoTitleBar">
</activity>

RestartActivity を起動する

終了したいタイミングで RestartActivity を起動します。

private void restartApp() {
    Context context = getApplicationContext();
    Intent intent = RestartActivity.createIntent(context);
    // RestartActivity を起動(AndroidManifest.xml での宣言により別プロセスで起動する
    context.startActivity(intent);
}

再起動処理をする

1. メインプロセスを Kill する
RestartActivity の onCreate メソッドでメインプロセスを Kill します。
この時、PID は Intent で渡された値を利用します。

2. MainActivity を起動する
メインプロセスを Kill したら、再起動したい Activity(今回のケースでは MainActivity)を起動します。

3. RestartActivity を終了する
RestartActivity とそのプロセスを終了します。

これでアプリが再起動されるはずです。

以下に RestartActivity の onCreate のコードを記載します。

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);

   // 1. メインプロセスを Kill する
   Intent intent = getIntent();
   int mainPid = intent.getIntExtra(EXTRA_MAIN_PID, -1);
   android.os.Process.killProcess(mainPid);

   // 2. MainActivity を再起動する
   Context context = getApplicationContext();
   Intent restartIntent = new Intent(Intent.ACTION_MAIN);
   restartIntent.setClassName(context.getPackageName(), MainActivity.class.getName());
   restartIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   context.startActivity(restartIntent);

   // 3. RestartActivity を終了する
   finish();
   android.os.Process.killProcess(android.os.Process.myPid());
}

すべてのコード

すべてのコードは github にありますので参考にしてください。

余談

この方法は Android 版 Chrome でも使われているようです。
Chrome にも BrowserRestartActivity というクラスがあり、ChromeLifetimeController から呼ばれています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away