Z tego przewodnika dowiesz się, jak obsługiwać aktualizacje w aplikacji w aplikacji za pomocą Kotlina lub Javy. Istnieją oddzielne przewodniki na wypadek, gdy implementacja używa kodu natywnego (C/C++), oraz na wypadek, gdy używa Unity lub Unreal Engine.
Konfigurowanie środowiska programistycznego
Biblioteka aktualizacji w aplikacji w Google Play należy do podstawowych bibliotek Google Play. Aby zintegrować Bibliotekę aktualizacji w aplikacji Google Play, dodaj tę zależność Gradle.
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") ... }
Sprawdzanie dostępności aktualizacji
Zanim poprosisz o aktualizację, sprawdź, czy jest dostępna aktualizacja aplikacji.
Aby sprawdzić, czy jest dostępna aktualizacja, kliknij 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. } });
Zwrócona instancja AppUpdateInfo
zawiera stan dostępności aktualizacji. W zależności od stanu aktualizacji instancja zawiera też:
- Jeśli aktualizacja jest dostępna i dozwolona, instancja zawiera też intencję rozpoczęcia aktualizacji.
- Jeśli aktualizacja w aplikacji jest już w toku, instancja podaje też stan tej aktualizacji.
Sprawdzanie aktualności aktualizacji
Oprócz sprawdzenia, czy jest dostępna nowa wersja, warto też sprawdzić, ile czasu minęło od ostatniego powiadomienia o aktualizacji w Sklepie Play. Pomoże Ci to zdecydować, czy zainicjować elastyczne wprowadzanie zmian, czy natychmiastowe wprowadzanie zmian. Możesz na przykład poczekać kilka dni, zanim powiadomisz użytkownika o możliwej aktualizacji, a potem jeszcze kilka dni, zanim poprosisz o natychmiastową aktualizację.
Aby sprawdzić, ile dni minęło od udostępnienia aktualizacji w Sklepie Play, użyj opcji clientVersionStalenessDays()
:
Kotlin
val appUpdateManager = AppUpdateManagerFactory.create(context) // Returns an intent object that you use to check for an update. val appUpdateInfoTask = appUpdateManager.appUpdateInfo // Checks whether the platform allows the specified type of update, // and current version staleness. appUpdateInfoTask.addOnSuccessListener { 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. } });
Sprawdzanie priorytetu aktualizacji
Interfejs Google Play Developer API umożliwia ustawienie priorytetu każdej aktualizacji. Pozwala to aplikacji określić, jak mocno zalecić użytkownikowi zaktualizowanie. Rozważ na przykład tę strategię ustawiania priorytetu aktualizacji:
- Niewielkie ulepszenia interfejsu: aktualizacja o niskim priorytecie; nie żądaj aktualizacji elastycznej ani natychmiastowej aktualizacji. Aktualizuj tylko wtedy, gdy użytkownik nie wchodzi w interakcję z aplikacją.
- Ulepszenia dotyczące wydajności: aktualizacja o średnim priorytecie; poproś o elastyczne aktualizacje.
- Niezbędna aktualizacja zabezpieczeń: wysoki priorytet; zalecana natychmiastowa aktualizacja.
Aby określić priorytet, Google Play używa liczby całkowitej z zakresu od 0 do 5, przy czym 0 to wartość domyślna, a 5 to najwyższy priorytet. Aby ustawić priorytet aktualizacji, użyj pola inAppUpdatePriority
w sekcji Edits.tracks.releases
w interfejsie Google Play Developer API. Wszystkie nowo dodane wersje w ramach danej wersji mają ten sam priorytet. Priorytet można ustawić tylko podczas wdrażania nowej wersji i nie można go później zmienić.
Ustaw priorytet za pomocą interfejsu Google Play Developer API zgodnie z opisem w dokumentacji interfejsu Play Developer API. Priorytet aktualizacji w aplikacji powinien być określony w zasobie Edit.tracks
przekazanym w ramach metody Edit.tracks: update
. Ten przykład pokazuje, jak wydać aplikację z kodem wersji 88 i inAppUpdatePriority
5:
{ "releases": [{ "versionCodes": ["88"], "inAppUpdatePriority": 5, "status": "completed" }] }
W kodzie aplikacji możesz sprawdzić poziom priorytetu danej aktualizacji za pomocą funkcji updatePriority()
. Zwracana priorytet bierze pod uwagę wartość inAppUpdatePriority
dla wszystkich kodów wersji aplikacji między zainstalowaną wersją a najnowszą dostępną wersją niezależnie od ścieżki wersji. Rozważmy na przykład taki scenariusz:
- Wersja 1 jest publikowana na ścieżce produkcyjnej bez priorytetu.
- Wersję 2 publikujesz na ścieżce testów wewnętrznych z priorytetem 5.
- Wersja 3 jest publikowana na ścieżce produkcyjnej bez priorytetu.
Gdy użytkownicy w wersji produkcyjnej zaktualizują wersję 1 na wersję 3, otrzymają priorytet 5, mimo że wersja 2 została opublikowana na innej ścieżce.
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. } });
Rozpoczynanie aktualizacji
Po potwierdzeniu dostępności aktualizacji możesz poprosić o jej zainstalowanie:
AppUpdateManager.startUpdateFlowForResult()
:
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());
Każdej instancji AppUpdateInfo
można użyć tylko raz do uruchomienia aktualizacji. Aby ponownie spróbować przeprowadzić aktualizację w przypadku niepowodzenia, poproś o nową AppUpdateInfo
i ponownie sprawdź, czy aktualizacja jest dostępna i dozwolona.
Możesz zarejestrować funkcję uruchamiania wyników aktywności, korzystając z wbudowanego kontraktu ActivityResultContracts.StartIntentSenderForResult
. Sprawdź sekcję o rozmowie zwrotnej z uaktualnieniem stanu.
Dalsze czynności zależą od tego, czy prośba dotyczy elastycznej aktualizacji, czy natychmiastowej aktualizacji.
Konfigurowanie aktualizacji za pomocą AppUpdateOptions
AppUpdateOptions
zawiera pole AllowAssetPackDeletion
, które określa, czy aktualizacja może wyczyścić pakiety zasobów w przypadku ograniczonej pamięci urządzenia. Domyślnie to pole jest ustawione na false
, ale możesz użyć metody setAllowAssetPackDeletion()
, aby ustawić je na true
:
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());
Prośba o połączenie zwrotne w celu uzyskania informacji o stanie zgłoszenia
Po rozpoczęciu aktualizacji zarejestrowany wywołanie funkcji wywołania z wynikiem działania otrzymuje wynik okna potwierdzenia:
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. } } });
Z funkcji onActivityResult()
callback możesz otrzymać kilka wartości:
RESULT_OK
: użytkownik zaakceptował aktualizację. W przypadku natychmiastowych aktualizacji możesz nie otrzymać tego połączenia zwrotnego, ponieważ aktualizacja powinna być już zakończona, zanim kontrola zostanie przywrócona do Twojej aplikacji.RESULT_CANCELED
: użytkownik odrzucił lub anulował aktualizację.ActivityResult.RESULT_IN_APP_UPDATE_FAILED
: inny błąd uniemożliwił użytkownikowi wyrażenie zgody lub przeprowadzenie aktualizacji.
Obsługa elastycznej aktualizacji
Gdy rozpoczniesz elastyczne aktualizowanie, użytkownikowi najpierw wyświetli się okno z prośbą o zgodę. Jeśli użytkownik wyrazi zgodę, pobieranie rozpocznie się w tle, a użytkownik będzie mógł nadal korzystać z aplikacji. W tej sekcji opisano, jak monitorować i przeprowadzać elastyczne aktualizacje w aplikacji.
Monitorowanie stanu elastycznej aktualizacji
Po rozpoczęciu pobierania elastycznej aktualizacji aplikacja musi monitorować stan aktualizacji, aby wiedzieć, kiedy można ją zainstalować, oraz wyświetlać postęp w interfejsie aplikacji.
Stan trwającej aktualizacji możesz monitorować, rejestrując listenera na potrzeby aktualizacji stanu instalacji. Możesz też umieścić w interfejsie aplikacji pasek postępu, aby informować użytkowników o postępie pobierania.
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);
Instalowanie elastycznej aktualizacji
Gdy wykryjesz stan InstallStatus.DOWNLOADED
, musisz ponownie uruchomić aplikację, aby zainstalować aktualizację.
W przypadku aktualizacji elastycznych Google Play nie uruchamia automatycznie ponownego uruchamiania aplikacji, tak jak w przypadku aktualizacji natychmiastowych. Dzieje się tak, ponieważ podczas aktualizacji elastycznej użytkownik może nadal korzystać z aplikacji, dopóki nie zdecyduje się na zainstalowanie aktualizacji.
Zalecamy wyświetlenie powiadomienia (lub innego wskazania w interfejsie) z informacją o tym, że aktualizacja jest gotowa do zainstalowania, oraz poproszenie o potwierdzenie przed ponownym uruchomieniem aplikacji.
Ten przykład pokazuje implementację paska informacji w stylu Material Design, który prosi użytkownika o potwierdzenie ponownego uruchomienia aplikacji:
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(); }
Gdy wywołasz appUpdateManager.completeUpdate()
na pierwszym planie, platforma wyświetla interfejs pełnoekranowy, który uruchamia aplikację w tle.
Gdy platforma zainstaluje aktualizację, aplikacja uruchomi się ponownie i przejdzie do głównej czynności.
Jeśli zamiast tego wywołasz completeUpdate()
, gdy aplikacja jest w tle, aktualizacja zostanie zainstalowana bez uruchamiania interfejsu użytkownika.
Za każdym razem, gdy użytkownik przeniesie aplikację na pierwszy plan, sprawdź, czy czeka na nią aktualizacja. Jeśli aplikacja ma aktualizację w stanie DOWNLOADED
, poproś użytkownika o zainstalowanie aktualizacji. W przeciwnym razie dane aktualizacji nadal będą zajmować miejsce na urządzeniu użytkownika.
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(); } }); }
Przeprowadzanie natychmiastowej aktualizacji
Gdy rozpoczniesz natychmiastową aktualizację i użytkownik wyrazi zgodę na jej rozpoczęcie, Google Play będzie wyświetlać postęp aktualizacji na górze interfejsu aplikacji przez cały czas trwania aktualizacji. Jeśli użytkownik zamknie aplikację w trakcie aktualizacji, aktualizacja powinna być nadal pobierana i instalowana w tle bez dodatkowego potwierdzenia przez użytkownika.
Gdy jednak aplikacja wróci na pierwszy plan, sprawdź, czy aktualizacja nie została wstrzymana w stanie UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
. Jeśli aktualizacja wstrzyma się w tym stanie, wznów ją:
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()); } }); }
Proces aktualizacji zwraca wynik zgodnie z opisem w dokumentacji referencyjnej startUpdateFlowForResult()
. W szczególności aplikacja powinna obsługiwać przypadki, gdy użytkownik odrzuci aktualizację lub anuluje pobieranie. Gdy użytkownik wykona któreś z tych działań, interfejs Google Play zostanie zamknięty. Aplikacja powinna określić najlepszy sposób działania.
Jeśli to możliwe, pozwól użytkownikowi kontynuować bez aktualizacji i poproś o to ponownie później. Jeśli aplikacja nie może działać bez aktualizacji, przed ponownym uruchomieniem procesu aktualizacji warto wyświetlić użytkownikowi wiadomość informacyjną lub poprosić go o zamknięcie aplikacji. W ten sposób użytkownik będzie wiedział, że może ponownie uruchomić aplikację, gdy będzie gotowy do zainstalowania wymaganej aktualizacji.
Dalsze kroki
Sprawdź aktualizacje w aplikacji, aby upewnić się, że integracja działa prawidłowo.