Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

アプリ内アップデートをサポートする(Kotlin または Java)

このガイドでは、Kotlin または Java を使用して、アプリ内でアプリ内アップデートをサポートする方法について説明します。実装にネイティブ コード(C / C++)を使用するケースと Unity を使用するケースについては、個別のガイドが用意されています。

アップデートの有無の確認

アップデートをリクエストする前に、アプリで利用できるアップデートがあるかどうかを確認します。アップデートの確認には、AppUpdateManager を使用します。

Kotlin

val appUpdateManager = AppUpdateManagerFactory.create(context)

// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo

// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
        // This example applies an immediate update. To apply a flexible update
        // instead, pass in AppUpdateType.FLEXIBLE
        && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
    ) {
        // Request the update.
    }
}

Java

AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);

// Returns an intent object that you use to check for an update.
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

// Checks that the platform will allow the specified type of update.
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
          // This example applies an immediate update. To apply a flexible update
          // instead, pass in AppUpdateType.FLEXIBLE
          && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
              // Request the update.
    }
});

返される AppUpdateInfo インスタンスに、アップデートの有無を示すステータスが含まれます。アップデートのステータスに応じて、インスタンスには以下も含まれます。

  • アップデートが利用可能で、許可されている場合、インスタンスにはアップデートを開始するインテントも含まれます。
  • アプリ内アップデートがすでに進行中の場合、インスタンスは進行中の更新のステータスも報告します。

アップデートの新しさの確認

アップデートが適用可能であるかどうかを確認するだけでなく、ユーザーが Google Play ストアからアップデートの通知を受信してから経過した期間を確認することもできます。これは、フレキシブル アップデートと即時アップデートのどちらを開始する必要があるかを判断する際に有用です。たとえば、ユーザーにフレキシブル アップデートを通知するまで数日待ち、その後、即時アップデートを要求するまでさらに数日待つこともできます。

アップデートが Play ストアで入手できるようになってからの日数の確認には、clientVersionStalenessDays() を使用します。

Kotlin

val appUpdateManager = AppUpdateManagerFactory.create(context)

// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo

// Checks whether the platform allows the specified type of update,
// and current version staleness.
appUpdateInfoTask.addOnSuccessListener {
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
          && (appUpdateInfo.clientVersionStalenessDays() ?: -1) >= DAYS_FOR_FLEXIBLE_UPDATE
          && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
              // Request the update.
}

Java

AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);

// Returns an intent object that you use to check for an update.
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

// Checks whether the platform allows the specified type of update,
// and current version staleness.
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
          && appUpdateInfo.clientVersionStalenessDays() != null
          && appUpdateInfo.clientVersionStalenessDays() >= DAYS_FOR_FLEXIBLE_UPDATE
          && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
              // Request the update.
    }
});

アップデートの優先度の確認

Google Play Developer API では、各アップデートの優先度を設定できます。 これにより、アプリはユーザーにアップデートを推奨する程度を決定できるようになります。たとえば、アップデートの優先度を設定するための次のような戦略を考えてみます。

  • UI の細かな改善: 優先度が低いアップデート。フレキシブル アップデートも即時アップデートもリクエストしません。ユーザーがアプリを操作していないときにのみ更新します。
  • パフォーマンスの改善: 優先度が中程度のアップデート。フレキシブル アップデートをリクエストします。
  • 重要なセキュリティ アップデート: 優先度が高いアップデート。即時アップデートをリクエストします。

優先度を決定するにあたり、Google Play は 0~5 の整数値を使用します。0 はデフォルトの値、5 は優先度が最も高い値です。アップデートの優先度を設定するには、Google Play Developer API の Edits.tracks.releases の下にある inAppUpdatePriority フィールドを使用します。リリースで新たに追加されたすべてのバージョンの優先度は、リリースと同じとみなされます。優先度は新しいリリースの公開時にのみ設定できます。後から変更することはできません。

Google Play Developer API を使用した優先度の設定については、Play Developer API のドキュメントをご覧ください。アプリ内アップデートの優先度は、Edit.tracks: update メソッドで渡される Edit.tracks で指定する必要があります。次の例に、APK(バージョン コード 88、inAppUpdatePriority 5)のリリースを示します。

