Uygulama içi güncellemeleri destekleme (Kotlin veya Java)

Bu kılavuzda, Kotlin veya Java'yı kullanarak uygulamanızda uygulama içi güncellemeleri nasıl destekleyebileceğiniz açıklanmaktadır. Uygulamanızın yerel kod (C/C++) ve Unity kullandığı durumlar için ayrı kılavuzlar mevcuttur.

Geliştirme ortamınızı ayarlama

Play Uygulama İçi Güncelleme Kitaplığı, Google Play Core kitaplıklarının bir parçasıdır. Play Uygulama İçi Güncelleme Kitaplığı'nı entegre etmek için lütfen aşağıdaki Gradle bağımlılığını dahil edin.

Eski

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

Güncelleme kullanılabilirliğini kontrol etme

Güncelleme isteğinde bulunmadan önce uygulamanız için bir güncelleme olup olmadığını kontrol edin. Güncelleme olup olmadığını kontrol etmek için AppUpdateManager değerini kullanın:

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

Döndürülen AppUpdateInfo örneği, güncelleme kullanılabilirlik durumunu içerir. Güncellemenin durumuna bağlı olarak örnek aşağıdaki bilgileri de içerir:

  • Bir güncelleme varsa ve güncellemeye izin veriliyorsa örnek, güncellemeyi başlatma niyeti de içerir.
  • Devam eden bir uygulama içi güncelleme varsa örnek, devam etmekte olan güncellemenin durumunu da bildirir.

Güncelleme eskiliğini kontrol etme

Bir güncellemenin mevcut olup olmadığını kontrol etmenin yanı sıra kullanıcıya Play Store üzerinden son güncelleme bildiriminden bu yana ne kadar süre geçtiğini de kontrol etmek isteyebilirsiniz. Bu, esnek bir güncelleme mi yoksa hemen bir güncelleme mi başlatmanız gerektiğine karar vermenize yardımcı olabilir. Örneğin, kullanıcıyı esnek bir güncellemeyle bilgilendirmeden önce birkaç gün ve bundan sonra, acil güncelleme gerektirmeden birkaç gün bekleyebilir.

Güncellemenin Play Store'da kullanıma sunulmasından bu yana geçen gün sayısını kontrol etmek için clientVersionStalenessDays() aracını kullanın:

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

Güncelleme önceliğini kontrol edin

Google Play Developer API, her güncellemenin önceliğini belirlemenize olanak tanır. Bu, uygulamanızın kullanıcıya ne kadar önemli bir güncelleme önereceğine karar vermesine olanak tanır. Örneğin, güncelleme önceliğini ayarlamak için aşağıdaki stratejiyi göz önünde bulundurun:

  • Kullanıcı arayüzünde küçük iyileştirmeler: Düşük öncelikli güncelleme; ne esnek güncelleme ne de anında güncelleme isteğinde bulunun. Yalnızca kullanıcı, uygulamanızla etkileşim kurmadığında güncelleyin.
  • Performans iyileştirmeleri: Orta öncelikli güncelleme; esnek bir güncelleme isteyin.
  • Kritik güvenlik güncellemesi: Yüksek öncelikli güncelleme; anında güncelleme isteyin.

Google Play, önceliği belirlemek için 0 ile 5 arasında bir tam sayı değeri kullanır. 0 varsayılan, 5 ise en yüksek önceliktir. Bir güncellemenin önceliğini ayarlamak için Google Play Developer API'de Edits.tracks.releases altındaki inAppUpdatePriority alanını kullanın. Sürüme yeni eklenen tüm sürümler, sürümle aynı önceliğe sahiptir. Öncelik yalnızca yeni bir sürüm kullanıma sunulurken ayarlanabilir ve daha sonra değiştirilemez.

Önceliği, Play Developer API belgelerinde açıklandığı gibi Google Play Developer API'yi kullanarak ayarlayın. Uygulama içi güncelleme önceliği, Edit.tracks: update yönteminde iletilen Edit.tracks kaynağında belirtilmelidir. Aşağıdaki örnekte, sürüm kodu 88 ve inAppUpdatePriority 5 olan bir uygulamanın yayınlanması gösterilmektedir:

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

