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

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

Entwicklungsumgebung einrichten

Die Bibliothek für In-App-Updates von Google Play ist Teil der Google Play-Kernbibliotheken. Fügen Sie die folgende Gradle-Abhängigkeit hinzu, um die In-App-Update-Bibliothek von Google Play zu integrieren.

Groovig

// 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 für Ihre App ein Update 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 der Aktualisierung enthält die Instanz außerdem Folgendes:

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

Update-Veralterung prüfen

Sie können nicht nur prüfen, ob ein Update verfügbar ist, sondern auch, wie viel Zeit vergangen ist, seit der Nutzer das letzte Mal über den Play Store über ein Update benachrichtigt wurde. Dies kann Ihnen bei der Entscheidung helfen, ob Sie ein flexibles oder ein sofortiges Update initiieren sollten. Beispielsweise können Sie einige Tage warten, bevor Sie den Nutzer mit einem flexiblen Update benachrichtigen, und einige Tage danach, bevor Sie eine sofortige Aktualisierung anfordern.

Mit clientVersionStalenessDays() kannst du prüfen, wie viele Tage seit dem Update im 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. Auf diese Weise kann deine App entscheiden, wie stark sie dem Nutzer ein Update empfehlen sollte. Betrachten Sie beispielsweise die folgende Strategie zum Festlegen der Aktualisierungspriorität:

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

Zur Bestimmung der Priorität verwendet Google Play eine Ganzzahl zwischen 0 und 5, wobei 0 die Standardeinstellung und 5 die höchste Priorität ist. Du kannst die Priorität für ein Update in der Google Play Developer API im Feld inAppUpdatePriority unter Edits.tracks.releases festlegen. 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 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 in der Methode Edit.tracks: update übergeben wird. Im folgenden Beispiel wird die Veröffentlichung einer App mit den Versionscodes 88 und inAppUpdatePriority 5 veranschaulicht:

{
  "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 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 Priorität 5.
  • Sie veröffentlichen Version 3 in einem Produktions-Track ohne Priorität.

Wenn Produktionsnutzer ein Update von Version 1 auf Version 3 durchführen, 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 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 ein Update nur einmal gestartet werden. Wenn Sie das Update wiederholen möchten, falls es fehlschlägt, 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 Aktivitätsergebnis-Launcher mit dem integrierten ActivityResultContracts.StartIntentSenderForResult-Vertrag registrieren. Lesen Sie dazu den Abschnitt Callback für den Updatestatus 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 angibt, ob durch das Update bei begrenztem Gerätespeicher Asset-Packs gelöscht werden dürfen. 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());

Callback für Updatestatus abrufen

Nach dem Start eines Updates erhält der Callback des Launchers der registrierten Aktivitätsergebnisse 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.
            }
        }
    });

Der onActivityResult()-Callback kann mehrere Werte liefern:

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

Flexible Updates verarbeiten

Wenn Sie ein flexibles Update starten, wird dem Nutzer zuerst ein Dialogfeld angezeigt, in dem er seine Einwilligung einholen kann. Wenn der Nutzer einwilligt, wird der Download im Hintergrund gestartet und er 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 überwachen

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

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 bereitstellen, um Nutzer über den Downloadfortschritt 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 App neu starten, um das Update zu installieren.

Im Gegensatz zu sofortigen Updates löst Google Play nicht automatisch einen App-Neustart für ein flexibles Update aus. Dies liegt daran, dass der Nutzer während eines flexiblen Updates weiterhin mit der Anwendung interagieren möchte, bis er das Update installieren möchte.

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

Das folgende Beispiel zeigt die Implementierung einer Material Design-Snackbar, die den Nutzer um eine Bestätigung zum Neustart der App bittet:

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 Ihre App mit der Hauptaktivität neu gestartet.

Wenn Sie stattdessen completeUpdate() aufrufen, während Ihre App im Hintergrund ausgeführt wird, wird das Update im Hintergrund installiert, ohne die Benutzeroberfläche des Geräts zu verdecken.

Wenn der Nutzer Ihre App in den Vordergrund bringt, prüfen Sie, ob ein Update für die App verfügbar ist, das noch installiert werden muss. Wenn es für Ihre App ein Update mit dem Status DOWNLOADED gibt, fordern Sie den Nutzer auf, das Update zu installieren. Andernfalls belegen die Update-Daten 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();
              }
          });
}

Ein sofortiges Update durchführen

Wenn Sie ein sofortiges Update starten und der Nutzer einwilligt, mit dem Update zu beginnen, zeigt Google Play den Aktualisierungsfortschritt während der gesamten Dauer des Updates oben auf der Benutzeroberfläche Ihrer App an. Wenn der Nutzer die App während des Updates schließt oder beendet, sollte das Update ohne zusätzliche Bestätigung durch den Nutzer weiterhin im Hintergrund heruntergeladen und installiert werden.

Wenn Ihre App jedoch in den Vordergrund zurückkehrt, sollten Sie prüfen, ob das Update im Status UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS festhängt. Wenn das Update in diesem Status angehalten wird, 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 Aktualisierungsvorgang gibt ein Ergebnis zurück, wie in der Referenzdokumentation zu startUpdateFlowForResult() beschrieben. Ihre App sollte insbesondere Fälle bewältigen 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 die beste Vorgehensweise ermitteln.

Wenn möglich, lassen Sie den Nutzer ohne das Update fortfahren und fordern Sie ihn später noch einmal auf. Wenn deine App ohne das Update nicht funktionieren kann, solltest du vor dem Neustart des Updates eine entsprechende Meldung anzeigen lassen oder den Nutzer zum Schließen der App auffordern. So weiß der Nutzer, dass er die App neu starten kann, wenn er das erforderliche Update installieren möchte.

Nächste Schritte

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