İçeriğe geç
Tüm yazılar

2026'da Android Uygulama İçi Güncelleme API'si: esnek mi zorunlu mu, hangisini ne zaman kullanmalı

Google'ın Uygulama İçi Güncelleme API'sine pratik bir rehber — esnek ve zorunlu akışlar, güncelleme önceliği, bayatlama günleri ve herkesin unuttuğu devam kontrolü.

MFKAPPS 4 dk okuma

Play Store’un otomatik güncellemesi kullanıcılarınızın çoğunu er ya da geç kapsar, ama “er ya da geç” bu cümlede epey iş yapıyor. Yalnızca Wi-Fi ayarı, depolama baskısı ya da Play Store uygulamasını hiç açmayan bir kullanıcı, birini üç sürüm geride bırakabilir — hâlâ iki hafta önce düzelttiğiniz hatanın olduğu build’i çalıştırıyor, ya da daha kötüsü, backend’inizin artık desteklemediği bir sunucu sözleşmesine hâlâ çarpıyor olabilir. Google’ın Uygulama İçi Güncelleme API’si tam bu boşluk için var: uygulamanızın yeni bir sürüm olup olmadığını kontrol etmesine ve güncellemeyi kullanıcıyı hiçbir yere göndermeden, uygulamanın içinden istemesine izin verir.

API’nin iki ayrı akışı var ve yanlış olanı seçmek bunu kötü şekilde göndermenin en yaygın yolu.

Gerçekte nasıl çalışır

API, Play Core’un (com.google.android.play:app-update-ktx) bir parçasıdır. AppUpdateManager’dan güncel AppUpdateInfo’yu istersiniz; bu size bir güncellemenin mevcut olup olmadığını ve Google’ın bu güncelleme hakkında ne bildiğini söyler:

val updateManager = AppUpdateManagerFactory.create(context)

updateManager.appUpdateInfo.addOnSuccessListener { info ->
    if (info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
        // decide which flow to start based on info.updatePriority()
        // and info.clientVersionStalenessDays()
    }
}

Bu AppUpdateInfo nesnesi API’nin aslında tamamı — gerisi ne yapacağınıza karar vermekten ibaret.

Esnek ve zorunlu: iki farklı iş

Esnek, kullanıcı uygulamayı kullanmaya devam ederken güncellemeyi arka planda indirir, sonra hazır olduğunda küçük bir “yeniden başlatıp güncelle” snackbar’ı gösterir. Kullanıcı engellenmez ve istemi kapatabilir. Aciliyeti olmayan her şey için doğru varsayılan budur — bir arayüz cilası, yeni bir özellik, kırıcı olmayan bir hata düzeltmesi.

if (info.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
    updateManager.startUpdateFlowForResult(
        info, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()
    )
}

İndirme bittiğinde, InstallStateUpdatedListener InstallStatus.DOWNLOADED durumunu bildirir ve kurulumu açıkça siz tamamlarsınız:

updateManager.registerListener { state ->
    if (state.installStatus() == InstallStatus.DOWNLOADED) {
        updateManager.completeUpdate() // shows the snackbar's restart action
    }
}

Zorunlu ise tam tersi: kullanıcıyı, güncelleme kurulana kadar uygulamayı kullanmaktan alıkoyan, tam ekran, engelleyici bir akış. Tasarım gereği rahatsız edicidir, bu da onu tam olarak tek bir durum için uygun kılar — mevcut sürüm gerçekten önemli bir şekilde bozuksa. Bir güvenlik düzeltmesi, eski bir istemcinin bozacağı bir Room şema geçişi, eski build’i her istekte çökerten bir backend API değişikliği. Birinin eski sürümü bir gün daha kullanmasına izin vermenin gerçekten zararlı olduğunu açıklayamıyorsanız, bu zorunlu bir güncelleme değil, esnek bir güncellemedir.

if (info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
    updateManager.startUpdateFlowForResult(
        info, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
    )
}