Uygulamanızın kodunda, belirli bir güncellemenin öncelik düzeyini updatePriority() kullanarak kontrol edebilirsiniz. Döndürülen öncelik, sürüm kanalından bağımsız olarak, yüklü sürüm ile mevcut en son sürüm arasındaki tüm uygulama sürüm kodları için inAppUpdatePriority bilgisini dikkate alır. Örneğin, aşağıdaki senaryoyu inceleyin:

  • Sürüm 1'i önceliği olmayan bir üretim kanalına yayınlarsınız.
  • Sürüm 2'yi önceliği 5 olan dahili test kanalına yayınlarsınız.
  • Sürüm 3'ü önceliği olmayan bir üretim kanalına yayınlarsınız.

Üretim kullanıcıları sürüm 1'den sürüm 3'e güncelleme yaptıklarında, sürüm 2 farklı bir kanalda yayınlanmış olsa bile öncelik 5'e sahip olurlar.

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

Güncelleme başlatın

Bir güncellemenin olduğunu onayladıktan sonra AppUpdateManager.startUpdateFlowForResult() adresini kullanarak güncelleme isteğinde bulunabilirsiniz:

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

Her AppUpdateInfo örneği yalnızca bir kez güncelleme başlatmak için kullanılabilir. Hata olması durumunda güncellemeyi yeniden denemek için yeni bir AppUpdateInfo isteyin ve güncellemenin kullanılabilir ve izin verildiğini tekrar kontrol edin.

Yerleşik ActivityResultContracts.StartIntentSenderForResult sözleşmesini kullanarak etkinlik sonucu başlatıcı kaydedebilirsiniz. Güncelleme durumu için geri aranma ile ilgili bölümü kontrol edin.

Sonraki adımlar esnek güncelleme mi yoksa anlık güncelleme mi istediğinize bağlıdır.

AppUpdateOptions ile güncelleme yapılandırma

AppUpdateOptions, cihaz depolama alanının sınırlı olması durumunda güncellemenin öğe paketlerini temizlemesine izin verilip verilmediğini tanımlayan bir AllowAssetPackDeletion alanı içerir. Bu alan varsayılan olarak false değerine ayarlıdır ancak bunun yerine setAllowAssetPackDeletion() yöntemini kullanarak alanı true olarak ayarlayabilirsiniz:

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

Güncelleme durumu için geri aranma

Bir güncelleme başlatıldıktan sonra, kayıtlı etkinlik sonucu başlatıcı geri çağırması onay iletişim kutusu sonucunu alır:

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

onActivityResult() geri çağırmasından alabileceğiniz birkaç değer vardır:

  • RESULT_OK: Kullanıcı, güncellemeyi kabul etmiştir. Anlık güncellemelerde, uygulamanıza geri arama verilmeden önce güncellemenin tamamlanmış olması gerektiğinden bu geri çağırmayı alamayabilirsiniz.
  • RESULT_CANCELED: Kullanıcı güncellemeyi reddetti veya iptal etti.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Başka bir hata, kullanıcının izin vermesini veya güncellemenin devam etmesini engelledi.

Esnek güncellemeleri yönetme

Esnek güncelleme başlattığınızda, önce kullanıcıya izin istemesi için bir iletişim kutusu gösterilir. Kullanıcı izin verirse indirme işlemi arka planda başlar ve kullanıcı uygulamanızla etkileşimde bulunmaya devam edebilir. Bu bölümde esnek bir uygulama içi güncellemeyi nasıl izleyeceğiniz ve tamamlayacağınız açıklanmaktadır.

Esnek güncelleme durumunu izleme

Esnek güncelleme için indirme işlemi başladıktan sonra, güncellemenin ne zaman yüklenebileceğini öğrenmek ve ilerlemeyi uygulamanızın kullanıcı arayüzünde göstermek için uygulamanızın güncelleme durumunu izlemesi gerekir.

