5

The Google Play Billing library documentation on acknowledging purchases states that:

you must acknowledge all purchases that have a SUCCESS state received through the Google Play Billing Library as soon as possible after granting entitlement to the user.

So your app should first give the user what he bought, and then acknowledge the purchase. This is also what their example code implies:

fun handlePurchase() {
    if (purchase.purchaseState === PurchaseState.PURCHASED) {
        // Grant entitlement to the user.
        ...
        // Acknowledge the purchase if it hasn't already been acknowledged.
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
                    .build()
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener)
        }
    }
}

I am currently developing an Android app where I give users access to their bought content after the acknoweldgement returned with an OK status (so the other way around):

private fun acknowledgePurchase(purchase: Purchase) {
    val params = AcknowledgePurchaseParams.newBuilder()
        .setPurchaseToken(purchase.purchaseToken)
        .build()

    billingClient.acknowledgePurchase(params) { billingResult ->
        when (billingResult.responseCode) {
            BillingResponseCode.OK -> loadPurchase(purchase.sku)
            else -> { ... }
        }
    }
}

because the documentation states that:

... you must acknowledge all purchases within three days. Failure to properly acknowledge purchases results in those purchases being refunded.

If this happens, and a user gets refunded, the user's entitlment to the product should also be withdrawn. But in my case, making a purchase means loading data, storing stuff in the database, and so on, and I do not have, nor do I want to have, code in place to revert this. Therefore I provide the user with the product only after a successful acknowledge.

Hence my question: is it okay to wait with granting entitlement to an in-app purchase until after the purchase has been acknowledged? Or is there some catch I am missing here? I assume that the documentation specifies this order for a reason, but they do not elaborate on it.

Bastiaan van den Berg
  • 1,585
  • 1
  • 14
  • 20
  • 1
    Q: What language are you using? Just curious... In answer to your question, my understanding is: 1) If somebody tries to "buy" something, you may 2) accept or decline "entitlement". Either way, you should 3) Acknowledge "as soon as possible". 4) If you DON'T acknowledge acceptance within 3 days, the policy is for Google to assume you "declined". – paulsm4 Nov 16 '19 at 20:01
  • I'm voting to close this question as off-topic because it's about Google purchase logic, not programming. – Reg Edit Nov 16 '19 at 20:11
  • @paulsm4 A: The language is Kotlin, in my opinion a lot nicer to work with than working with Java, so highly recomended :). – Bastiaan van den Berg Nov 17 '19 at 12:12
  • @paulsm4 My situation is when the purchase was successful, at which point I can't think of any reason to decline. I guess that Google wants an acknowledgment to know if the user realy got what he paid for, so that he can be refunded if this failed. At the same time, I want to know if the acknowledgement went well before actually giving the user the product, to prevent having to revert a purchase if acknowledgement failed (due to failing internet connection?, or maybe malicious use?). The question is if I can take this approach without some unexpected side effect. – Bastiaan van den Berg Nov 17 '19 at 12:14
  • Just curious to know, how long it takes for receiving the acknowledgment callback after we call the client.acknowledgePurchase() method? I am in a similar dilemma as the OP so searching for a solution. – coderGtm Nov 07 '22 at 11:44

1 Answers1

3

After some more research I noticed that the Trivial Drive sample app takes the exact same approach as I do. The following is a snippet of their code:

private fun acknowledgeNonConsumablePurchasesAsync(nonConsumables: List<Purchase>) {
    nonConsumables.forEach { purchase ->
        val params = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase
                .purchaseToken).build()
        playStoreBillingClient.acknowledgePurchase(params) { billingResult ->
            when (billingResult.responseCode) {
                BillingClient.BillingResponseCode.OK -> {
                    disburseNonConsumableEntitlement(purchase)
                }
                else -> Log.d(LOG_TAG, "acknowledgeNonConsumablePurchasesAsync response is ${billingResult.debugMessage}")
            }
        }

    }
}

showing that entitilement is granted in the acknowledge callback function, if the response was OK. Exactly the same as the code in my question.

So I guess the answer to the question is: yes, it is okay to grant entitlement after successful acknowledgement.

Bastiaan van den Berg
  • 1,585
  • 1
  • 14
  • 20