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

Bu kılavuzda, Kotlin veya Java kullanılarak uygulamanızda uygulama içi güncellemeleri nasıl destekleyeceğiniz açıklanmaktadır. Uygulamanızın doğal kod (C/C++) kullandığı durumlar ve uygulamanızın Unity kullandığı durumlar için ayrı kılavuzlar vardır.

Geliştirme ortamınızı kurma

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.

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

Güncelleme olup olmadığını kontrol etme

Güncelleme isteğinde bulunmadan önce uygulamanız için güncelleme olup olmadığını kontrol edin. Güncelleme olup olmadığını kontrol etmek için AppUpdateManager simgesini 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 mevcutsa ve güncellemeye izin veriliyorsa örnek, güncellemeyi başlatma amacı da içerir.
  • Uygulama içi güncelleme zaten devam ediyorsa örnek, devam eden güncellemenin durumunu da bildirir.

Güncellemenin güncel olup olmadığını kontrol etme

Kullanıcıya Play Store üzerinden son güncelleme bildirimi gönderildikten bu yana ne kadar süre geçtiğini de kontrol edebilirsiniz. Bu, esnek bir güncelleme mi yoksa anında güncelleme mi başlatacağınıza karar vermenize yardımcı olabilir. Örneğin, kullanıcıyı esnek bir güncellemeyle bilgilendirmeden önce birkaç gün bekleyebilir ve hemen güncelleme yapmadan önce birkaç gün daha bekleyebilirsiniz.

Güncellemenin Play Store'da kullanıma sunulmasından bu yana geçen gün sayısını kontrol etmek için clientVersionStalenessDays() simgesini 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 Developer API, her güncellemenin önceliğini ayarlamanıza olanak tanır. Bu sayede uygulamanız, kullanıcıya güncellemeyi ne kadar güçlü bir şekilde önereceğine karar verebilir. Örneğin, güncelleme önceliğini belirlemek için aşağıdaki stratejiyi kullanabilirsiniz:

  • Kullanıcı arayüzünde küçük iyileştirmeler: Düşük öncelikli güncelleme; esnek güncelleme veya anlık güncelleme isteğinde bulunmayın. Yalnızca kullanıcı uygulamanızla etkileşimde değilken güncelleyin.
  • Performans iyileştirmeleri: Orta öncelikli güncelleme; esnek bir güncelleme isteyin.
  • Kritik güvenlik güncellemesi: Yüksek öncelikli güncellemedir. Hemen güncelleme isteyin.

Google Play, önceliği belirlemek için 0 ile 5 arasında bir tam sayı 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ümlerin önceliği, sürümle aynı kabul edilir. Öncelik yalnızca yeni bir sürüm kullanıma sunulduğunda belirlenebilir ve daha sonra değiştirilemez.

Önceliği, Play Developer API dokümanlarında açıklandığı şekilde Google Play Developer API'yi kullanarak ayarlayın. Uygulama içi güncelleme önceliği, Edit.tracks: update metodunda 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, updatePriority() kullanarak belirli bir güncellemenin öncelik düzeyini 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 değerini dikkate alır. Örneğin, aşağıdaki senaryoyu inceleyin:

  • 1. sürümü, önceliği olmayan bir üretim kanalında yayınlarsınız.
  • 2. sürümü, önceliği 5 olan bir dahili test kanalında yayınlarsınız.
  • 3. sürümü, önceliği olmayan bir üretim kanalında yayınlarsınız.

Üretim kullanıcıları 1. sürümden 3. sürüme güncellendiğinde, 2. sürüm farklı bir kanalda yayınlanmış olsa bile öncelik 5'tir.

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şlatma

Güncelleme olduğunu onayladıktan sonra AppUpdateManager.startUpdateFlowForResult() simgesini 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, güncelleme başlatmak için yalnızca bir kez kullanılabilir. Başarısızlık durumunda güncellemeyi yeniden denemek için yeni bir AppUpdateInfo isteyin ve güncellemenin kullanılabilir olup olmadığını ve izin verilip verilmediğini tekrar kontrol edin.

Yerleşik ActivityResultContracts.StartIntentSenderForResult sözleşmesini kullanarak etkinlik sonucu başlatıcı kaydedebilirsiniz. Durum güncellemesi için geri arama alma bölümünü inceleyin.

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

AppUpdateOptions ile güncellemeyi yapılandırma

