Play Faturalandırma Kitaplığı çağrısı bir işlemi tetiklediğinde kitaplık, geliştiricileri sonuç hakkında bilgilendirmek için bir BillingResult
yanıtı döndürür. Örneğin, kullanıcı için kullanılabilir teklifleri almak amacıyla queryProductDetailsAsync
kullanırsanız yanıt kodu bir Ok kodu ve doğru ProductDetails
nesnesini sağlar ya da ProductDetails
nesnesinin neden sağlanamadığını gösteren farklı bir yanıt içerir.
Tüm yanıt kodları hata değildir. BillingResponseCode
referans sayfasında, bu kılavuzda açıklanan her bir yanıtın ayrıntılı bir açıklaması yer alır.
Aşağıda, hata göstermeyen yanıt kodlarına birkaç örnek verilmiştir:
BillingClient.BillingResponseCode.OK
: Arama tarafından tetiklenen işlem başarıyla tamamlandı.BillingClient.BillingResponseCode.USER_CANCELED
: Kullanıcıya Play Store kullanıcı arayüzü akışlarını gösteren işlemler için bu yanıt, kullanıcının işlemi tamamlamadan bu kullanıcı arayüzü akışlarından ayrıldığını belirtir.
Yanıt kodu bir hata gösteriyorsa bunun nedeni bazen geçici koşullardır ve dolayısıyla kurtarma mümkündür. Play Faturalandırma Kitaplığı yöntemine yapılan bir çağrı, kurtarılabilir koşulu belirten BillingResponseCode
değeri döndürdüğünde çağrıyı yeniden denemeniz gerekir. Diğer durumlarda, koşullar geçici olarak kabul edilmez ve bu nedenle yeniden deneme önerilmez.
Geçici hatalar, hatanın kullanıcılar oturumdayken (ör. kullanıcı bir satın alma sürecindeyken veya hatanın arka planda meydana gelmesi) olup olmadığı (örneğin, onResume
sırasında kullanıcının mevcut satın alma işlemlerini sorgularken) gibi faktörlere bağlı olarak farklı yeniden deneme stratejileri gerektirir.
Aşağıdaki yeniden deneme stratejileri bölümünde, bu farklı stratejilerle ilgili örnekler yer alır. Geri alınabilir BillingResult
yanıtlar bölümünde ise her yanıt kodu için en uygun strateji önerilir.
Bazı hata yanıtları, yanıt koduna ek olarak hata ayıklama ve günlük kaydı için gönderilen mesajları içerir.
Yeniden deneme stratejileri
Basit yeniden deneme
Kullanıcının oturumda olduğu durumlarda hatanın kullanıcı deneyimini mümkün olduğunca az kesintiye uğratması için basit bir yeniden deneme stratejisi uygulamak daha iyidir. Bu durumda, çıkış koşulu olarak maksimum deneme sayısına sahip basit bir yeniden deneme stratejisi kullanmanızı öneririz.
Aşağıdaki örnekte, BillingClient
bağlantısı kurulurken bir hatayı ele almak için basit bir yeniden deneme stratejisi gösterilmektedir:
class BillingClientWrapper(context: Context) : PurchasesUpdatedListener {
// Initialize the BillingClient.
private val billingClient = BillingClient.newBuilder(context)
.setListener(this)
.enablePendingPurchases()
.build()
// Establish a connection to Google Play.
fun startBillingConnection() {
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
Log.d(TAG, "Billing response OK")
// The BillingClient is ready. You can now query Products Purchases.
} else {
Log.e(TAG, billingResult.debugMessage)
retryBillingServiceConnection()
}
}
override fun onBillingServiceDisconnected() {
Log.e(TAG, "GBPL Service disconnected")
retryBillingServiceConnection()
}
})
}
// Billing connection retry logic. This is a simple max retry pattern
private fun retryBillingServiceConnection() {
val maxTries = 3
var tries = 1
var isConnectionEstablished = false
do {
try {
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
isConnectionEstablished = true
Log.d(TAG, "Billing connection retry succeeded.")
} else {
Log.e(
TAG,
"Billing connection retry failed: ${billingResult.debugMessage}"
)
}
}
})
} catch (e: Exception) {
e.message?.let { Log.e(TAG, it) }
tries++
}
} while (tries <= maxTries && !isConnectionEstablished)
}
...
}
Eksponansiyel geri yükleme denemesi
Arka planda gerçekleşen ve kullanıcı oturumdayken kullanıcı deneyimini etkilemeyen Play Faturalandırma Kitaplığı işlemleri için üstel geri yükleme kullanmanızı öneririz.
Örneğin, bu işlem arka planda gerçekleşebileceği için ve bir hata oluşursa onayın gerçek zamanlı olarak gerçekleşmesine gerek olmadığı için yeni satın alma işlemlerini onaylarken bunu uygulamak uygun olur.
private fun acknowledge(purchaseToken: String): BillingResult {
val params = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchaseToken)
.build()
var ackResult = BillingResult()
billingClient.acknowledgePurchase(params) { billingResult ->
ackResult = billingResult
}
return ackResult
}
suspend fun acknowledgePurchase(purchaseToken: String) {
val retryDelayMs = 2000L
val retryFactor = 2
val maxTries = 3
withContext(Dispatchers.IO) {
acknowledge(purchaseToken)
}
AcknowledgePurchaseResponseListener { acknowledgePurchaseResult ->
val playBillingResponseCode =
PlayBillingResponseCode(acknowledgePurchaseResult.responseCode)
when (playBillingResponseCode) {
BillingClient.BillingResponseCode.OK -> {
Log.i(TAG, "Acknowledgement was successful")
}
BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> {
// This is possibly related to a stale Play cache.
// Querying purchases again.
Log.d(TAG, "Acknowledgement failed with ITEM_NOT_OWNED")
billingClient.queryPurchasesAsync(
QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.ProductType.SUBS)
.build()
)
{ billingResult, purchaseList ->
when (billingResult.responseCode) {
BillingClient.BillingResponseCode.OK -> {
purchaseList.forEach { purchase ->
acknowledge(purchase.purchaseToken)
}
}
}
}
}
in setOf(
BillingClient.BillingResponseCode.ERROR,
BillingClient.BillingResponseCode.SERVICE_DISCONNECTED,
BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE,
) -> {
Log.d(
TAG,
"Acknowledgement failed, but can be retried --
Response Code: ${acknowledgePurchaseResult.responseCode} --
Debug Message: ${acknowledgePurchaseResult.debugMessage}"
)
runBlocking {
exponentialRetry(
maxTries = maxTries,
initialDelay = retryDelayMs,
retryFactor = retryFactor
) { acknowledge(purchaseToken) }
}
}
in setOf(
BillingClient.BillingResponseCode.BILLING_UNAVAILABLE,
BillingClient.BillingResponseCode.DEVELOPER_ERROR,
BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED,
) -> {
Log.e(
TAG,
"Acknowledgement failed and cannot be retried --
Response Code: ${acknowledgePurchaseResult.responseCode} --
Debug Message: ${acknowledgePurchaseResult.debugMessage}"
)
throw Exception("Failed to acknowledge the purchase!")
}
}
}
}
private suspend fun <T> exponentialRetry(
maxTries: Int = Int.MAX_VALUE,
initialDelay: Long = Long.MAX_VALUE,
retryFactor: Int = Int.MAX_VALUE,
block: suspend () -> T
): T? {
var currentDelay = initialDelay
var retryAttempt = 1
do {
runCatching {
delay(currentDelay)
block()
}
.onSuccess {
Log.d(TAG, "Retry succeeded")
return@onSuccess;
}
.onFailure { throwable ->
Log.e(
TAG,
"Retry Failed -- Cause: ${throwable.cause} -- Message: ${throwable.message}"
)
}
currentDelay *= retryFactor
retryAttempt++
} while (retryAttempt < maxTries)
return block() // last attempt
}
Geri alınabilir BillingResult yanıtları
NETWORK_ERROR (Hata Kodu 12)
Sorun
Bu hata, cihaz ile Play sistemleri arasındaki ağ bağlantısında bir sorun olduğunu gösterir.
Olası çözüm
Hatayı kurtarmak için hangi işlemin hatayı tetiklediğine bağlı olarak basit yeniden deneme veya üstel geri yükleme yöntemini kullanın.
SERVICE_TIMEOUT (Hata Kodu -3)
Sorun
Bu hata, Google Play'in yanıt verebilmesi için isteğin maksimum zaman aşımına ulaştığını belirtir. Bunun nedeni, örneğin Play Faturalandırma Kitaplığı çağrısı tarafından istenen işlemin yürütülmesinde yaşanan gecikme olabilir.
Olası çözüm
Bu genellikle geçici bir sorundur. Hangi işlemin hata döndürdüğüne bağlı olarak basit veya üstel geri yükleme stratejisi kullanarak isteği yeniden deneyin.
Aşağıdaki SERVICE_DISCONNECTED
'in aksine, Google Play Faturalandırma hizmetiyle bağlantı kesilmez ve yalnızca Play Faturalandırma Kitaplığı'nda denenen işlemi yeniden denemeniz gerekir.
SERVICE_DISCONNECTED (Hata Kodu -1)
Sorun
Bu önemli hata, istemci uygulamasının BillingClient
üzerinden Google Play Store hizmetiyle olan bağlantısının koptuğunu gösterir.
Olası çözüm
Bu hatayı mümkün olduğunca önlemek için Play Faturalandırma Kitaplığı ile arama yapmadan önce BillingClient.isReady()
numaralı telefonu arayarak Google Play Hizmetleri bağlantısını kontrol edin.
SERVICE_DISCONNECTED
'ten kurtarma işlemini denemek için istemci uygulamanızın, BillingClient.startConnection
kullanarak bağlantıyı yeniden kurmayı denemesi gerekir.
SERVICE_TIMEOUT
'te olduğu gibi, hatayı tetikleyen işleme bağlı olarak basit yeniden denemeler veya üstel geri yükleme kullanın.
SERVICE_UNAVAILABLE (Hata Kodu 2)
Önemli Not:
Google Play Faturalandırma Kitaplığı 6.0.0 sürümünden itibaren, SERVICE_UNAVAILABLE
artık ağ sorunları nedeniyle döndürülmemektedir. Faturalandırma hizmeti kullanılamadığında ve kullanımdan kaldırılan SERVICE_TIMEOUT
destek kaydı senaryolarında döndürülür.
Sorun
Bu geçici hata, Google Play Faturalandırma hizmetinin şu anda kullanılamadığını belirtir. Çoğu durumda bu, istemci cihaz ile Google Play Faturalandırma Hizmetleri arasındaki herhangi bir yerde bir ağ bağlantısı sorunu olduğu anlamına gelir.
Olası çözüm
Bu genellikle geçici bir sorundur. Hangi işlemin hata döndürdüğüne bağlı olarak basit veya üstel geri yükleme stratejisi kullanarak isteği yeniden deneyin.
SERVICE_DISCONNECTED
'in aksine, Google Play Faturalandırma hizmetiyle bağlantı koparılmaz ve yapılmaya çalışılan işlemi yeniden denemeniz gerekir.
BILLING_UNAVAILABLE (Hata Kodu 3)
Sorun
Bu hata, satın alma işlemi sırasında bir kullanıcı faturalandırma hatası oluştuğunu belirtir. Buna örnek olarak aşağıdakiler verilebilir:
- Kullanıcının cihazındaki Play Store uygulaması güncel değil.
- Kullanıcı desteklenmeyen bir ülkede.
- Kullanıcı kurumsal bir kullanıcı ve kurumsal yöneticisi kullanıcıların satın alma işlemi yapmasını devre dışı bıraktı.
- Google Play, kullanıcının ödeme yönteminden ödeme alamıyor. Örneğin, kullanıcının kredi kartının süresi dolmuş olabilir.
Olası çözüm
Bu durumda otomatik yeniden denemelerin yardımcı olma olasılığı düşüktür. Bununla birlikte, kullanıcı soruna neden olan durumu ele alırsa manuel yeniden deneme faydalı olabilir. Örneğin, kullanıcı Play Store sürümünü desteklenen bir sürüme güncellerse ilk işlem için manuel olarak yeniden deneme yapılabilir.
Bu hata, kullanıcı oturumda değilken ortaya çıkarsa yeniden denemek mantıklı olmayabilir.
Satın alma akışı nedeniyle bir BILLING_UNAVAILABLE
hatası aldığınızda kullanıcı, satın alma işlemi sırasında Google Play'den geri bildirim almış ve neyin yanlış gittiğinin farkında olabilir. Bu durumda, bir şeylerin yanlış gittiğini belirten bir hata mesajı görüntüleyebilir ve kullanıcıya sorunu çözdükten sonra manuel yeniden deneme seçeneği sunmak için "Tekrar dene" düğmesi sunabilirsiniz.
ERROR (Hata Kodu 6)
Sorun
Bu, Google Play'in kendisinde dahili bir sorun olduğunu gösteren önemli bir hatadır.
Olası çözüm
Bazen ERROR
'e neden olan dahili Google Play sorunları geçicidir ve bunu azaltmak için üstel geri yükleme ile yeniden deneme uygulanabilir. Kullanıcılar oturumdayken basit bir yeniden deneme tercih edilir.
ITEM_ALREADY_OWNED
Sorun
Bu yanıt, Google Play kullanıcısının satın almaya çalıştığı aboneliğe veya tek seferlik satın alınan ürüne zaten sahip olduğunu belirtir. Çoğu durumda, bu geçici bir hata değildir. Bunun nedeni eski bir Google Play önbelleğinden kaynaklanmadığı durumlardır.
Olası çözüm
Nedeni bir önbellek sorunu olmadığında bu hatanın oluşmasını önlemek için kullanıcı zaten sahip olduğu halde satın alınabilecek bir ürün sunmayın. Satın alınabilecek ürünleri gösterirken kullanıcının yararlanma haklarını kontrol ettiğinizden ve kullanıcının satın alabileceği öğelere göre filtrelediğinizden emin olun.
İstemci uygulaması bir önbellek sorunu nedeniyle bu hatayı aldığında hata, Google Play'in önbelleğini Play'in arka ucundan en son verilerle güncellenmesi için tetikler.
Bu durumda, hatadan sonra yeniden denemek söz konusu geçici örneği çözecektir. Kullanıcının ürünü edinip edinmediğini kontrol etmek için ITEM_ALREADY_OWNED
aldıktan sonra BillingClient.queryPurchasesAsync()
yöntemini çağırın. Bu durumda değilse satın alma işlemini tekrar denemek için basit bir yeniden deneme mantığı uygulayın.
ÖĞE_NOT_OWNED
Sorun
Bu satın alma yanıtı, Google Play kullanıcısının değiştirme, onaylama veya tüketmeye çalıştığı aboneliğe veya tek seferlik satın alınan ürüne sahip olmadığını gösterir. Bu, Google Play önbelleğinin eski duruma gelmesinden kaynaklandığı durumlar dışında çoğu durumda geçici bir hata değildir.
Olası çözüm
Hata, bir önbellek sorunu nedeniyle alındığında Google Play'in önbelleğini, Play'in arka ucundan en son verilerle güncellenmesi için tetikler. Hatadan sonra basit bir yeniden deneme stratejisiyle tekrar denemek bu geçici örneği çözecektir. Kullanıcının ürünü edinip edinmediğini kontrol etmek için ITEM_NOT_OWNED
aldıktan sonra BillingClient.queryPurchasesAsync()
numaralı telefonu arayın. Aksi halde, basit yeniden deneme mantığını kullanarak satın alma işlemini tekrar deneyin.
Geri Alınamayan BillingResult yanıtları
Yeniden deneme mantığını kullanarak bu hataları düzeltemezsiniz.
FEATURE_NOT_SUPPORTED
Sorun
Bu tekrarlanamayan hata, muhtemelen eski bir Play Store sürümü nedeniyle kullanıcının cihazında Google Play Faturalandırma özelliğinin desteklenmediğini belirtir.
Örneğin, kullanıcılarınızdan bazılarının cihazları uygulama içi mesajlaşmayı desteklemiyor olabilir.
Olası çözüm
Play Faturalandırma Kitaplığı'nı aramadan önce özellik desteğini kontrol etmek için BillingClient.isFeatureSupported()
adresini kullanın.
when {
billingClient.isReady -> {
if (billingClient.isFeatureSupported(BillingClient.FeatureType.IN_APP_MESSAGING)) {
// use feature
}
}
}
KULLANICI_İPTAL EDİLDİ
Sorun
Kullanıcı, faturalandırma akışı kullanıcı arayüzünü tıkladı.
Olası çözüm
Bu, yalnızca bilgilendirme amaçlıdır ve başarılı bir şekilde başarısız olabilir.
ÖĞE_KULLANILAMIYOR
Sorun
Google Play Faturalandırma aboneliği veya tek seferlik satın alım ürünü bu kullanıcı tarafından satın alınamaz.
Olası çözüm
Uygulamanızın, ürün ayrıntılarını queryProductDetailsAsync
üzerinden önerildiği şekilde yenilediğinden emin olun. Gerekirse ilave yenilemeler uygulamak için ürün kataloğunuzun Play Console yapılandırmasında ne sıklıkta değiştiğini göz önünde bulundurun.
Google Play Faturalandırma'da yalnızca queryProductDetailsAsync
üzerinden doğru bilgileri veren ürünleri satmaya çalışın.
Tutarsızlık olup olmadığını görmek için ürün uygunluğu yapılandırmasını kontrol edin.
Örneğin, yalnızca kullanıcının satın almaya çalıştığı bölge dışındaki bir bölgede kullanılabilen bir ürünü sorguluyor olabilirsiniz.
Bir ürünün satın alınabilmesi için etkin olması, uygulamasının yayınlanmış ve kullanıcının ülkesinde kullanılabilir olması gerekir.
Bazen, özellikle test sırasında, ürün yapılandırmasındaki her şey doğru olsa da kullanıcılar bu hatayı görmeye devam eder. Bunun nedeni, ürün ayrıntılarının Google sunucuları arasında yayılmasında gecikme olabilir. Daha sonra tekrar deneyin.
DEVELOPER_ERROR
Sorun
Bu hata, bir API'yi hatalı şekilde kullandığınızı gösteren önemli bir hatadır.
Örneğin, BillingClient.launchBillingFlow
için yanlış parametreler sağlanması bu hataya neden olabilir.
Olası çözüm
Farklı Play Faturalandırma Kitaplığı çağrılarını doğru şekilde kullandığınızdan emin olun. Ayrıca, hata hakkında daha fazla bilgi için hata ayıklama mesajına göz atın.