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 Fälle, in denen die Implementierung nativen Code (C/C++) verwendet, und für Fälle, in denen Unity verwendet wird.

Entwicklungsumgebung einrichten

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

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 Anwendung verfügbar ist. Verwenden Sie AppUpdateManager, um nach einem Update zu 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 Verfügbarkeitsstatus des Updates. Abhängig vom Status des Updates enthält die Instanz außerdem Folgendes:

  • Wenn ein Update verfügbar ist und das Update 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.

Veraltete Updates prüfen

Neben der Prüfung, ob ein Update verfügbar ist, kannst du auch prüfen, wie viel Zeit vergangen ist, seit der Nutzer das letzte Mal über ein Update über den Play Store benachrichtigt wurde. Dies kann Ihnen bei der Entscheidung helfen, ob Sie ein flexibles oder ein sofortiges Update vornehmen sollten. Sie können beispielsweise einige Tage warten, bevor Sie den Nutzer über ein flexibles Update benachrichtigen, und einige Tage danach, bevor ein sofortiges Update erforderlich ist.

Mit clientVersionStalenessDays() kannst du prüfen, wie viele Tage seit dem Update im Play Store verfügbar 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 Ihre App entscheiden, wie dringend ein Update dem Nutzer empfohlen wird. Betrachten Sie beispielsweise die folgende Strategie zum Festlegen der Aktualisierungspriorität:

  • Kleinere Verbesserungen der Benutzeroberfläche: Aktualisierung mit niedriger Priorität; weder ein flexibles noch eine sofortige Aktualisierung anfordern. Du solltest nur aktualisieren, wenn der Nutzer nicht mit deiner App interagiert.
  • Leistungsverbesserungen: Aktualisierung mit mittlerer Priorität; flexible Aktualisierung anfordern.
  • Kritisches Sicherheitsupdate: Update mit hoher Priorität. Fordern Sie ein sofortiges Update an.

Zur Bestimmung der Priorität verwendet Google Play einen ganzzahligen Wert zwischen 0 und 5, wobei 0 die Standardeinstellung und 5 die höchste Priorität ist. Verwende das Feld inAppUpdatePriority unter Edits.tracks.releases in der Google Play Developer API, um die Priorität für eine Aktualisierung festzulegen. Alle neu hinzugefügten Versionen im Release haben dieselbe Priorität wie der Release. Die Priorität kann nur bei der Einführung 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 für In-App-Updates sollte in der Ressource Edit.tracks angegeben werden, die mit der Methode Edit.tracks: update ü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. Stellen Sie sich beispielsweise das folgende Szenario vor:

  • Du veröffentlichst Version 1 in einem Produktions-Track ohne Priorität.
  • Sie veröffentlichen Version 2 in einem internen Test-Track mit 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 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 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());

Jede AppUpdateInfo-Instanz kann nur einmal verwendet werden, um ein Update zu starten. Wenn Sie das Update nach einem Fehler wiederholen möchten, fordern Sie einen neuen 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 finden Sie im Abschnitt Callback zum Updatestatus abrufen.

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

Aktualisierung mit AppUpdateOptions konfigurieren

AppUpdateOptions enthält ein AllowAssetPackDeletion-Feld, das definiert, ob das Update bei begrenztem Speicherplatz auf dem Gerät Asset-Packs löschen darf. Dieses Feld ist standardmäßig auf false gesetzt, aber Sie können stattdessen die Methode setAllowAssetPackDeletion() verwenden, um es auf true festzulegen:

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 erhalten Sie diesen Callback möglicherweise nicht, da das Update zum Zeitpunkt der Zeitkontrolle bereits abgeschlossen sein sollte.
  • RESULT_CANCELED: Der Nutzer hat das Update abgelehnt oder abgebrochen.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Aufgrund eines anderen Fehlers konnte der Nutzer entweder seine Einwilligung nicht erteilen oder die Aktualisierung konnte nicht fortgesetzt werden.

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, wird der Download im Hintergrund gestartet und der Nutzer kann weiter mit deiner App interagieren. In diesem Abschnitt wird beschrieben, wie ein flexibles In-App-Update überwacht und durchgeführt wird.

Status der flexiblen Aktualisierung überwachen

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 in der Benutzeroberfläche Ihrer Anwendung anzeigen zu lassen.

Sie können den Status einer laufenden Aktualisierung überwachen, indem Sie einen Listener für Updates des Installationsstatus registrieren. Du kannst auch eine Fortschrittsanzeige in der Benutzeroberfläche der App anzeigen lassen, 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, müssen Sie die Anwendung neu starten, um das Update zu installieren.

Anders als bei sofortigen Updates löst Google Play für ein flexibles Update nicht automatisch einen App-Neustart aus. Der Grund hierfür ist, dass der Nutzer während eines flexiblen Updates erwartet, dass er weiterhin mit der Anwendung interagiert, bis er beschließt, das Update zu installieren.

Es empfiehlt sich, eine Benachrichtigung (oder einen anderen Hinweis auf die Benutzeroberfläche) zu senden, um den Nutzer darüber zu informieren, dass das Update installiert werden kann, und vor dem Neustart der App eine Bestätigung anzufordern.

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 Sie appUpdateManager.completeUpdate() im Vordergrund aufrufen, zeigt die Plattform eine Vollbild-UI an, durch die die App im Hintergrund neu gestartet wird. Nachdem die Plattform das Update installiert hat, wird Ihre App mit der Hauptaktivität neu gestartet.

Wenn du stattdessen completeUpdate() aufrufst, während deine App im Hintergrund läuft, wird das Update automatisch installiert, ohne die Geräte-UI zu verdecken.

Immer wenn der Nutzer deine App in den Vordergrund bringt, solltest du prüfen, ob für deine App ein Update zur Installation bereitsteht. Wenn es für deine App ein Update mit dem Status DOWNLOADED gibt, fordere den Nutzer auf, 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 du ein sofortiges Update startest und der Nutzer dem Beginn des Updates zustimmt, zeigt Google Play den Updatefortschritt während der gesamten Dauer des Updates auf der Benutzeroberfläche deiner App an. Wenn der Nutzer deine App während des Updates schließt oder beendet, sollte das Update ohne zusätzliche Bestätigung durch den Nutzer im Hintergrund weiter heruntergeladen und installiert werden.

Wenn die Anwendung jedoch in den Vordergrund zurückkehrt, sollten Sie prüfen, ob das Update im Status UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS angehalten wurde. Wenn das Update in diesem Status angehalten wurde, setze 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 gemäß der Beschreibung in der Referenzdokumentation für startUpdateFlowForResult() zurück. Ihre App sollte insbesondere in der Lage sein, Fälle zu verarbeiten, in denen ein Nutzer die Aktualisierung ablehnt oder den Download abbricht. Wenn der Nutzer eine dieser Aktionen ausführt, wird die Google Play-Benutzeroberfläche geschlossen. Ihre App sollte die beste Vorgehensweise bestimmen.

Lass den Nutzer nach Möglichkeit ohne das Update fortfahren und frage ihn später noch einmal. Wenn deine App ohne das Update nicht funktioniert, solltest du vor einem Neustart des Updateablaufs eine entsprechende Meldung einblenden oder den Nutzer auffordern, die App zu schließen. So weiß der Nutzer, dass er deine App neu starten kann, wenn er zur Installation des erforderlichen Updates bereit ist.

Nächste Schritte

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