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 mevcut teklifleri almak üzere queryProductDetailsAsync
işlevini kullanırsanız yanıt kodu ya OK kodu içerir ve doğru ProductDetails
nesnesi sağlar ya da ProductDetails
nesnesinin sağlanamamasının nedenini belirten farklı bir yanıt içerir.
Tüm yanıt kodları hata değildir. Bu kılavuzda ele alınan yanıtların her biri BillingResponseCode
referans sayfasında ayrıntılı olarak açıklanmaktadır.
Hata belirtmeyen yanıt kodlarına bazı örnekler:
BillingClient.BillingResponseCode.OK
: Aramanın tetiklediği 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ı gösterir.
Yanıt kodu bir hata gösterdiğinde bunun nedeni bazen geçici koşullardan kaynaklanır ve bu nedenle kurtarma işlemi yapılabilir. Play Billing Library yöntemine yapılan bir çağrı, kurtarılabilir bir durumu belirten bir 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ı oturumunda mı (ör. kullanıcı bir satın alma akışındayken) yoksa arka planda mı (ör. onResume
sırasında kullanıcının mevcut satın alma işlemlerini sorgularken) gerçekleştiği gibi faktörlere bağlı olarak farklı yeniden deneme stratejileri gerektirir.
Aşağıdaki yeniden deneme stratejileri bölümünde bu farklı stratejilere dair örnekler verilmiştir. Yeniden 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ı amacıyla mesajlar içerir.
Yeniden deneme stratejileri
Basit yeniden deneme
Kullanıcının oturumunun açık olduğu durumlarda, hatanın kullanıcı deneyimini mümkün olduğunca az etkilemesi için basit bir yeniden deneme stratejisi uygulamak daha iyidir. Bu durumda, çıkış koşulu olarak maksimum deneme sayısı içeren basit bir yeniden deneme stratejisi kullanmanızı öneririz.
Aşağıdaki örnekte, BillingClient
bağlantısı kurulurken oluşan bir hatayı işlemek 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 yeniden denemesi
Arka planda gerçekleşen ve kullanıcı oturumdayken kullanıcı deneyimini etkilemeyen Play Faturalandırma Kitaplığı işlemleri için eksponansiyel geri yükleme kullanmanızı öneririz.
Örneğin, bu işlem arka planda gerçekleşebileceği için ve bir hata oluşursa onaylama işleminin gerçek zamanlı olarak gerçekleşmesi gerekmez. Bu nedenle, yeni satın alma işlemlerini onaylarken bunu uygulamak uygundur.
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
}
Yeniden alınabilen 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
Hataya neden olan işleme bağlı olarak, basit yeniden denemeler veya eksponansiyel geri yükleme kullanarak kurtarma işlemini gerçekleştirin.
SERVICE_TIMEOUT (Hata Kodu -3)
Sorun
Bu hata, Google Play yanıt vermeden önce isteğin maksimum zaman aşımına ulaştığını gösterir. Bunun nedeni, örneğin Play Faturalandırma Kitaplığı çağrısı tarafından istenen işlemin yürütülmesindeki bir 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 bir geri yükleme stratejisi kullanarak isteği yeniden deneyin.
Aşağıdaki SERVICE_DISCONNECTED
durumundan farklı olarak, Google Play Faturalandırma hizmetine olan bağlantı kesilmez. Tek yapmanız gereken, denenen Play Faturalandırma Kitaplığı işlemini tekrar denemektir.
SERVICE_DISCONNECTED (Hata Kodu: -1)
Sorun
Bu önemli hata, istemci uygulamasının BillingClient
üzerinden Google Play Store hizmetine olan bağlantısının kesildiğini gösterir.
Olası çözüm
Bu hatayı mümkün olduğunca önlemek için Play Faturalandırma Kitaplığı ile çağrı yapmadan önce BillingClient.isReady()
adresini arayarak Google Play Hizmetleri'ne olan bağlantıyı her zaman kontrol edin.
SERVICE_DISCONNECTED
ile kurtarma işlemini denemek için istemci uygulamanız BillingClient.startConnection
kullanarak bağlantıyı yeniden kurmayı denemelidir.
SERVICE_TIMEOUT
ile aynı şekilde, hatayı tetikleyen işleme bağlı olarak basit yeniden denemeler veya eksponansiyel geri yükleme kullanın.
SERVICE_UNAVAILABLE (Hata Kodu 2)
Önemli Not:
Google Play Faturalandırma Kitaplığı 6.0.0'dan itibaren SERVICE_UNAVAILABLE
, ağ sorunları için artık döndürülmemektedir. Faturalandırma hizmeti kullanılamadığında ve desteği sonlandı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ı gösterir. Çoğu durumda bu, istemci cihaz ile Google Play Faturalandırma Hizmetleri arasında bir ağ bağlantısı sorunu olduğu anlamına gelir.
Olası çözüm
Bu genellikle geçici bir sorundur. Hatayı döndüren işleme bağlı olarak basit veya eksponansiyel geri yükleme stratejisi kullanarak isteği yeniden deneyin.
SERVICE_DISCONNECTED
durumundan farklı olarak, Google Play Faturalandırma hizmetine olan bağlantı kesilmez ve denenen işlemi tekrarlamanız gerekir.
BILLING_UNAVAILABLE (Hata Kodu 3)
Sorun
Bu hata, satın alma işlemi sırasında kullanıcı faturalandırması hatası oluştuğunu gösterir. Bu durumun yaşanabileceği durumlara örnek olarak aşağıdakiler verilebilir:
- Kullanıcının cihazındaki Play Store uygulaması güncel değildir.
- Kullanıcı desteklenmeyen bir ülkede bulunuyor.
- 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 alamaz. Örneğin, kullanıcının kredi kartının süresi dolmuş olabilir.
Olası çözüm
Otomatik yeniden denemelerin bu durumda yardımcı olması olası değildir. Ancak kullanıcı, soruna neden olan durumu giderirse manuel olarak tekrar denemek faydalı olabilir. Örneğin, kullanıcı Play Store sürümünü desteklenen bir sürüme güncellerse ilk işlemin manuel olarak yeniden denenmesi işe yarayabilir.
Bu hata, kullanıcı oturumda değilken oluşursa yeniden denemek mantıklı olmayabilir.
Satın alma akışı nedeniyle bir BILLING_UNAVAILABLE
hatası aldığınızda, kullanıcı büyük olasılıkla satın alma işlemi sırasında Google Play'den geri bildirim almıştır ve sorunun ne olduğunun farkında olabilir. Bu durumda, bir sorun olduğunu belirten bir hata mesajı gösterebilir ve kullanıcıya sorunu giderdikten sonra manuel olarak tekrar deneme seçeneği sunmak için bir "Tekrar deneyin" düğmesi sunabilirsiniz.
ERROR (Hata Kodu 6)
Sorun
Bu, Google Play'in kendisiyle ilgili dahili bir sorunu gösteren önemli bir hatadır.
Olası çözüm
Bazen ERROR
hatasına yol açan dahili Google Play sorunları geçicidir ve sorunu azaltmak için eksponansiyel 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ğin veya tek seferlik satın alım ürününün zaten sahibi olduğunu gösterir. Çoğu durumda bu geçici bir hata değildir (Google Play'in eski bir önbelleği nedeniyle ortaya çıkan durumlar hariç).
Olası çözüm
Nedeni önbellek sorunu olmadığında bu hatanın oluşmasını önlemek için, kullanıcının zaten sahip olduğu bir ürünü satın almak üzere 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 ürünleri buna göre filtrelediğinizden emin olun.
İstemci uygulaması, önbellek sorunu nedeniyle bu hatayı aldığında Google Play'in önbelleği, Play'in arka ucundan alınan en son verilerle güncellenir.
Hata oluştuktan sonra yeniden denemek, bu durumdaki geçici durumu çözecektir. Kullanıcının ürünü edinip edinmediğini kontrol etmek için ITEM_ALREADY_OWNED
aldıktan sonra BillingClient.queryPurchasesAsync()
numaralı telefonu çağırın. Kullanıcının ürünü edinip edinmediğini kontrol etmek için basit bir yeniden deneme mantığı uygulayarak satın alma işlemini yeniden deneyin.
ITEM_NOT_OWNED
Sorun
Bu satın alma yanıtı, Google Play kullanıcısının değiştirmeye, onaylamaya veya kullanmaya çalıştığı aboneliğin ya da tek seferlik satın alma ürünün sahibi olmadığını gösterir. Bu hata, Google Play'in önbelleği eski bir duruma geldiğinde hariç olmak üzere çoğu durumda geçici değildir.
Olası çözüm
Önbellek sorunu nedeniyle alınan hata, Play'in arka ucundan gelen en son verilerle güncellenmesi için Google Play'in önbelleğini tetikler. Hata oluştuktan sonra basit bir yeniden deneme stratejisiyle yeniden denemek, bu geçici durumu çözecektir. Kullanıcının ürünü alıp almadığını kontrol etmek için ITEM_NOT_OWNED
aldıktan sonra BillingClient.queryPurchasesAsync()
işlevini çağırın. Aksi takdirde, satın alma işlemini yeniden denemek için basit yeniden deneme mantığını kullanın.
Yeniden alınamayan BillingResult yanıtları
Yeniden deneme mantığını kullanarak bu hataları kurtaramazsınız.
FEATURE_NOT_SUPPORTED
Sorun
Bu geri alınamaz hata, muhtemelen eski bir Play Store sürümü nedeniyle Google Play Faturalandırma özelliğinin kullanıcının cihazında desteklenmediğini gösterir.
Örneğin, bazı kullanıcılarınızı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()
uygulamasını kullanın.
when {
billingClient.isReady -> {
if (billingClient.isFeatureSupported(BillingClient.FeatureType.IN_APP_MESSAGING)) {
// use feature
}
}
}
USER_CANCELED
Sorun
Kullanıcı, faturalandırma akışı kullanıcı arayüzünü tıklayarak çıktı.
Olası çözüm
Bu yalnızca bilgilendirme amaçlıdır ve sorunsuz bir şekilde başarısız olabilir.
ÖĞE_YOK
Sorun
Google Play Faturalandırma aboneliği veya tek seferlik satın alma ürünü bu kullanıcı tarafından satın alınamaz.
Olası çözüm
Uygulamanızın, ürün ayrıntılarını önerilen şekilde queryProductDetailsAsync
üzerinden yenilediğinden emin olun. Gerekirse ek 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 döndüren ürünleri satmaya çalışın.
Ürün uygunluğu yapılandırmasını kontrol ederek tutarsızlık olup olmadığını kontrol edin.
Örneğin, yalnızca kullanıcının satın almaya çalıştığı bölge dışında bir bölgede kullanılabilen bir ürün için sorgu yapıyor 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ında her şey doğru olsa bile kullanıcılar bu hatayı görmeye devam eder. Bu durum, ürün ayrıntılarının Google sunucularına dağıtılmasındaki gecikmeyle ilgili olabilir. Daha sonra tekrar deneyin.
GELİŞTİRİCİ_HATASI
Sorun
Bu, bir API'yi yanlış kullandığınızı belirten önemli bir hatadır.
Örneğin, BillingClient.launchBillingFlow
için yanlış parametreler sağlandığında bu hata meydana gelebilir.
Olası çözüm
Farklı Play Faturalandırma Kitaplığı çağrılarını doğru şekilde kullandığınızdan emin olun. Hatayla ilgili daha fazla bilgi için hata ayıklama mesajını da kontrol edin.