0
votes

I have a one time purchase in my application. It enables all the features of the application.

When a user purchases the sku on their phone... everything works fine. We see the event returned by the billing client and record the purchase of the premium mode via setting a boolean in a local db. The local Google Play cache is updated properly.

Our problem is when they install on another device. Imagine wanting to use it on a tablet and your phone OR you lost your phone and got another.

We have been using the "query purchases" method of the billing client to validate a purchase. They install the app and I would assume that the purchase history would be added to the local cache at this time.

Generally, it works. But a non-negligible amount of users need to restart their phones several times or wait DAYS from Google to get their @#$% together and actually add the purchase history to their cache.

Their docs say that method only queries the local cache. https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases

The Google Play Developer API lets use query for purchases but we need the purchase token in order to validate anything. If Google Play can't return a purchase token since it has no record of a purchase... what do we do?

How does everyone else deal with this problem?

1

1 Answers

0
votes

queryPurchases relies on the cache on device. So if a user's device doesn't have cache updated in time, you will see this behavior. To solve it you should use queryPurchaseHistoryAsync inside queryPurchases as follows

override fun onBillingSetupFinished(billingResult: BillingResult) {
        when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
                ...
                queryPurchasesAsync()
            }
            ...
        }
    }

fun queryPurchasesAsync() {
        val purchasesResult = HashSet<Purchase>()
        var result = playStoreBillingClient.queryPurchases(BillingClient.SkuType.INAPP)
        if(nullOrEmpty(result)){
            queryPurchaseHistoryAsync(...) // response is returned to onPurchaseHistoryResponse
        }else{
         ... // here you add your existing logic to give users access to products and services 
        }
    }

Aside: since you use the tag google-play-developer-api, does your app have a server? If so you could set the boolean on your server instead of using a local cache and grab the entitlement information from your server. The advantage of this approach is that when your app becomes cross-platform then it doesn't matter if the user made a purchase through Android or the web, they will get access to the premium content by checking with your server.

ref: https://github.com/googlesamples/android-play-billing/tree/master/TrivialDriveKotlin