Quando una chiamata di Libreria Fatturazione Play attiva un'azione, la libreria restituisce un
BillingResult
per informare gli sviluppatori del risultato. Ad esempio, se utilizzi
queryProductDetailsAsync
per ottenere le offerte disponibili per l'utente, il codice di risposta contiene un
il codice corretto e restituisce il ProductDetails
corretto
o contiene una risposta diversa che indica il motivo per cui
ProductDetails
non è stato possibile fornire l'oggetto.
Non tutti i codici di risposta sono errori. La BillingResponseCode
pagina di riferimento fornisce una descrizione dettagliata di ciascuna delle risposte
trattati in questa guida.
Ecco alcuni esempi di codici di risposta che non indicano errori:
BillingClient.BillingResponseCode.OK
: l'azione attivata dalla chiamata è stata completata correttamente.BillingClient.BillingResponseCode.USER_CANCELED
: per le azioni che mostrano l'UI del Play Store, viene inviata all'utente, questa risposta indica che l'utente è uscito dai flussi UI senza completare la e il processo di sviluppo.
Quando il codice di risposta indica un errore, la causa a volte è dovuta a
in condizioni transitorie e quindi il recupero è possibile. Quando viene effettuata una chiamata a un Play Store
Il metodo della Libreria Fatturazione restituisce un valore BillingResponseCode
che indica una condizione recuperabile, devi riprovare a effettuare la chiamata. Nella
in altri casi, le condizioni non sono considerate transitorie, pertanto l'esecuzione di un nuovo tentativo
non consigliato.
Gli errori temporanei richiedono strategie diverse per i nuovi tentativi in base a fattori come
se l'errore si verifica quando gli utenti sono nella sessione, ad esempio quando
durante un flusso di acquisto, oppure l'errore si verifica in background,
ad esempio, quando esegui una query sugli acquisti esistenti dell'utente durante il periodo onResume
.
La sezione relativa alle strategie per nuovi tentativi di seguito fornisce esempi di
di queste diverse strategie e la strategia Retriable BillingResult
Sezione Risposte
consiglia la strategia migliore per ciascun codice di risposta.
Oltre al codice di risposta, alcune risposte di errore includono messaggi per per scopi di debug e logging.
Strategie per nuovi tentativi
Nuovo tentativo semplice
Nelle situazioni in cui l'utente è in sessione, è meglio implementare una semplice strategia di ripetizione in modo che l'errore interrompa l'esperienza utente anche possibile. In tal caso, consigliamo una strategia semplice per i nuovi tentativi con un numero massimo di numero di tentativi come condizione di uscita.
L'esempio seguente mostra una semplice strategia di ripetizione per gestire un errore.
quando si stabilisce una BillingClient
connessione:
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)
}
...
}
Nuovo backoff esponenziale
Ti consigliamo di utilizzare il backoff esponenziale per le operazioni di Libreria Fatturazione Play che avvengono in background e non influiscono sull'esperienza utente durante la sessione.
Ad esempio, sarebbe appropriato implementarla quando si riconoscono nuove acquisti perché questa operazione può avvenire in background; la conferma non deve avvenire in tempo reale se si verifica un errore.
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
}
Risposte BillingResult recuperabili
NETWORK_ERROR (codice di errore 12)
Problema
Questo errore indica un problema con la connessione di rete. tra il dispositivo e i sistemi di Google Play.
Possibile risoluzione
Per il ripristino, utilizza semplici nuovi tentativi o il backoff esponenziale, a seconda di azione ha attivato l'errore.
SERVICE_TIMEOUT (codice di errore -3)
Problema
Questo errore indica che la richiesta ha raggiunto il timeout massimo prima Google Play è in grado di rispondere. Ciò potrebbe essere causato, ad esempio, da un ritardo nell'esecuzione dell'azione richiesta dalla chiamata a Libreria Fatturazione Play.
Possibile risoluzione
In genere si tratta di un problema temporaneo. Riprova la richiesta utilizzando un di backoff semplice o esponenziale, a seconda di quale azione ha restituito .
Non mi piace più SERVICE_DISCONNECTED
di seguito, la connessione al servizio Fatturazione Google Play non viene interrotta e
devi solo riprovare a eseguire un'operazione di Libreria Fatturazione Play.
SERVICE_DISCONNECTED (codice di errore -1)
Problema
Questo errore irreversibile indica che la connessione dell'app client a Google Play
Servizio di negozio tramite BillingClient
è stato interrotto.
Possibile risoluzione
Per evitare il più possibile questo errore, controlla sempre la connessione a Google
Play Services prima di effettuare chiamate con la Libreria Fatturazione Play chiamando
BillingClient.isReady()
Per tentare il recupero da SERVICE_DISCONNECTED
, l'app client dovrebbe provare a ristabilire la connessione utilizzando
BillingClient.startConnection
.
Proprio come in SERVICE_TIMEOUT
, utilizza semplici nuovi tentativi o il backoff esponenziale, a seconda dell'azione attivata
l'errore.
SERVICE_UNAVAILABLE (codice di errore 2)
Nota importante:
A partire dalla Libreria Fatturazione Google Play 6.0.0, SERVICE_UNAVAILABLE
non è
più a lungo per i problemi di rete. Viene restituito quando il servizio di fatturazione
non disponibile e gli scenari SERVICE_TIMEOUT
deprecati.
Problema
Questo errore temporaneo indica che il servizio Fatturazione Google Play è attualmente non disponibile. Nella maggior parte dei casi, significa che c'è un problema di connessione di rete in qualsiasi punto tra il dispositivo client e i servizi di fatturazione di Google Play.
Possibile risoluzione
In genere si tratta di un problema temporaneo. Riprova la richiesta utilizzando un di backoff semplice o esponenziale, a seconda di quale azione ha restituito .
Non mi piace più SERVICE_DISCONNECTED
, la connessione al servizio Fatturazione Google Play non viene interrotta e devi
di riprovare a qualsiasi operazione.
BILLING_UNAVAILABLE (codice di errore 3)
Problema
Questo errore indica che si è verificato un errore di fatturazione dell'utente durante procedura di acquisto. Ecco alcuni esempi di casi in cui ciò può verificarsi:
- L'app Play Store sul dispositivo dell'utente non è aggiornata.
- L'utente si trova in un paese non supportato.
- L'utente è un utente aziendale e il suo amministratore aziendale ha disattivato gli utenti dagli acquisti.
- Google Play non è in grado di addebitare l'importo sul metodo di pagamento dell'utente. Ad esempio, la carta di credito dell'utente potrebbe essere scaduta.
Possibile risoluzione
È improbabile che i nuovi tentativi automatici siano utili in questo caso. Tuttavia, un nuovo tentativo manuale se l'utente risolve la condizione che ha causato il problema. Ad esempio, se l'utente aggiorna la propria versione del Play Store a una versione supportata, dopodiché un nuovo tentativo dell'operazione iniziale potrebbe funzionare.
Se questo errore si verifica quando l'utente non è nella sessione, il nuovo tentativo potrebbe non rendere
senso.
Quando ricevi un BILLING_UNAVAILABLE
a causa del flusso di acquisto, è molto probabile che l'utente abbia ricevuto
feedback di Google Play durante la procedura di acquisto e potresti essere a conoscenza di cosa
è andato storto. In questo caso, potresti visualizzare un messaggio di errore che specifica qualcosa
si è verificato un problema e offrire un pulsante "Riprova" per dare all'utente la possibilità di
un nuovo tentativo manuale dopo aver risolto il problema.
ERRORE (codice di errore 6)
Problema
Si tratta di un errore irreversibile che indica un problema interno con Google Play. per trovare le regole.
Possibile risoluzione
A volte problemi interni di Google Play che portano a ERROR
.
sono temporanei ed è possibile implementare un nuovo tentativo con un backoff esponenziale
mitigazione dei rischi. Quando gli utenti sono nella sessione, è preferibile un semplice nuovo tentativo.
ITEM_ALREADY_OWNED
Problema
Questa risposta indica che l'utente di Google Play è già proprietario abbonamento o acquisto una tantum di un prodotto che stanno tentando di acquistare. Nella maggior parte dei casi, non si tratta di un errore temporaneo, tranne quando è causato da un la cache di Google Play non aggiornata.
Possibile risoluzione
Per evitare che questo errore si verifichi quando la causa non è un problema di cache, non offrire una
il prodotto può essere acquistato quando l'utente lo possiede già. Assicurati di controllare
i diritti dell'utente quando mostri i prodotti disponibili per l'acquisto; e
filtrando ciò che l'utente può acquistare di conseguenza.
Quando l'app client riceve questo errore a causa di un problema di cache, l'errore si attiva
Cache di Google Play per aggiornarsi con gli ultimi dati provenienti dal backend di Google Play.
Riprovare dopo l'errore dovrebbe risolvere questa specifica istanza temporanea
per verificare se è così. Chiama il numero BillingClient.queryPurchasesAsync()
dopo aver ricevuto un ITEM_ALREADY_OWNED
per verificare se l'utente ha acquisito il prodotto e in caso contrario
implementare una logica di nuovo tentativo per ritentare l'acquisto.
ITEM_NOT_OWNED
Problema
Questa risposta all'acquisto indica che l'utente di Google Play non è proprietario del abbonamento o acquisto una tantum di un prodotto che l'utente stia cercando di sostituire, riconoscere o utilizzare. Nella maggior parte dei casi non si tratta di un errore temporaneo, tranne quando è causato da Google La cache di Play sta passando a uno stato inattivo.
Possibile risoluzione
Quando l'errore viene ricevuto a causa di un problema di cache, l'errore attiva Google
Cache di Play per aggiornarsi con gli ultimi dati provenienti dal backend di Google Play. Nuovo tentativo in corso...
con una semplice strategia di ripetizione, dopo che l'errore dovrebbe risolvere
un'istanza temporanea. Chiama il numero BillingClient.queryPurchasesAsync()
dopo aver ricevuto un ITEM_NOT_OWNED
per verificare se l'utente ha
acquisito il prodotto. In caso contrario, utilizza la logica dei nuovi tentativi per ritentare la
acquisto.
Risposte BillingResult non recuperabili
Non puoi ripristinare questi errori utilizzando la logica per i nuovi tentativi.
FEATURE_NOT_SUPPORTED
Problema
Questo errore non recuperabile indica che la funzionalità Fatturazione Google Play non è supportata sul dispositivo dell'utente, probabilmente a causa di una versione precedente del Play Store.
Ad esempio, alcuni dei tuoi utenti potrebbero I dispositivi non supportano la messaggistica in-app.
Possibile mitigazione
Utilizza BillingClient.isFeatureSupported()
per verificare il supporto delle funzionalità prima di effettuare la chiamata al servizio di fatturazione di Play
Raccolta.
when {
billingClient.isReady -> {
if (billingClient.isFeatureSupported(BillingClient.FeatureType.IN_APP_MESSAGING)) {
// use feature
}
}
}
UTENTE_ANNULLATO
Problema
L'utente ha fatto clic per uscire dall'interfaccia utente del flusso di fatturazione.
Possibile risoluzione
Si tratta solo di informazioni e può non funzionare correttamente.
ITEM_UNAVAILABLE
Problema
Il prodotto dell'abbonamento Fatturazione Google Play o dell'acquisto una tantum non è disponibile per l'acquisto per questo utente.
Possibile mitigazione
Assicurati che la tua app aggiorni i dettagli del prodotto tramite queryProductDetailsAsync
come consigliato. Prendi in considerazione la frequenza
modifiche al catalogo dei prodotti nella configurazione di Play Console per implementare
aggiornamenti aggiuntivi, se necessario.
Tenta di vendere solo prodotti su Fatturazione Google Play che restituiscono il diritto
informazioni tramite queryProductDetailsAsync
.
Controlla la configurazione dell'idoneità dei prodotti per verificare la presenza di eventuali incoerenze.
Ad esempio, potresti eseguire una query per un prodotto disponibile solo per
regione diversa da quella che l'utente sta cercando di acquistare.
Per essere acquistabile, un prodotto deve essere attivo e la relativa app deve essere
e la relativa app deve essere disponibile nel paese dell'utente.
A volte, in particolare durante i test, tutto è corretto nel prodotto configurazione, ma gli utenti continuano a visualizzare questo errore. Ciò potrebbe essere dovuto a ritardo nella propagazione dei dettagli del prodotto tra i server di Google. Riprova in un secondo momento.
ERRORE_SVILUPPATORI
Problema
Questo è un errore irreversibile che indica che stai utilizzando in modo improprio un'API.
Ad esempio, fornire parametri errati a BillingClient.launchBillingFlow
può
causare questo errore.
Possibile risoluzione
Assicurati di utilizzare correttamente la Libreria Fatturazione Play diversa chiamate. Inoltre, controlla il messaggio di debug per maggiori informazioni sull'errore.