Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Google BillingClient how to get unconsumed items?

Question: using the Google Play BillingClient 1.1 how can I get only unconsumed purchases?

Background:

In our Android app we wanted to change the "old" billing libraries (using the V.3 IabHelper.java class from the examples) using the new

com.android.billingclient:billing:1.1

The idea was to use

BillingClient.queryPurchases(BillingClient.SkuType.INAPP)

in order to get a "history" of all purchases the user made. This is what the API tells (https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#queryPurchases(java.lang.String)) and it works fine. In the old version one would only get the unconsumed items which is useless for something like a "purchase history". However if I want to know whether there are unconsumed items, I can no longer get that information.

Same for queryPurchaseHistoryAsync().

The Purchase objects don't seem to contain any information about their consumption. How can I get only not-consumed items (or at least filter them)?

Please note, I'm aware that the purchases eventually have to be managed on our server side. However until this is successful, it would be good to know which item was "redeemed" (consumed) already or not. So I can't rely on our backend only.

---- EDIT ----

The Purchase objects (JSON) coming from the query all look like this:

{
  "orderId": "[Id]",
  "packageName": "[just the app's package]",
  "productId": "[the SKU name]",
  "purchaseTime": 1531224460215,
  "purchaseState": 0,
  "purchaseToken": "[a purchase token]"
}

So nothing that appears to be a consumption state.

---- EDIT 2 ----

I found a (bad) solution for it. When trying to consume a purchase, google tells me with it's return code whether it was already consumed or not. But that is not a solution for us since we wanted to keep it "marked as unconsumed" until it's redeemed on our server.

like image 282
Tobias Reich Avatar asked Jul 10 '18 12:07

Tobias Reich


2 Answers

Okay, I guess I found the answer. In case you have the same issue as I do, here is the solution:

The billingClient has two method calls.

  • The first one is

billingClient.queryPurchaseHistoryAsync().

This async call (internet required) is fetching a history of the last 11 purchases the user has made. The newest one is the first one (element 0 of the list). However this shows all purchases - no matter whether they are consumed or not. So if you want to know their state you can't do this here. If you have a backend system (and a working network connection) you may send them all to the server and validate them. Since our app is "offline first" this was not always possible for our users.

You may check this however when trying to purchase them again. A call of billingClient.launchBillingFlow() would return responseCode ITEM_ALREADY_OWNED (7) but you don't want to wait for the user trying to purchase it again. Especially since we wanted to guarantee the purchase already even without internet connection.

  • The solution is the other method.

The BillingClient offers:

billingClient.queryPurchases(BillingClient.SkuType.INAPP)

This returns a cached list of previous purchases. The API states this as

Get purchases details for all the items bought within your app.

However this seems to return a list of only the non consumed items. This way you can get non consumed items from the list of all (recent) purchases. Note however that this is cached by the playstore. If you need exact data you will still have to establish a connection with the google server (also when the playstore cache is cleared etc.).

This gives the option of a history of all purchases with additional information about non consumed items, which makes your app (partially) offline usable.

At least this is the best approach I was coming up with but it seems to work. Please let me know if you have any corrections or better solutions!!!

like image 94
Tobias Reich Avatar answered Sep 29 '22 07:09

Tobias Reich


The official documentation says that it is recommended to check purchases with the https://developers.google.com/android-publisher/api-ref/purchases/products/get request. In the response from JSON, there is a consumptionState field that shows whether the purchase is consumed.

{
  "kind": "androidpublisher#productPurchase",
  "purchaseTimeMillis": long,
  "purchaseState": integer,
  "consumptionState": integer,
  "developerPayload": string,
  "orderId": string,
  "purchaseType": integer
}

Learn more https://developers.google.com/android-publisher/api-ref/purchases/products#resource. In this way, you can receive a purchase using the queryPurchaseHistoryAsync network query and check it as described above. But this way is not easy, because the request requires authorization, which needs to be configured https://developers.google.com/android-publisher/authorization

like image 37
ni032mas Avatar answered Sep 29 '22 06:09

ni032mas