Unterstützung von In-App-Updates (Kotlin oder Java)

In diesem Leitfaden wird beschrieben, wie Sie In-App-Updates in Ihrer App mit Kotlin oder Java unterstützen. Es gibt separate Leitfäden für Fälle, in denen Ihre Implementierung nativen Code (C/C++) verwendet, und für Fälle, in denen Ihre Implementierung Unity oder Unreal Engine verwendet.

Entwicklungsumgebung einrichten

Die Play In-App Update Library ist Teil der Google Play Core-Bibliotheken. Fügen Sie die folgende Gradle-Abhängigkeit hinzu, um die Play In-App Update Library einzubinden.

Groovy

// In your app's build.gradle file:
...
dependencies {
    // This dependency is downloaded from the Google's Maven repository.
    // So, make sure you also include that repository in your project's build.gradle file.
    implementation 'com.google.android.play:app-update:2.1.0'

    // For Kotlin users also add the Kotlin extensions library for Play In-App Update:
    implementation 'com.google.android.play:app-update-ktx:2.1.0'
    ...
}

Kotlin

// In your app's build.gradle.kts file:
...
dependencies {
    // This dependency is downloaded from the Google's Maven repository.
    // So, make sure you also include that repository in your project's build.gradle file.
    implementation("com.google.android.play:app-update:2.1.0")

    // For Kotlin users also import the Kotlin extensions library for Play In-App Update:
    implementation("com.google.android.play:app-update-ktx:2.1.0")
    ...
}

Prüfen, ob ein Update verfügbar ist

Bevor Sie ein Update anfordern, prüfen Sie, ob ein Update für Ihre App verfügbar ist. Verwenden Sie dazu 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.
    }
});

Die zurückgegebene AppUpdateInfo-Instanz enthält den Status der Updateverfügbarkeit. Je nach Status des Updates enthält die Instanz auch Folgendes:

  • Wenn ein Update verfügbar und zulässig ist, enthält die Instanz auch einen Intent zum Starten des Updates.
  • Wenn ein In-App-Update bereits ausgeführt wird, meldet die Instanz auch den Status des laufenden Updates.

Aktualität von Updates prüfen

Zusätzlich zur Prüfung, ob ein Update verfügbar ist, solltest du auch prüfen, wie viel Zeit vergangen ist, seit der Nutzer zuletzt über den Google Play Store über ein Update benachrichtigt wurde. So kannst du besser entscheiden, ob du ein flexibles oder ein sofortiges Update initiieren solltest. Beispielsweise könntest du ein paar Tage warten, bevor du den Nutzer über ein flexibles Update benachrichtigst, und dann noch einmal ein paar Tage, bevor du ein sofortiges Update verlangst.

Verwenden Sie clientVersionStalenessDays(), um die Anzahl der Tage zu prüfen, die seit der Verfügbarkeit des Updates im Google Play Store vergangen sind:

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 { appUpdateInfo ->
    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.
    }
});

Updatepriorität prüfen

Mit der Google Play Developer API können Sie die Priorität jedes Updates festlegen. So kann in Ihrer App entschieden werden, wie dringend ein Update für den Nutzer empfohlen werden soll. Betrachten Sie beispielsweise die folgende Strategie zum Festlegen der Updatepriorität:

  • Kleinere Verbesserungen an der Benutzeroberfläche: Update mit niedriger Priorität; weder ein flexibles noch ein sofortiges Update anfordern. Aktualisieren Sie die App nur, wenn der Nutzer nicht mit ihr interagiert.
  • Leistungsverbesserungen: Update mit mittlerer Priorität; flexibles Update anfordern.
  • Kritisches Sicherheitsupdate: Update mit hoher Priorität; sofortiges Update anfordern.

Zur Bestimmung der Priorität verwendet Google Play einen ganzzahligen Wert zwischen 0 und 5, wobei 0 der Standardwert und 5 die höchste Priorität ist. Wenn du die Priorität für ein Update festlegen möchtest, verwende das Feld inAppUpdatePriority unter Edits.tracks.releases in der Google Play Developer API. Alle neu hinzugefügten Versionen im Release haben dieselbe Priorität wie das Release. Die Priorität kann nur beim Roll-out eines neuen Release festgelegt und später nicht mehr geändert werden.

Legen Sie die Priorität mithilfe der Google Play Developer API fest, wie in der Dokumentation zur Play Developer API beschrieben. Die Priorität des In-App-Updates sollte in der Ressource Edit.tracks angegeben werden, die in der Methode Edit.tracks: update übergeben wird. Im folgenden Beispiel wird gezeigt, wie eine App mit dem Versionscode 88 und dem inAppUpdatePriority 5 veröffentlicht wird:

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

