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

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

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ı ekleyin.

Modern

// 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 olup olmadığını 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 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ğıdakileri de içerir:

  • Güncelleme varsa ve güncellemeye izin veriliyorsa örnek, güncellemeyi başlatma niyeti de içerir.
  • Halihazırda devam eden bir uygulama içi güncelleme varsa örnek, devam eden güncellemenin durumunu da bildirir.

Güncelleme eskiliğini kontrol et

Bir güncelleme olup olmadığını kontrol etmeye ek olarak, kullanıcıya Play Store'dan bir güncellemeyle ilgili son bildirim verilmesinden bu yana ne kadar süre geçtiğine de göz atabilirsiniz. Bu sayede esnek güncelleme mi yoksa anında güncelleme mi başlatmanız gerektiğine karar verebilirsiniz. Örneğin, kullanıcıyı esnek bir güncellemeyle bilgilendirmeden önce birkaç gün, bundan sonra da hemen güncelleme istemeden önce birkaç gün bekleyebilirsiniz.

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 etme

Google Play Geliştirici API'si her güncellemenin önceliğini ayarlamanızı sağlar. Bu sayede uygulamanız, kullanıcıya güncelleme önermesinin ne kadar güçlü olacağına karar verebilir. Ö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şimde olmadığında güncelleyin.
  • Performans iyileştirmeleri: Orta öncelikli güncelleme; esnek güncelleme isteğinde bulunun.
  • Kritik güvenlik güncellemesi: Yüksek öncelikli güncelleme; hemen güncelleme isteğinde bulunun.

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 önceliklidir. 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ümdeki yeni eklenen tüm sürümlerin, sürümle aynı önceliğe sahip olduğu kabul edilir. Öncelik, yalnızca yeni bir sürüm kullanıma sunulurken ayarlanabilir ve daha sonra değiştirilemez.

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

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

Uygulamanızın kodunda, updatePriority() kullanarak belirli bir güncellemenin öncelik seviyesini kontrol edebilirsiniz. Döndürülen öncelikte, 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 dikkate alınır. Örneğin, aşağıdaki senaryoyu inceleyin:

  • Sürüm 1'i öncelik olmadan bir üretim kanalına yayınlarsınız.
  • Sürüm 2'yi önceliği 5 olan bir dahili test kanalına yayınlarsınız.
  • Sürüm 3'ü öncelik olmadan 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 alırlar.

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

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 durumunda güncellemeyi tekrar denemek için yeni bir AppUpdateInfo isteyip güncellemenin kullanılabilir olup olmadığını tekrar kontrol edin.

Yerleşik ActivityResultContracts.StartIntentSenderForResult sözleşmesini kullanarak bir etkinlik sonucu başlatıcıyı kaydedebilirsiniz. Güncelleme durumu için geri arama alma ile ilgili bölüme göz atın.

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 verilmeyeceğini tanımlayan bir AllowAssetPackDeletion alanı içerir. Bu alan varsayılan olarak false değerine ayarlıdır ancak bunun yerine true olarak ayarlamak için setAllowAssetPackDeletion() yöntemini kullanabilirsiniz:

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şladıktan sonra, kayıtlı etkinlik sonucu başlatıcıyı geri çağırma işlemi 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 etti. Anlık güncellemelerde bu geri çağırmayı almayabilirsiniz. Bunun nedeni, uygulamanızın zaman kontrolü verilene kadar güncellemenin tamamlanmış olmasıdır.
  • RESULT_CANCELED: Kullanıcı, güncellemeyi reddetmiştir veya iptal etmiştir.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Başka bir hata, kullanıcının izin vermesini veya güncellemeyi durdurdu.

Esnek güncellemeyi işleme

Esnek güncellemeyi başlattığınızda, kullanıcıya ilk olarak izin istemek 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 indirme işlemi başladıktan sonra uygulamanızın, güncellemenin ne zaman yüklenebileceğini bilmek ve ilerleme durumunu uygulamanızın kullanıcı arayüzünde görüntülemek için 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üncelleme yükleme

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

Anında yapılan güncellemelerden farklı olarak Google Play, esnek güncelleme için bir uygulamanın yeniden başlatılmasını 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şimde bulunmaya devam edeceğini düşünmesidir.

Uygulamayı yeniden başlatmadan önce, kullanıcıya güncellemenin yüklenmeye hazır olduğunu bildirmek ve 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 bir Materyal Tasarıma sahip atıştırmalık çubuğu 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();
}

Ön planda appUpdateManager.completeUpdate() çağrısı yaptığınızda platform, uygulamayı arka planda yeniden başlatan tam ekran bir kullanıcı arayüzü görüntüler. Platform, güncellemeyi yükledikten sonra uygulamanız ana etkinliğinde yeniden başlatılır.

Bunun yerine, uygulamanız arka plandadayken completeUpdate() yöntemini çağırırsanız güncelleme, cihazın kullanıcı arayüzünü gizlemeden sessiz bir şekilde yüklenir.

Kullanıcı, uygulamanızı ön plana getirdiğinde uygulamanızın yüklenmeyi bekleyen bir güncellemesi olup olmadığını kontrol edin. Uygulamanızda DOWNLOADED durumunda bir güncelleme varsa kullanıcıdan güncellemeyi yüklemesini isteyin. Aksi takdirde, güncelleme verileri kullanıcının cihaz depolama alanını doldurmaya 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();
              }
          });
}

Güncellemeleri anında gerçekleştirme

Güncellemeyi anında başlattığınızda kullanıcı güncellemenin başlatılmasına izin verirse Google Play, güncelleme süresince 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 döndüğünde, güncellemenin UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS durumunda kaybolmadığını onaylamanız gerekir. Güncelleme bu durumda kesilmişse 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() işlevi için referans dokümanlarında açıklandığı gibi bir sonuç döndürür. Uygulamanız, özellikle kullanıcının güncellemeyi reddettiği veya indirme işlemini iptal ettiği durumları işleyebilmelidir. Kullanıcı bu işlemlerden birini gerçekleştirdiğinde Google Play kullanıcı arayüzü kapanır. Devam etmek için en iyi yöntemi uygulamanız belirler.

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

Sonraki adımlar

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