{
  "releases": [{
      "versionCodes": ["88"],
      "inAppUpdatePriority": 5,
      "status": "completed"
  }]
}

アプリのコードで、updatePriority() を使用して特定のアップデートの優先度を確認できます。

Kotlin

val appUpdateManager = AppUpdateManagerFactory.create(context)

// Returns an intent object that you use to check for an update.
val appUpdateInfoTask = appUpdateManager.appUpdateInfo

// Checks whether the platform allows the specified type of update,
// and checks the update priority.
appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
          && appUpdateInfo.updatePriority() >= 4 /* high priority */
          && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
              // Request an immediate update.
}

Java

AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);

// Returns an intent object that you use to check for an update.
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

// Checks whether the platform allows the specified type of update,
// and checks the update priority.
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
          && appUpdateInfo.updatePriority() >= 4 /* high priority */
          && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
              // Request an immediate update.
    }
});

アップデートの開始

アップデートが利用可能であることを確認したら、AppUpdateManager.startUpdateFlowForResult() を使用してアップデートをリクエストできます。

Kotlin

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
    AppUpdateType.IMMEDIATE,
    // The current activity making the update request.
    this,
    // Include a request code to later monitor this update request.
    MY_REQUEST_CODE)

Java

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
    AppUpdateType.IMMEDIATE,
    // The current activity making the update request.
    this,
    // Include a request code to later monitor this update request.
    MY_REQUEST_CODE);

AppUpdateInfo インスタンスを使用してアップデートを開始できる回数は 1 回のみです。失敗した場合にアップデートを再試行するには、新しい AppUpdateInfo をリクエストし、アップデートが利用可能かつ許可されていることを再度確認します。

以下のステップは、フレキシブル アップデート即時アップデートのどちらをリクエストしているかによって異なります。

AppUpdateOptions を使用してアップデートを構成する

また、明示的なアップデートのフロー タイプの代わりに AppUpdateOptions オブジェクトをビルドして渡すこともできます。appUpdateType フィールドに加えて、AppUpdateOptions オブジェクトには AllowAssetPackDeletion フィールドもあります。デバイスのストレージが限られている場合には、このフィールドで、アップデートにアセットパックの消去を許可するかどうかを定義します。このフィールドはデフォルトでは false に設定されていますが、代わりに setAllowAssetPackDeletion() メソッドを使用して true に設定することもできます。

Kotlin

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // The current activity making the update request.
    this,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
        .setAllowAssetPackDeletion(true)
        .build(),
    // Include a request code to later monitor this update request.
    MY_REQUEST_CODE)

Java

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // The current activity making the update request.
    this,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
        .setAllowAssetPackDeletion(true)
        .build(),
    // Include a request code to later monitor this update request.
    MY_REQUEST_CODE);

アップデート ステータスのコールバックの取得

アップデートを開始した後でアップデートの失敗やキャンセルが発生した場合、onActivityResult() コールバックを使用して対処します。

Kotlin

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == MY_REQUEST_CODE) {
        if (resultCode != RESULT_OK) {
            Log.e("MY_APP", "Update flow failed! Result code: $resultCode")
            // If the update is cancelled or fails,
            // you can request to start the update again.
        }
    }
}

Java

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == MY_REQUEST_CODE) {
    if (resultCode != RESULT_OK) {
      log("Update flow failed! Result code: " + resultCode);
      // If the update is cancelled or fails,
      // you can request to start the update again.
    }
  }
}

onActivityResult() コールバックから受け取る可能性がある値がいくつかあります。

  • RESULT_OK: ユーザーがアップデートを承認しました。即時アップデートの場合、アプリに制御が返されるまでにアップデートがすでに完了しているため、このコールバックを受信しない可能性があります。
  • RESULT_CANCELED: ユーザーがアップデートを拒否またはキャンセルしました。
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: 他のエラーにより、ユーザーが同意できなかったか、アップデートを続行できませんでした。

フレキシブル アップデートの処理

フレキシブル アップデートを開始すると、ユーザーに同意を求めるダイアログが最初に表示されます。ユーザーが同意すると、バックグラウンドでダウンロードが開始され、ユーザーはアプリの操作を続けることができます。このセクションでは、アプリ内フレキシブル アップデートを確認、完了する方法について説明します。