Bunu yalnızca bir kez kullandım: yinelenen işlemlerin nasıl saklandığını değiştiren bir Granyn sürümünde — yeni şemaya yazan eski bir istemci bakiyeleri sessizce yanlış hesaplardı. Buna engelleme değer. Adı değiştirilmiş bir buton değil.

Önceliğe (ve bayatlamaya) karar vermek

AppUpdateInfo, esnek/zorunlu seçimini tahmine bırakmak yerine size iki sinyal verir:

  • updatePriority() — Play Console’da, yayına alma anında, her sürüm için kendinizin belirlediği 0-5 arası bir tam sayı. Diff’ten hesaplanmaz; Google’a (ve kendi istemci kodunuza) bu sürümün ne kadar acil olduğunu siz söylersiniz.
  • clientVersionStalenessDays() — güncellemenin bu belirli kullanıcı için ne zamandır mevcut olduğu, ki bu sizin ne zaman gönderdiğinizden farklıdır. Kademeli bir yayın, aynı sürüm için bile bu sayının kurulum tabanınız genelinde değişmesi anlamına gelir.

Benim için işe yarayan bir kalıp: öncelik 4-5’i zorunlu-uygun olarak ele alın, geri kalan her şey için önceliği bayatlamayla birleştirin — öncelik 3 olan bir sürüm ancak bir-iki hafta talep edilmeden kaldıktan sonra zorunlu hâle gelir, böylece kullanıcılar rahatsız edilmeden önce bir tolerans süresi kazanır.

val shouldForce = info.updatePriority() >= 4 ||
    (info.updatePriority() == 3 && (info.clientVersionStalenessDays() ?: 0) > 14)

Herkesin unuttuğu kontrol: yarıda kalan güncellemeyi sürdürmek

Zorunlu bir güncelleme kesintiye uğrayabilir — kullanıcı uygulamayı arka plana atar, süreç ölür, bir telefon araması gelir. Bu olduğunda Play Core sizin için sessizce devam ettirmez; ilgili ekran her devam ettiğinde, yalnızca başlangıçta bir kez değil, yarıda kalmış bir güncellemeyi kontrol etmeniz gerekir:

override fun onResume() {
    super.onResume()
    updateManager.appUpdateInfo.addOnSuccessListener { info ->
        if (info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
            updateManager.startUpdateFlowForResult(
                info, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
            )
        }
    }
}

Bunu atlarsanız, API’ye kötü bir ün kazandıran hata modunu elde edersiniz: kullanıcı güncelleme ortasında kesintiye uğrar, bir mesaja cevap vermek için uygulamayı arka plana atar, geri döner ve uygulama hiç test etmediğiniz, yarı güncellenmiş bir durumda çalışmaya devam eder. onResume kontrolü üç satırdır ve sağlam bir zorunlu güncelleme ile tekrarlayamadığınız aralıklı bir hata raporu arasındaki farktır.

Gerçek bir yayın beklemeden test etmek

Kendi cihazınızdan, şu anda kurulu build’inize karşı gerçek bir güncellemeyi tetikleyemezsiniz — Play Core’un hesabınıza görünür gerçek bir sürüm farkına ihtiyacı vardır. Pratik kurulum bir internal testing track’idir: oradan eski bir sürüm kodu kurun, sonra yenisini gönderin ve API’nin gerçek farkı görmesine izin verin. Google ayrıca AppUpdateInfo yanıtlarını yerel olarak sahtelemek için bir uygulama içi güncelleme test API’si sunuyor; bu akışa sık dokunuyorsanız bir debug menüsüne bağlamaya değer — öncelik/bayatlama mantığının kendisi üzerinde yineleme yapmak için gerçek bir track gidiş-dönüşünden çok daha hızlı.

Bu özelliğin tamamını dayanacağınız bir UX kalıbı değil, bir güvenlik ağı olarak ele alın. Bu API’nin en iyi versiyonu, kullanıcılarınızın hiç görmediği versiyondur — çünkü otomatik güncelleme zaten işini yapmıştır; esnek ve zorunlu, yapmadığı günler için var.