Google In-App Billing V3
Hi! Today, I will be trying to make it easier to integrate, or at least understand, Google In-app Billing for consumable products, like coins, gems or whatever you like.
I had to read multiple times the documentation to fully understand how the flow of a purchase should be managed. The difficult part for me was, when to call consumePurchase
.
This post is an attempt to make your integration of the Google In-App Billing easier.
As I understood it, the purchase of a consumable product that can be bought several times has five steps.
- Create the product
Follow this to create the product, take into account thatProduct Type
has to be Managed product. - Purchase the item
This action is very will documented here.
Take into account that after every purchase the product is disabled to be bought, the only way to enable the product again is to call theconsumePurchase
method. But lets not go ahead.
When the checkout flow finishes, you will get information about the purchased item. Using theproductId
,purchaseToken
andorderID
you must validate the purchase. - Validating purchase
There are two ways of validating the purchase, the safest is using a server. Make a request to the server with theproductId
,purchaseToken
andorderID
. Then in the server you must hit to Google at this endpoint. Note: the request requires to be authenticated with thehttps://www.googleapis.com/auth/androidpublisher
scope. - Consume the purchase
I was not sure about if in my case I have to consume the purchase, but like we are talking about consumable products, like coins, we must do it in order that user can buy as many coins as he want.
As I understand we should separte the Managed products in three categories:
a) Consumable items, that can be bought N times, like coins, one after another, despite of not being used.
b) Consumable items, that can be bought N times, like a magic potion, but cannot be bought one after another, it has to be used to be bought again.
c) Non-Consumable items, like a super cool hat for you character.
You have to call theconsumePurchase
method only if you want to enabled again the purchase of a product for that user. And like we are in the case a , we must call this method. - Assign the coins
Finally, ifconsumePurchase
is successfull you must add the coins to the user. To do that you must make a request to the API with theorderId
and thepurchaseToken
in order to add more coins to the user.
Something that I do not mention explicity is the information you need to save in the database. In my case I am saving the purchases and the coins of the user.
In the step three, every time after a validation happens I create a Purchase with the corresponding attributes, orderId
, purchaseToken
, productId
, state
and the raw data returned by https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/products/productId/tokens/token
The state
can be one of the following pending , approved , consumed or cancelled.
Meaning of each state
of a Purchase:
- Consumed , it was paid and consumed
- Approved , the
Purchase
was paid but not consumed. - Pending, not paid nor consumed.
- Cancelled , the
Purchase
was paid but refunded the money.
So after getting the purchase information, I set the state of the purchase according to the purchaseState
and consumptionState
. If the purchaseState == 0
is true then the purchase is approved , so the state of the Purchase
in my DB is approved , if it is different from zero then it’s cancelled. Although if the request fails or the it doesn’t return a 200, the state
of the Purchase
will be pending.
Then, in the step five, after the successfull response of consuming the purchase, the front hits the API with the orderId
and the purchaseToken
. The API verifies that the Purchase
related to the orderId
was not consumed (consumed == false
), then get the purchase again from google. If it is consumed, i.e. the consumptionState == 1
is true, I update the Purchase
‘s state
in the DB as consumed and add the coins to the user.
Well, that’s all! If you have any doubt feel free to ask or write to me!