フレキシブル アップデートの状態の確認

フレキシブル アップデートのダウンロードが開始されたら、アプリはアップデートの状態を確認して、アップデートをインストールできるタイミングを把握し、アプリの UI に進行状況を表示する必要があります。

インストール ステータス アップデートのリスナーを登録することで、進行中のアップデートの状態を確認できます。また、アプリの UI に進行状況バーを表示して、ダウンロードの進行状況をユーザーに知らせることもできます。

Kotlin

// Create a listener to track request state updates.
val listener = InstallStateUpdatedListener { state ->
    // (Optional) Provide a download progress bar.
    if (state.installStatus() == InstallStatus.DOWNLOADING) {
      val bytesDownloaded = state.bytesDownloaded()
      val totalBytesToDownload = state.totalBytesToDownload()
      // Show update progress bar.
    }
    // Log state or install the update.
}

// Before starting an update, register a listener for updates.
appUpdateManager.registerListener(listener)

// Start an update.

// When status updates are no longer needed, unregister the listener.
appUpdateManager.unregisterListener(listener)

Java

// Create a listener to track request state updates.
InstallStateUpdatedListener listener = state -> {
  // (Optional) Provide a download progress bar.
  if (state.installStatus() == InstallStatus.DOWNLOADING) {
      long bytesDownloaded = state.bytesDownloaded();
      long totalBytesToDownload = state.totalBytesToDownload();
      // Implement progress bar.
  }
  // Log state or install the update.
};

// Before starting an update, register a listener for updates.
appUpdateManager.registerListener(listener);

// Start an update.

// When status updates are no longer needed, unregister the listener.
appUpdateManager.unregisterListener(listener);

フレキシブル アップデートのインストール

InstallStatus.DOWNLOADED の状態を検出した場合は、アプリを再起動してアップデートをインストールする必要があります。

即時アップデートとは異なり、Google Play では、フレキシブル アップデートでアプリの再起動が自動的に行われません。これは、フレキシブル アップデートの間、ユーザーはアップデートのインストールを決定するまでアプリを使用し続けることを期待しているからです。

アップデートのインストール準備ができたことをユーザーに伝え、アプリの再起動に対するユーザーの確認を求める通知(またはその他の UI 表示)を行うことをおすすめします。

次の例は、アプリの再起動に対するユーザーの確認を求めるマテリアル デザインのスナックバーの実装方法を示しています。

Kotlin

val listener = { state ->
    if (state.installStatus() == InstallStatus.DOWNLOADED) {
        // After the update is downloaded, show a notification
        // and request user confirmation to restart the app.
        popupSnackbarForCompleteUpdate()
    }
    ...
}

// Displays the snackbar notification and call to action.
fun popupSnackbarForCompleteUpdate() {
    Snackbar.make(
        findViewById(R.id.activity_main_layout),
        "An update has just been downloaded.",
        Snackbar.LENGTH_INDEFINITE
    ).apply {
        setAction("RESTART") { appUpdateManager.completeUpdate() }
        setActionTextColor(resources.getColor(R.color.snackbar_action_text_color))
        show()
    }
}

Java

InstallStateUpdatedListener listener = state -> {
    if (state.installStatus() == InstallStatus.DOWNLOADED) {
        // After the update is downloaded, show a notification
        // and request user confirmation to restart the app.
        popupSnackbarForCompleteUpdate();
    }
    ...
};

// Displays the snackbar notification and call to action.
private void popupSnackbarForCompleteUpdate() {
  Snackbar snackbar =
      Snackbar.make(
          findViewById(R.id.activity_main_layout),
          "An update has just been downloaded.",
          Snackbar.LENGTH_INDEFINITE);
  snackbar.setAction("RESTART", view -> appUpdateManager.completeUpdate());
  snackbar.setActionTextColor(
      getResources().getColor(R.color.snackbar_action_text_color));
  snackbar.show();
}

フォアグラウンドで appUpdateManager.completeUpdate() を呼び出すと、バックグラウンドでアプリを再起動するフルスクリーン UI がプラットフォームに表示されます。アップデートがインストールされると、アプリはメイン アクティビティで再起動します。