Im Code Ihrer App können Sie die Prioritätsstufe für ein bestimmtes Update mit updatePriority() prüfen. Die zurückgegebene Priorität berücksichtigt die inAppUpdatePriority für alle App-Versionscodes zwischen der installierten Version und der neuesten verfügbaren Version, unabhängig vom Release-Track. Betrachten wir folgendes Szenario:

  • Sie veröffentlichen Version 1 in einem Produktions-Track ohne Priorität.
  • Sie veröffentlichen Version 2 in einem Interner-Test-Track mit Priorität 5.
  • Sie veröffentlichen Version 3 in einem Produktions-Track ohne Priorität.

Wenn Nutzer der Produktionsversion von Version 1 auf Version 3 aktualisieren, erhalten sie Priorität 5, obwohl Version 2 in einem anderen Track veröffentlicht wurde.

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.
    }
});

Update starten

Nachdem Sie bestätigt haben, dass ein Update verfügbar ist, können Sie mit AppUpdateManager.startUpdateFlowForResult() ein Update anfordern:

Kotlin

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // an activity result launcher registered via registerForActivityResult
    activityResultLauncher,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build())

Java

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // an activity result launcher registered via registerForActivityResult
    activityResultLauncher,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build());

Jede AppUpdateInfo-Instanz kann nur einmal zum Starten eines Updates verwendet werden. Wenn Sie das Update im Falle eines Fehlers noch einmal versuchen möchten, fordern Sie ein neues AppUpdateInfo an und prüfen Sie noch einmal, ob das Update verfügbar und zulässig ist.

Sie können einen Launcher für Aktivitätsergebnisse mit dem integrierten ActivityResultContracts.StartIntentSenderForResult-Vertrag registrieren. Weitere Informationen findest du im Abschnitt Callback für Aktualisierungsstatus abrufen.

Die nächsten Schritte hängen davon ab, ob Sie ein flexibles Update oder ein sofortiges Update anfordern.

Update mit AppUpdateOptions konfigurieren

AppUpdateOptions enthält ein AllowAssetPackDeletion-Feld, das definiert, ob das Update bei begrenztem Gerätespeicher Asset-Packs löschen darf. Dieses Feld ist standardmäßig auf false festgelegt. Sie können es jedoch mit der Methode setAllowAssetPackDeletion() auf true festlegen:

Kotlin

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // an activity result launcher registered via registerForActivityResult
    activityResultLauncher,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
        .setAllowAssetPackDeletion(true)
        .build())

Java

appUpdateManager.startUpdateFlowForResult(
    // Pass the intent that is returned by 'getAppUpdateInfo()'.
    appUpdateInfo,
    // an activity result launcher registered via registerForActivityResult
    activityResultLauncher,
    // Or pass 'AppUpdateType.FLEXIBLE' to newBuilder() for
    // flexible updates.
    AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE)
        .setAllowAssetPackDeletion(true)
        .build());

Rückruf zum Aktualisierungsstatus erhalten

Nach dem Starten eines Updates erhält der registrierte Callback des Aktivitätsergebnis-Launchers das Ergebnis des Bestätigungsdialogfelds:

Kotlin

registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult ->
    // handle callback
    if (result.resultCode != RESULT_OK) {
        log("Update flow failed! Result code: " + result.resultCode);
        // If the update is canceled or fails,
        // you can request to start the update again.
    }
}

Java

registerForActivityResult(
    new ActivityResultContracts.StartIntentSenderForResult(),
    new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            // handle callback
            if (result.getResultCode() != RESULT_OK) {
                log("Update flow failed! Result code: " + result.getResultCode());
                // If the update is canceled or fails,
                // you can request to start the update again.
            }
        }
    });

Es gibt mehrere Werte, die Sie vom onActivityResult()-Callback erhalten können:

  • RESULT_OK: Der Nutzer hat das Update akzeptiert. Bei sofortigen Updates erhalten Sie diesen Callback möglicherweise nicht, da das Update bereits abgeschlossen sein sollte, wenn die Kontrolle an Ihre App zurückgegeben wird.
  • RESULT_CANCELED: Der Nutzer hat das Update abgelehnt oder abgebrochen.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Ein anderer Fehler hat entweder verhindert, dass der Nutzer seine Einwilligung erteilt, oder dass die Aktualisierung fortgesetzt wird.

Flexibles Update verarbeiten

Wenn du ein flexibles Update startest, wird dem Nutzer zuerst ein Dialogfeld angezeigt, in dem er um seine Zustimmung gebeten wird. Wenn der Nutzer zustimmt, wird der Download im Hintergrund gestartet und der Nutzer kann weiterhin mit Ihrer App interagieren. In diesem Abschnitt wird beschrieben, wie Sie ein flexibles In-App-Update überwachen und abschließen.

Status des flexiblen Updates überwachen

Nachdem der Download für ein flexibles Update begonnen hat, muss Ihre App den Updatestatus überwachen, um zu wissen, wann das Update installiert werden kann, und um den Fortschritt in der Benutzeroberfläche Ihrer App anzuzeigen.

Du kannst den Status eines laufenden Updates im Blick behalten, indem du einen Listener für Updates des Installationsstatus registrierst. Du kannst auch eine Fortschrittsanzeige in der Benutzeroberfläche der App bereitstellen, um Nutzer über den Fortschritt des Downloads zu informieren.

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);

Flexibles Update installieren

Wenn der Status InstallStatus.DOWNLOADED erkannt wird, musst du die App neu starten, um das Update zu installieren.

Im Gegensatz zu sofortigen Updates wird bei einem flexiblen Update von Google Play nicht automatisch ein Neustart der App ausgelöst. Das liegt daran, dass der Nutzer bei einem flexiblen Update erwartet, dass er die App weiter verwenden kann, bis er sich entscheidet, das Update zu installieren.

Es wird empfohlen, den Nutzer über eine Benachrichtigung (oder eine andere UI-Anzeige) darüber zu informieren, dass das Update installiert werden kann, und vor dem Neustart der App eine Bestätigung anzufordern.

Im folgenden Beispiel wird eine Material Design-Snackbar implementiert, die den Nutzer auffordert, den Neustart der App zu bestätigen:

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();
}

Wenn Sie appUpdateManager.completeUpdate() im Vordergrund aufrufen, wird auf der Plattform eine Vollbild-UI angezeigt, über die die App im Hintergrund neu gestartet wird. Nachdem die Plattform das Update installiert hat, wird die App neu gestartet und die Hauptaktivität wird angezeigt.

Wenn Sie stattdessen completeUpdate() aufrufen, während sich Ihre App im Hintergrund befindet, wird das Update im Hintergrund installiert, ohne dass die Benutzeroberfläche des Geräts verdeckt wird.

Prüfen Sie immer, ob ein Update für Ihre App installiert werden muss, wenn der Nutzer Ihre App in den Vordergrund bringt. Wenn für deine App ein Update im Status DOWNLOADED verfügbar ist, fordere den Nutzer auf, das Update zu installieren. Andernfalls belegen die Updatedaten weiterhin den Speicherplatz auf dem Gerät des Nutzers.

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();
              }
          });
}

Sofortiges Update verarbeiten

Wenn du ein sofortiges Update startest und der Nutzer dem Update zustimmt, zeigt Google Play den Fortschritt des Updates während des gesamten Updatevorgangs über der Benutzeroberfläche deiner App an. Wenn der Nutzer deine App während des Updates schließt oder beendet, sollte das Update im Hintergrund ohne zusätzliche Bestätigung durch den Nutzer weiter heruntergeladen und installiert werden.

Wenn deine App jedoch wieder in den Vordergrund wechselt, solltest du prüfen, ob das Update nicht im Status UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS hängen geblieben ist. Wenn das Update in diesem Zustand hängen bleibt, setzen Sie es fort:

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,
                  activityResultLauncher,
                  AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build())
            }
        }
}

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,
                  activityResultLauncher,
                  AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build());
            }
          });
}

Der Aktualisierungsablauf gibt ein Ergebnis zurück, wie in der Referenzdokumentation zu startUpdateFlowForResult() beschrieben. Insbesondere sollte deine App in der Lage sein, Fälle zu verarbeiten, in denen ein Nutzer das Update ablehnt oder den Download abbricht. Wenn der Nutzer eine dieser Aktionen ausführt, wird die Google Play-Benutzeroberfläche geschlossen. Ihre App sollte den besten Weg für das weitere Vorgehen bestimmen.

Wenn möglich, lass den Nutzer ohne das Update fortfahren und fordere ihn später noch einmal auf. Wenn deine App ohne das Update nicht funktioniert, solltest du eine informative Nachricht anzeigen, bevor du den Updatevorgang neu startest oder den Nutzer aufforderst, die App zu schließen. So versteht der Nutzer, dass er die App neu starten kann, wenn er bereit ist, das erforderliche Update zu installieren.

Nächste Schritte

Testen Sie die In-App-Updates Ihrer App, um zu prüfen, ob die Integration ordnungsgemäß funktioniert.