I have users that have purchased items (SkuType.INAPP
) from my application.
In the previously recommended implementation of in app billing the IabHelper.QueryInventoryFinishedListener
would return an Inventory
that contained no items that they owned.
In the new Play Billing Library I use the following method:
Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
Assuming the response code is successful, I query:
purchasesResult.getPurchasesList()
For this small percentage of users, the list is empty.
As a fail-safe, for negative results above, I continue to try:
mBillingClient.queryPurchaseHistoryAsync(BillingClient.SkuType.INAPP, this);
The onPurchaseHistoryResponse(final int responseCode, final List<Purchase> purchasesList)
successfully details the purchase.
Perplexed by this, I asked the affected users running both implementations to confirm the following:
- They only had one Google account on the device
- The one account received the purchase confirmation email
- This is the only account option in the Google Play Store app
- The Google Play Store app 'order history' detailed the purchase
Taking suggestions from this thread, I asked them to:
- Clear data & cache from the Google Play Store app
- Reboot
- Log back into the Google Play Store
- Open my app again
Despite the above, still, only queryPurchaseHistoryAsync
correctly identified that their account owned items.
Question: Why?
The Billing Library implementation states:
queryPurchaseHistoryAsync() returns the most recent purchase made by the user for each SKU, even if that purchase is expired, canceled, or consumed. Use the queryPurchases() method whenever possible as it uses the local cache, in preference to the queryPurchaseHistoryAsync() method.
I have confirmed in my Order Management, that the purchases are valid and have not been cancelled. I do not consume them, therefore they cannot expire.
Now I have a problem
Given that for these users I can only identify their purchases in the above way, I am forced to implement this fail-safe for all.
Apart from being frustrated by the necessity of having to do this, it wouldn't seem like too much of a problem, until you read again:
queryPurchaseHistoryAsync() returns the most recent purchase made by the user for each SKU, even if that purchase is expired, canceled, or consumed
Therefore, in my standard implementation, I need to check that this purchase remains valid.
Unfortunately, the Purchase object has no such method to check its validity.
So, I probably need to perform an external check.
All when my app starts and my logic decides whether or not to show ads.
Help. Please.