AppUpdateOptions, sınırlı cihaz depolama alanı olması durumunda güncellemenin öğe paketlerini temizlemesine izin verilip verilmeyeceğini tanımlayan bir AllowAssetPackDeletion alanı içerir. Bu alan varsayılan olarak false olarak ayarlanmıştır ancak setAllowAssetPackDeletion() yöntemini kullanarak 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());

Durum güncellemesi için geri arama alma

Bir güncelleme başladıktan sonra, kayıtlı etkinlik sonucu başlatıcısı geri çağırma işlevi 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() callback'inden alabileceğiniz birkaç değer vardır:

  • RESULT_OK: Kullanıcı güncellemeyi kabul etti. Kontrol uygulamanıza geri verildiğinde güncelleme zaten tamamlanmış olacağından anında güncellemeler için bu geri çağırma çağrısını alamayabilirsiniz.
  • RESULT_CANCELED: Kullanıcı güncellemeyi reddetti veya iptal etti.
  • ActivityResult.RESULT_IN_APP_UPDATE_FAILED: Kullanıcı izni vermeyi veya güncellemenin devam etmesini engelleyen başka bir hata oluştu.

Esnek güncellemeyi işleme

Esnek bir güncellemeyi başlattığınızda kullanıcıdan izin isteğinde bulunmak için önce bir iletişim kutusu gösterilir. Kullanıcı izin verirse indirme işlemi arka planda başlar ve kullanıcı uygulamanızla etkileşim kurmaya devam edebilir. Bu bölümde, esnek uygulama içi güncellemeyi nasıl izleyebileceğiniz ve tamamlayabileceğiniz açıklanmaktadır.

Esnek güncelleme durumunu izleme

Esnek güncelleme indirilmeye başladıktan sonra uygulamanızın, güncellemenin ne zaman yüklenebileceğini öğrenmek 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 dinleyici kaydederek devam eden bir güncellemenin durumunu izleyebilirsiniz. Ayrıca, kullanıcıları indirme işleminin ilerleme durumundan haberdar etmek 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 tespit ettiğinizde güncellemeyi yüklemek için uygulamayı yeniden başlatmanız gerekir.

Anında güncellemelerin aksine Google Play, esnek güncelleme için 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 isteyip istemediğine karar verene kadar uygulamayla etkileşime devam etmeyi 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şlatmak için kullanıcıdan onay isteyen bir Materyal Tasarım bilgi çubuğu'nun 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();
}

Ön planda appUpdateManager.completeUpdate() simgesine dokunduğunuzda 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ğinde yeniden başlatılır.

Bunun yerine, uygulamanız arka plandayken completeUpdate() işlevini çağırırsanız güncelleme, cihaz kullanıcı arayüzünü gizlemeden sessizce yüklenir.

Kullanıcı uygulamanızı ön plana getirdiğinde, uygulamanızda yüklenmeyi bekleyen bir güncelleme olup olmadığını kontrol edin. Uygulamanızda DOWNLOADED durumu olan 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ı 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();
              }
          });
}

Acil güncellemeyi işleme

Anında güncelleme başlattığınızda ve kullanıcı güncellemeyi başlatmayı kabul ettiğinde Google Play, güncellemenin tüm süresi boyunca uygulamanızın kullanıcı arayüzünün üstünde güncelleme ilerleme durumunu gösterir. Kullanıcı güncelleme sırasında uygulamanızı kapatırsa veya sonlandırırsa güncelleme, ek kullanıcı onayı olmadan arka planda indirilip yüklenmeye devam eder.

Ancak uygulamanız ön plana döndüğünde güncellemenin UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS durumunda takılı kalmadığını onaylamanız gerekir. Güncelleme bu durumda durmuşsa 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şlevinin referans dokümanlarında açıklandığı şekilde bir sonuç döndürür. Özellikle, uygulamanız bir kullanıcının güncellemeyi reddetmesi veya indirme işlemini iptal etmesi gibi durumları ele alabilmelidir. Kullanıcı bu işlemlerden birini gerçekleştirdiğinde Google Play kullanıcı arayüzü kapanır. Devam etmenin en iyi yolunu uygulamanız 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 önce bilgilendirici bir mesaj gösterebilir veya kullanıcıdan uygulamayı kapatmasını isteyebilirsiniz. Bu sayede 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.