代わりに、アプリがバックグラウンドで実行されているときに completeUpdate() を呼び出すと、デバイス UI を遮ることなく、アップデートがサイレント インストールされます。

ユーザーがアプリをフォアグラウンドにするたびに、アプリにインストール待ちのアップデートがあるかどうかを確認してください。アプリに DOWNLOADED 状態のアップデートがある場合は、ユーザーにアップデートをインストールするよう促します。それ以外の場合、アップデート データは引き続きユーザーのデバイス ストレージに置かれます。

Kotlin

// Checks that the update is not stalled during 'onResume()'.
// However, you should execute this check at all app entry points.
override fun onResume() {
    super.onResume()

    appUpdateManager
        .appUpdateInfo
        .addOnSuccessListener { appUpdateInfo ->
            ...
            // If the update is downloaded but not installed,
            // notify the user to complete the update.
            if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                popupSnackbarForCompleteUpdate()
            }
        }
}

Java

// Checks that the update is not stalled during 'onResume()'.
// However, you should execute this check at all app entry points.
@Override
protected void onResume() {
  super.onResume();

  appUpdateManager
      .getAppUpdateInfo()
      .addOnSuccessListener(appUpdateInfo -> {
              ...
              // If the update is downloaded but not installed,
              // notify the user to complete the update.
              if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                  popupSnackbarForCompleteUpdate();
              }
          });
}

即時アップデートの処理

即時アップデートを開始し、ユーザーがアップデートの開始に同意した場合、Google Play はアップデートが完了するまでの間、アプリの UI の上にアップデートの進行状況を表示します。ユーザーがアップデート中にアプリを閉じた、または終了した場合、ユーザーへの追加の確認を行うことなく、引き続きバックグラウンドでアップデートのダウンロードとインストールが行われます。

ただし、アプリがフォアグラウンドに戻ったら、アップデートが UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS の状態で停止していないことを確認する必要があります。この状態でアップデートが停止している場合は、更新を再開します。

Kotlin

// Checks that the update is not stalled during 'onResume()'.
// However, you should execute this check at all entry points into the app.
override fun onResume() {
    super.onResume()

    appUpdateManager
        .appUpdateInfo
        .addOnSuccessListener { appUpdateInfo ->
            ...
            if (appUpdateInfo.updateAvailability()
                == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
            ) {
                // If an in-app update is already running, resume the update.
                appUpdateManager.startUpdateFlowForResult(
                    appUpdateInfo,
                    IMMEDIATE,
                    this,
                    MY_REQUEST_CODE
                )
            }
        }
}

Java

// Checks that the update is not stalled during 'onResume()'.
// However, you should execute this check at all entry points into the app.
@Override
protected void onResume() {
  super.onResume();

  appUpdateManager
      .getAppUpdateInfo()
      .addOnSuccessListener(
          appUpdateInfo -> {
            ...
            if (appUpdateInfo.updateAvailability()
                == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                // If an in-app update is already running, resume the update.
                appUpdateManager.startUpdateFlowForResult(
                    appUpdateInfo,
                    IMMEDIATE,
                    this,
                    MY_REQUEST_CODE);
            }
          });
}

アップデート フローは、startUpdateFlowForResult() のリファレンス ドキュメントに記載されている結果を返します。アプリは特に、ユーザーがアップデートを拒否した場合や、ダウンロードをキャンセルした場合に対処する必要があります。ユーザーがこのようなアクションのいずれかを実行すると、Google Play UI は終了します。続行するために、アプリは最善の方法を決定する必要があります。

可能であれば、ユーザーがアップデートを行わずに継続できるようにして、後でもう一度アップデートを促すようにしてください。アップデートを行わないとアプリを使用できない場合は、その旨をメッセージで表示した後で、アップデート フローを再開するか、ユーザーにアプリを終了するように促すことを検討してください。そうすることで、ユーザーは、必要なアップデートをインストールする準備ができるようになったらアプリを再起動できると理解します。

次のステップ

アプリ内アップデートをテストして、統合が正しく機能していることを確認する。