Yükleme durumu güncellemeleri için bir işleyici kaydederek devam eden bir güncellemenin durumunu izleyebilirsiniz. Ayrıca, kullanıcıları indirme işleminin ilerleme durumu hakkında bilgilendirmek için uygulamanın kullanıcı arayüzünde bir ilerleme çubuğu da sağlayabilirsiniz.

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

Esnek güncellemeyi yükleme

InstallStatus.DOWNLOADED durumunu algıladığında güncellemeyi yüklemek için uygulamayı yeniden başlatmanız gerekir.

Anında güncellemelerden farklı olarak Google Play, esnek güncelleme için uygulama yeniden başlatma işlemini otomatik olarak tetiklemez. Bunun nedeni, esnek güncelleme sırasında kullanıcının güncellemeyi yüklemek istediğine karar verene kadar uygulamayla etkileşim kurmaya devam etmesini beklemesidir.

Kullanıcıya güncellemenin yüklenmeye hazır olduğunu bildirmek ve uygulamayı yeniden başlatmadan önce onay istemek için bir bildirim (veya başka bir kullanıcı arayüzü göstergesi) sağlamanız önerilir.

Aşağıdaki örnekte, uygulamayı yeniden başlatması için kullanıcıdan onay isteyen Materyal Tasarıma sahip hızlı yemek çubuğunun uygulanması gösterilmektedir:

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

appUpdateManager.completeUpdate()'i ön planda çağırdığınızda platform, uygulamayı arka planda yeniden başlatan tam ekran bir kullanıcı arayüzü gösterir. Platform güncellemeyi yükledikten sonra, uygulamanız ana etkinliğine yeniden başlatılır.

Bunun yerine, uygulamanız arka plandayken completeUpdate() çağrısı yaparsanız güncelleme, cihazın kullanıcı arayüzü kapatılmadan sessiz bir şekilde yüklenir.

Kullanıcı uygulamanızı ön plana her getirdiğinde, uygulamanızın yüklenmeyi bekleyen bir güncellemesi olup olmadığını kontrol edin. Uygulamanızın DOWNLOADED durumunda bir güncellemesi varsa kullanıcıdan güncellemeyi yüklemesini isteyin. Aksi takdirde, güncelleme verileri kullanıcının cihaz depolama alanını kullanmaya devam eder.

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

Anlık güncelleme yapma

Anında bir güncelleme başlattığınızda ve kullanıcı güncellemenin başlatılmasına izin verdiğinde Google Play, güncelleme süresinin tamamı boyunca güncelleme ilerleme durumunu uygulamanızın kullanıcı arayüzünün üst kısmında gösterir. Kullanıcı, güncelleme sırasında uygulamanızı kapatır veya sonlandırırsa güncelleme, ek kullanıcı onayı olmadan arka planda indirilmeye ve yüklenmeye devam etmelidir.

Ancak, uygulamanız ön plana geri döndüğünde, güncellemenin UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS durumunda takılı olmadığını onaylamanız gerekir. Güncelleme bu durumda kaldıysa güncellemeyi devam ettirin:

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

Güncelleme akışı, startUpdateFlowForResult() referans belgelerinde açıklanan şekilde bir sonuç döndürür. Uygulamanızın özellikle kullanıcının güncellemeyi reddettiği veya indirme işlemini iptal ettiği durumları işleyebilmesi gerekir. Kullanıcı bu işlemlerden birini gerçekleştirdiğinde Google Play kullanıcı arayüzü kapanır. Uygulamanız, devam etmek için en iyi yöntemi belirlemelidir.

Mümkünse kullanıcının güncelleme yapmadan devam etmesine izin verin ve daha sonra tekrar isteyin. Uygulamanız güncelleme olmadan çalışamıyorsa, güncelleme akışını yeniden başlatmadan veya kullanıcıdan uygulamayı kapatmasını istemeden önce bilgilendirici bir mesaj görüntülemenizi öneririz. Bu şekilde, kullanıcı gerekli güncellemeyi yüklemeye hazır olduğunda uygulamanızı yeniden başlatabileceğini anlar.

Sonraki adımlar

Entegrasyonunuzun doğru çalıştığını doğrulamak için uygulamanızın uygulama içi güncellemelerini test edin.