Use the Google Play Billing Library

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:

  1. Read the Google Play Billing Overview to familiarize yourself with important concepts and terms.
  2. Configure your in-app products using the Google Play Console:

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:

Figure 1. Opening screen of Trivial Drive 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.3'
}

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:

  1. Call newBuilder() to create an instance of BillingClient You must also call setListener(), passing a reference to a PurchasesUpdatedListener to receive updates on purchases initiated by your app, as well as those initiated by the Google Play Store.

  2. Establish a connection to Google Play. The setup process is asynchronous, and you must implement a BillingClientStateListener to receive a callback once the setup of the client is complete and it’s ready to make further requests.

  3. 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, the BillingClient may lose its connection if the Google Play Store service is updating in the background. The BillingClient must call the startConnection() 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 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 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:

Figure 2. The Trivial Drive in-app products screen.

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:

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 3. Google Play purchase screen for a one-time product.

Figure 4 shows a purchase screen for a subscription:

Figure 4. Google Play 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.

Figure 5. Google Play success screen.

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.purchaseState === 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.getPurchaseState() == 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.getPurchaseState() 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:

  1. When starting your app, call BillingClient.queryPurchases() to retrieve the list of unconsumed products associated with the user, and then call getPurchaseState() on each returned Purchase object.
  2. Implement the onPurchasesUpdated() method to respond to changes to Purchase objects.

Here's an example that demonstrates how you might handle pending transactions:

Kotlin

fun handlePurchase(purchase: Purchase) {
    if (purchase.purchaseState == PurchaseState.PURCHASED) {
        // Grant the item to the user, and then acknowledge the purchase
    } else if (purchase.purchaseState == 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.getPurchaseState() == PurchaseState.PURCHASED) {
        // Acknowledge purchase and grant the item to the user
    } else if (purchase.getPurchaseState() == 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:

  1. 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.

  2. After you get the token from the app:

    1. 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.products for a one-time product purchase or rewarded purchase, or Purchases.subscriptions for a subscription). The GET request includes the app package name, product ID, and a token (purchase token).

    2. Google Play returns the purchase details.

    3. The secure backend server verifies that the order ID is a unique value that doesn’t represent a previous purchase.

    4. 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.

    5. (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 linkedPurchaseToken field. The linkedPurchaseToken field in a Purchases.subscriptions resource contains the token of the previous, or “originating” purchase. For more about linkedPurchaseToken, see Purchases.subscriptions).

    6. 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

  1. A user buys a one-time product, such as extra gas for a driving game.
  2. The app sends the purchase token to the secure backend server for verification.
  3. The server is temporarily down.
  4. The app recognizes that the server is down and notifies the user that there’s a problem with the purchase.
  5. The Android app retries sending the purchase token to the secure backend server, and finishes the purchase as soon as the server is restored.
  6. The app releases the content.

Handling multiple devices

  1. A user buys a subscription on their Android phone.
  2. The app sends the purchase token to the secure backend server for verification.
  3. The server verifies the purchase token.
  4. The app releases the content.
  5. The user switches to an Android tablet to use the subscription.
  6. The app on the new device queries for an updated list of purchases.
  7. 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 your onResume() 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: