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 Anleitungen für den Fall, dass in Ihrer Implementierung nativer Code (C/C++) verwendet wird, und für den Fall, dass in Ihrer Implementierung Unity verwendet wird.

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 zu integrieren.

Cool

// 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")
    ...
}

Verfügbarkeit von Updates prüfen

Bevor Sie ein Update anfordern, prüfen Sie, ob ein Update für Ihre App verfügbar ist. Mit AppUpdateManager können Sie nach einem Update suchen:

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 Verfügbarkeit des Updates. Je nach Status der Aktualisierung enthält die Instanz außerdem Folgendes:

  • Wenn ein Update verfügbar und zulässig ist, enthält die Instanz auch eine Absicht, das Update zu starten.
  • Wenn bereits ein In-App-Update ausgeführt wird, wird in der Instanz auch der Status des laufenden Updates angegeben.

Aktualität von Updates prüfen

Sie sollten nicht nur prüfen, ob ein Update verfügbar ist, sondern auch, wie viel Zeit vergangen ist, seit der Nutzer zuletzt über den Play Store über ein Update informiert wurde. So können Sie leichter entscheiden, ob Sie ein flexibles Update oder ein sofortiges Update starten sollten. Sie können beispielsweise einige Tage warten, bevor Sie den Nutzer über ein flexibles Update informieren, und einige Tage danach, bevor Sie ein sofortiges Update verlangen.

Mit clientVersionStalenessDays() können Sie die Anzahl der Tage seit der Verfügbarkeit des Updates im Play Store prüfen:

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

Priorität des Updates prüfen

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

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

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

Legen Sie die Priorität mit der Google Play Developer API fest, wie in der Google Play Developer API-Dokumentation beschrieben. Die Priorität des In-App-Updates muss in der Edit.tracks-Ressource angegeben werden, die in der Edit.tracks: update-Methode übergeben wird. Das folgende Beispiel zeigt die Veröffentlichung einer Anwendung mit dem Versionscode 88 und inAppUpdatePriority 5:

{
  "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 den inAppUpdatePriority für alle App-Versionscodes zwischen der installierten Version und der neuesten verfügbaren Version, unabhängig vom Release-Track. Betrachten Sie beispielsweise das folgende Szenario:

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

Wenn Produktionsnutzer von Version 1 auf Version 3 aktualisieren, erhalten sie Priorität 5, auch wenn Version 2 auf 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 es mit AppUpdateManager.startUpdateFlowForResult() 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());

Mit jeder AppUpdateInfo-Instanz kann nur einmal ein Update gestartet werden. Wenn das Update fehlschlägt, kannst du es noch einmal versuchen. Fordere dazu eine neue AppUpdateInfo an und prüfe noch einmal, ob das Update verfügbar und zulässig ist.

Sie können einen Launcher für Aktivitätsergebnisse mit dem integrierten Vertrag ActivityResultContracts.StartIntentSenderForResult registrieren. Weitere Informationen finden Sie im Abschnitt Callback zum Updatestatus erhalten.

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 Feld AllowAssetPackDeletion, das festlegt, ob bei begrenztem Gerätespeicherplatz Asset-Pakete im Rahmen des Updates gelöscht werden dürfen. Dieses Feld ist standardmäßig auf false gesetzt. Mit der Methode setAllowAssetPackDeletion() können Sie es jedoch 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 Updatestatus erhalten

Nach dem Start eines Updates erhält der Callback für den Launcher des registrierten Aktivitätsergebnisses 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 erhältst du diesen Rückruf möglicherweise nicht, da die Aktualisierung bis zum Zeitpunkt, zu dem die Steuerung an deine App zurückgegeben wird, bereits abgeschlossen sein sollte.
  • RESULT_CANCELED: Der Nutzer hat das Update abgelehnt oder abgebrochen.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Ein anderer Fehler hat verhindert, dass der Nutzer seine Einwilligung erteilt oder das Update fortgesetzt wurde.

Flexible Aktualisierung verarbeiten

Wenn Sie ein flexibles Update starten, wird dem Nutzer zuerst ein Dialogfeld angezeigt, in dem er um Zustimmung bitten kann. Wenn der Nutzer zustimmt, beginnt der Download im Hintergrund 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 der flexiblen Aktualisierung prüfen

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

Sie können den Status einer laufenden Aktualisierung beobachten, indem Sie einen Listener für Aktualisierungsstatusaktualisierungen registrieren. Sie können auch eine Fortschrittsanzeige in der Benutzeroberfläche der App einfügen, 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 du den Status InstallStatus.DOWNLOADED feststellst, musst du die App neu starten, um das Update zu installieren.

Im Gegensatz zu sofortigen Updates löst Google Play bei einem flexiblen Update nicht automatisch einen App-Neustart aus. Das liegt daran, dass Nutzer bei einem flexiblen Update davon ausgehen, dass sie weiterhin mit der App interagieren können, bis sie sich entscheiden, das Update zu installieren.

Wir empfehlen, eine Benachrichtigung oder eine andere Benutzeroberflächen-Anzeige einzublenden, um den Nutzer darüber zu informieren, dass das Update installiert werden kann, und um eine Bestätigung anzufordern, bevor die App neu gestartet wird.

Das folgende Beispiel zeigt, wie eine Material Design-Snackbar implementiert wird, die eine Bestätigung vom Nutzer anfordert, dass die App neu gestartet werden soll:

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 du appUpdateManager.completeUpdate() im Vordergrund aufrufst, zeigt die Plattform eine Vollbild-Benutzeroberfläche an, über die die App im Hintergrund neu gestartet wird. Nachdem die Plattform das Update installiert hat, wird Ihre App neu gestartet und die Hauptaktivität wird wieder angezeigt.

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

Prüfen Sie jedes Mal, wenn der Nutzer Ihre App in den Vordergrund bringt, ob ein Update für Ihre App zur Installation bereitsteht. Wenn für Ihre App ein Update im Status DOWNLOADED verfügbar ist, bitten Sie den Nutzer, das Update zu installieren. Andernfalls belegen die Updatedaten weiterhin den Gerätespeicher 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();
              }
          });
}

Sofortige Aktualisierung verarbeiten

Wenn Sie ein sofortiges Update starten und der Nutzer der Aktualisierung zustimmt, wird der Fortschritt des Updates während der gesamten Dauer des Updates über der Benutzeroberfläche Ihrer App angezeigt. Wenn der Nutzer Ihre App während des Updates schließt oder beendet, sollte das Update ohne zusätzliche Nutzerbestätigung im Hintergrund fortgesetzt und installiert werden.

Wenn Ihre App jedoch wieder in den Vordergrund wechselt, sollten Sie prüfen, ob das Update nicht im Status UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS steckengeblieben ist. Wenn das Update in diesem Status hängen bleibt, fahren 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 Updatevorgang gibt ein Ergebnis zurück, wie in der Referenzdokumentation für startUpdateFlowForResult() beschrieben. Insbesondere sollte Ihre App Fälle verarbeiten können, 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 vorgeben.

Lassen Sie den Nutzer nach Möglichkeit ohne Update fortfahren und bitten Sie ihn später noch einmal. Wenn Ihre App ohne das Update nicht funktioniert, sollten Sie eine informative Nachricht anzeigen, bevor Sie den Updatevorgang neu starten oder den Nutzer auffordern, die App zu schließen. So weiß der Nutzer, dass er Ihre App neu starten kann, wenn er bereit ist, das erforderliche Update zu installieren.

Nächste Schritte

Teste die In-App-Updates deiner App, um zu prüfen, ob die Integration korrekt funktioniert.