This document explains how to add Google Play Billing into your app using the Google Play Library. Specifically, this document covers how to add Google Play Billing functionality that's common to all in-app product types: one-time products, rewarded products, and subscriptions. To learn how to add in-app product-specific functionality to your app, read the documents listed at the end of this page.
Before reading this page, do the following:
- Read the Google Play Billing Overview to familiarize yourself with important concepts and terms.
- Configure your in-app products using the Google Play Console:
- To configure a one-time product, see Create a managed product.
- To configure a rewarded product, see Create a rewarded product.
- To configure a subscription, see Create a subscription.
About the code snippets
This guide uses code snippets from the TrivialDrive v2 sample app. This sample shows how to use Play Billing Library to implement in-app products for a driving game. The app demonstrates how to list the available products, start a purchase flow, record product consumption, and everything else you need to know to add Google Play Billing into your app. Figure 1 shows the opening screen of this app:
Steps to add Google Play Billing to an app
Follow the steps in the sections below to add Google Play Billing to your app.
Update your app's dependencies
Add the following line to the dependencies section of the build.gradle file
for your app:
dependencies {
...
implementation 'com.android.billingclient:billing:2.0.1'
}
To ensure you are using the current version of the Google Play Billing Library, see the Google Play Billing Library release notes.
Connect to Google Play
Before you can make Google Play Billing requests, you must first establish a connection to Google Play by doing the following:
Call
newBuilder()to create an instance ofBillingClientYou must also callsetListener(), passing a reference to aPurchasesUpdatedListenerto receive updates on purchases initiated by your app, as well as those initiated by the Google Play Store.Establish a connection to Google Play. The setup process is asynchronous, and you must implement a
BillingClientStateListenerto receive a callback once the setup of the client is complete and it’s ready to make further requests.Override the
onBillingServiceDisconnected()callback method and implement your own retry policy to handle lost connections to Google Play in the event the client loses connection. For example, theBillingClientmay lose its connection if the Google Play Store service is updating in the background. TheBillingClientmust call thestartConnection()method to restart the connection before making further requests.
The following code sample demonstrates how to start a connection and test that it's ready to use:
Kotlin
lateinit private var billingClient: BillingClient
...
billingClient = BillingClient.newBuilder(context).setListener(this).build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingResponse.OK) {
// The BillingClient is ready. You can query purchases here.
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
Java
private BillingClient billingClient;
...
billingClient = BillingClient.newBuilder(activity).setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingResponse.OK) {
// The BillingClient is ready. You can query purchases here.
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
Query for in-app product details
The unique product IDs you created when configuring your in-app products are
used to asynchronously query Google Play for in-app product details. To query
Google Play for in-app product details, call
querySkuDetailsAsync().
When calling this method, pass an instance of
SkuDetailsParams
that specifies a list of product ID strings and a SkuType. The SkuType can
be either SkuType.INAPP for one-time products or rewarded products or
SkuType.SUBS for subscriptions.
To handle the result of the asynchronous operation, you must also specify a
listener which implements the
SkuDetailsResponseListener
interface. You can then override
onSkuDetailsResponse()
which notifies the listener when the query finishes, as illustrated by the
following sample code:
Kotlin
val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("gas")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(SkuType.INAPP)
billingClient.querySkuDetailsAsync(params.build(), { billingResult, skuDetailsList ->
// Process the result.
})
Java
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
Your app should maintain its own product ID list either by bundling that list with your APK or querying it from your own secure backend server.
Call
BillingResult#getResponseCode()
to retrieve the response code. If the request is successful, the response code
is BillingResponse.OK. For a list of other possible response codes from Google
Play, see
BillingClient.BillingResponse.
If an error occurs, you can use
BillingResult#getDebugMessage()
to view the associated error message.
The Google Play Billing Library stores the query results in a List of
SkuDetails
objects. You can then call a variety of methods on each of the SkuDetails
objects in the list to view relevant information about an in-app product, such
as its price or description. To view the available product detail information,
see the list of methods in the SkuDetails class.
The following example shows how to retrieve the prices for in-app products using
the SkuDetails object returned by the previous code snippet:
Kotlin
if (result.responseCode == BillingResponse.OK && skuDetailsList != null) {
for (skuDetails in skuDetailsList) {
val sku = skuDetails.sku
val price = skuDetails.price
if ("premium_upgrade" == sku) {
premiumUpgradePrice = price
} else if ("gas" == sku) {
gasPrice = price
}
}
}
Java
if (result.getResponseCode() == BillingResponse.OK && skuDetailsList != null) {
for (SkuDetails skuDetails : skuDetailsList) {
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if ("premium_upgrade".equals(sku)) {
premiumUpgradePrice = price;
} else if ("gas".equals(sku)) {
gasPrice = price;
}
}
}
Retrieving a product’s price is an important step before a user can purchase a product because the price is different for each user based on their country of origin. The Trivial Drive app displays all the in-app products as a list as shown in Figure 2:
Consistent offers
When offering a discounted SKU, Google Play also returns the original price of
the SKU so that you can show users that they are receiving a discount. We
recommend that you use both getPrice() to show the discounted price to the
user and getOriginalPrice() to show the original price of the item.
SkuDetails contains two
methods for retrieving the original SKU price:
getOriginalPriceAmountMicros()- returns the unformatted original price of the SKU before discount.getOriginalPrice()- returns the original price with additional currency formatting.
Enable the purchase of an in-app product
Some Android phones might have an older version of the Google Play Store app
that doesn't support certain products types, such as subscriptions. Therefore,
before your app enters the billing flow, call
isFeatureSupported()
to check that the device supports the products you want to sell. For a list of
product types, see
BillingClient.FeatureType.
To start a purchase request from your app, call the
launchBillingFlow() method
from the UI thread. Pass a reference to a
BillingFlowParams
object containing the relevant data to complete the purchase, such as the
product ID (skuId) of the item and product type (SkuType.INAPP for a
one-time product or rewarded product, or SkuType.SUBS for a subscription). To
get an instance of
BillingFlowParams
, use the
BillingFlowParams.Builder
class:
Kotlin
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build()
val responseCode = billingClient.launchBillingFlow(activity, flowParams)
Java
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
int responseCode = billingClient.launchBillingFlow(flowParams);
When you call the
launchBillingFlow()
method, the system displays the Google Play purchase screen. Figure 3 shows a
purchase screen for a one-time product:
Figure 4 shows a purchase screen for a subscription:
The
launchBillingFlow()
method returns one of several response codes listed in
BillingClient.BillingResponse.
Google Play calls the
onPurchasesUpdated()
method to deliver the result of the purchase operation to a listener that
implements the
PurchasesUpdatedListener interface. The listener is specified using the
setListener() method as demonstrated earlier
in the Connect to Google Play section.
You must implement the
onPurchasesUpdated()
method to handle possible response codes. The following code snippet show how to
override the
onPurchasesUpdated()
method:
Kotlin
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
if (billingResult.responseCode == BillingResponse.OK && purchases != null) {
for (purchase in purchases) {
handlePurchase(purchase)
}
} else if (billingResult.responseCode == BillingResponse.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
Java
@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingResponse.OK
&& purchases != null) {
for (Purchase purchase : purchases) {
handlePurchase(purchase);
}
} else if (billingResult.getResponseCode() == BillingResponse.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
Successful purchases generate a Google Play success screen similar to the screen in Figure 5.
Successful purchases also generate a purchase token, which is a unique identifier representing the user and the product ID for the in-app product they purchased. Your apps can store the purchase token locally or, ideally, pass it to your secure backend server where it can be used to verify the purchase and protect against fraud. The purchase token is unique for every one-time product purchase and rewarded product. However, because subscriptions are purchased once and automatically renewed on a regular billing period, the purchase token for subscriptions stays the same for each billing period.
The user is also emailed a receipt of the transaction containing an order ID or a unique ID of the transaction. Users receive an email with a unique order ID for each one-time product purchase, and also for the initial subscription purchase and subsequent recurring automatic renewals. You can use the order ID to manage refunds in the Google Play Console. For further details, refer to to View and refund your app’s orders and subscriptions.
Acknowledge a purchase
If you use the Google Play Billing Library version 2.0 or newer, you must acknowledge all purchases within three days. Failure to properly acknowledge purchases results in those purchases being refunded.
Google Play supports purchasing products from inside of your app (in-app) or
outside of your app (out-of-app). In order for Google Play to ensure a
consistent purchase experience regardless of where the user purchases your
product, 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. If you do not acknowledge a purchase within
three days, the user automatically receives a refund, and Google Play revokes
the purchase. For pending transactions, the three-day window does
not apply when the purchase is in a PENDING state. Instead, it starts when the
purchase has moved to the SUCCESS state.
You can acknowledge a purchase by using one of the following methods:
- For consumable products, use
consumeAsync(), found in the client API. - For products that aren't consumed, use
acknowledgePurchase(), found in the client API. - A new
acknowledge()method is also available in the server API.
For subscriptions, you must acknowledge any purchase that contains a new purchase token. This means that all initial purchases, plan changes, and re-signups need to be acknowledged, but you do not need to acknowledge subsequent renewals. To determine if a purchase needs acknowledgment, you can check the acknowledgement field in the purchase.
The Purchase object includes an
isAcknowledged()
method that indicates whether a purchase has been acknowledged. In addition, the
server-side API includes acknowledgement boolean values for
Product.purchases.get() and Product.subscriptions.get(). Before
acknowledging a purchase, use these methods to determine whether the purchase
has already been acknowledged.
This example shows how to acknowledge a subscription purchase:
Kotlin
val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...
fun handlePurchase() {
if (purchase.state === 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)
}
}
}
Java
BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...
void handlePurchase(Purchase purchase) {
if (purchase.getState() == PurchaseState.PURCHASED) {
// Grant entitlement to the user.
...
// Acknowledge the purchase if it hasn't already been acknowledged.
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
}
}
Test acknowledging purchase with license testers
For purchases made by license testers, the acknowledgement window is shorter. Instead of three days, purchases are refunded and revoked if they are not acknowledged within five minutes.
Support pending transactions
When implementing a Google Play Billing solution, you must support purchases where additional action is required before granting entitlement. For example, a user might choose to purchase your in-app product at a physical store using cash. This means that the transaction is completed outside of your app. In this scenario, you should grant entitlement only after the user has completed the transaction.
To enable pending purchases, call
enablePendingPurchases()
when initializing your app. Note that if you do not call
enablePendingPurchases(), you cannot instantiate the Google Play Billing
Library.
Use the Purchase.getState()
method to determine whether the purchase state is PURCHASED or PENDING. Note
that you should grant entitlement only when the state is PURCHASED. You can
check for status changes by doing the following:
- When starting your app, call
BillingClient.queryPurchases()to retrieve the list of unconsumed products associated with the user, and then callgetState()on each returnedPurchaseobject. - Implement the
onPurchasesUpdated()method to respond to changes toPurchaseobjects.
Here's an example that demonstrates how you might handle pending transactions:
Kotlin
fun handlePurchase(purchase: Purchase) {
if (purchase.state == PurchaseState.PURCHASED) {
// Grant the item to the user, and then acknowledge the purchase
} else if (purchase.state == PurchaseState.PENDING) {
// Here you can confirm to the user that they've started the pending
// purchase, and to complete it, they should follow instructions that
// are given to them. You can also choose to remind the user in the
// future to complete the purchase if you detect that it is still
// pending.
}
}
Java
void handlePurchase(Purchase purchase) {
if (purchase.getState() == PurchaseState.PURCHASED) {
// Acknowledge purchase and grant the item to the user
} else if (purchase.getState() == PurchaseState.PENDING) {
// Here you can confirm to the user that they've started the pending
// purchase, and to complete it, they should follow instructions that
// are given to them. You can also choose to remind the user in the
// future to complete the purchase if you detect that it is still
// pending.
}
}
Test pending transactions with license testers
Pending transactions can be tested using license testers. In addition to two test credit cards, license testers have access to two test instruments for delayed forms of payment which automatically complete or cancel after a couple of minutes.
While testing your application, you should verify that your application does not grant entitlement or acknowledge the purchase immediately after purchasing when using either of these two instruments. When purchasing using the test instrument that automatically completes, you should verify that your application grants entitlement and acknowledges the purchase once the purchase completes.
When purchasing using the test instrument that automatically cancels, you should verify that your application does not grant entitlement, since there is no successful purchase.
Attach a developer payload
You can attach an arbitrary string, or developer payload, to purchases. Note, however, that you can attach a developer payload only when the purchase is acknowledged or consumed. This is unlike developer payload in AIDL, where the payload could be specified when launching the purchase flow.
For consumable products,
consumeAsync()
takes a ConsumeParams
object that includes a developer payload field, as shown in the following
example:
Kotlin
val client: BillingClient = ...
val listener: ConsumeResponseListener = ...
val consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build()
client.consumeAsync(consumeParams, listener)
Java
BillingClient client = ...
ConsumeResponseListener listener = ...
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.consumeAsync(consumeParams, listener);
For products that aren't consumed,
acknowledgePurchase()
takes an
AcknowledgePurchaseParams
object that includes a developer payload field, as shown in the following
example:
Kotlin
val client: BillingClient = ...
val listener: AcknowledgePurchaseResponseListener = ...
val acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build()
client.acknowledgePurchase(acknowledgePurchaseParams, listener)
Java
BillingClient client = ...
AcknowledgePurchaseResponseListener listener = ...
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(/* token */)
.setDeveloperPayload(/* payload */)
.build();
client.acknowledgePurchase(acknowledgePurchaseParams, listener);
To access a developer payload, call
getDeveloperPayload()
on the corresponding Purchase object.
You can only consume or acknowledge a purchase in PURCHASED purchase state.
Verify a purchase
You should always verify that purchase state is PURCHASED and other purchase
details that your app receives in
onPurchasesUpdated()
before providing the user access to what they have purchased.
Verify a purchase on a server
By implementing purchase verification logic on a server, you can protect your app from attackers who try to reverse-engineer your APK file and disable its verification logic. To verify purchase details on a secure backend server, complete the following steps:
From your app, send the purchase token and user account credential to your secure backend server. The secure backend server should associate the purchase with the user after verification has succeeded.
After you get the token from the app:
Use the Subscriptions and Purchases portion of the Google Play Developer API to perform a GET request to retrieve the purchase details from Google Play (
Purchases.productsfor a one-time product purchase or rewarded purchase, orPurchases.subscriptionsfor a subscription). The GET request includes the app package name, product ID, and a token (purchase token).Google Play returns the purchase details.
The secure backend server verifies that the order ID is a unique value that doesn’t represent a previous purchase.
The secure backend server uses the user account credential received in step 1 to associate the purchase token with the user of the app instance where the purchase was made.
(optional) If you are validating a subscription and the subscription is being upgraded, downgraded, or the user has re-subscribed before the subscription has lapsed, check the
linkedPurchaseTokenfield. ThelinkedPurchaseTokenfield in aPurchases.subscriptionsresource contains the token of the previous, or “originating” purchase. For more aboutlinkedPurchaseToken, seePurchases.subscriptions).The in-app product is made available to the user.
Verify a purchase on a device
If you cannot run your own server, you can still validate purchase details within your Android app.
To help ensure the integrity of the transaction information that is sent to your
application, Google Play signs the JSON string that contains the response data
for a purchase. Google Play uses the private key that is associated with your
application in the Play Console to create this signature. The Play Console
generates an RSA key pair for each application. You get this response JSON
using the getOriginalJson()
method within the
Purchase
class.
The Base64-encoded RSA public key that is generated by Google Play is in binary encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public key that is used with Google Play licensing.
When your application receives this signed response, you can use the public key portion of your RSA key pair to verify the signature. By performing signature verification, you can detect any responses that have been tampered with or that have been spoofed.
You should obfuscate your Google Play public key and Google Play Billing code so it's difficult for an attacker to reverse-engineer security protocols and other application components. At a minimum, we recommend that you run an obfuscation tool like Proguard on your code. To obfuscate your code using Proguard, you must add the following line to your Proguard configuration file:
-keep class com.android.vending.billing.**
After obfuscating your Google Play public key and Google Play Billing code, you're ready to have your app validate purchase details. When your app verifies a signature, ensure that your app's key signed the JSON data contained in that signature.
Keep purchases up-to-date
It's possible to lose track of which purchases a user has made. Here are two scenarios where your app could lose track of purchases and where querying for purchases is important.
Handling server outages
- A user buys a one-time product, such as extra gas for a driving game.
- The app sends the purchase token to the secure backend server for verification.
- The server is temporarily down.
- The app recognizes that the server is down and notifies the user that there’s a problem with the purchase.
- The Android app retries sending the purchase token to the secure backend server, and finishes the purchase as soon as the server is restored.
- The app releases the content.
Handling multiple devices
- A user buys a subscription on their Android phone.
- The app sends the purchase token to the secure backend server for verification.
- The server verifies the purchase token.
- The app releases the content.
- The user switches to an Android tablet to use the subscription.
- The app on the new device queries for an updated list of purchases.
- The app recognizes the subscription and grants access to it on the tablet.
Query cached purchases
To retrieve information about purchases that a user makes from your app, call
queryPurchases()
with the purchase type (SkuType.INAPP or SkuType.SUBS) on the
BillingClient, as shown in the following example:
Kotlin
val purchasesResult: PurchasesResult =
billingClient.queryPurchases(SkuType.INAPP)
Java
PurchasesResult purchasesResult = billingClient.queryPurchases(SkuType.INAPP);
Google Play returns the purchases made by the user account logged in to the
device. If the request is successful, the Play Billing Library stores the query
results in a List of Purchase
objects.
To retrieve the list, call
getPurchasesList()
on the
PurchasesResult.
You can then call a variety of methods on the
Purchase object to
view relevant information about the item, such as its purchase state or time. To
view the types of product detail information that are available, see the list of
methods in the Purchase class.
You should call
queryPurchases()
at least twice in your code:
- Call
queryPurchases()every time your app launches so that you can restore any purchases that a user has made since the app last stopped. - Call
queryPurchases()in youronResume()method, because a user can make a purchase when your app is in the background (for example, redeeming a promo code in the Google Play Store app).
Calling queryPurchases()
on startup and resume guarantees that your app finds out about all purchases and
redemptions the user may have made while the app wasn't running. Furthermore, if
a user makes a purchase while the app is running and your app misses it for any
reason, your app still finds out about the purchase the next time the activity
resumes and calls
queryPurchases().
Query most recent purchases
The
queryPurchases()
method uses a cache of the Google Play Store app without initiating a network
request. If you need to check the most recent purchase made by the user for each
product ID, you can use
queryPurchaseHistoryAsync(),
passing the purchase type and a
PurchaseHistoryResponseListener
to handle the query result.
queryPurchaseHistoryAsync()
returns a PurchaseHistory
object that contains info about the most recent purchase made by the user for
each product ID, even if that purchase is expired, cancelled, or consumed. Use
queryPurchases()
whenever possible, as it uses the local cache, instead of
queryPurchaseHistoryAsync(). If using queryPurchaseHistoryAsync(), you can
also combine it with a Refresh button, allowing users to update their list
of purchases.
The following code demonstrates how you can override the
onPurchaseHistoryResponse()
method:
Kotlin
billingClient.queryPurchaseHistoryAsync(SkuType.INAPP, { billingResult, purchasesList ->
if (billingResult.responseCode == BillingResponse.OK && purchasesList != null) {
for (purchase in purchasesList) {
// Process the result.
}
}
})
Java
billingClient.queryPurchaseHistoryAsync(SkuType.INAPP,
new PurchaseHistoryResponseListener() {
@Override
public void onPurchaseHistoryResponse(BillingResult billingResult,
List<Purchase> purchasesList) {
if (billingResult.getResponseCode() == BillingResponse.OK
&& purchasesList != null) {
for (Purchase purchase : purchasesList) {
// Process the result.
}
}
}
});
Next steps
After you're able to allow users to buy your products, you should learn how to cover product-specific scenarios:
- If you're adding Google Play Billing to support one-time products, see Add one-time product-specific features.
- If you're adding Google Play Billing to support rewarded products, see Add rewarded-product-specific features.
- If you're adding Google Play Billing to support subscriptions, see Add Subscription-specific features.