Skip to content

Most visited

Recently visited

navigation

Purchasing In-app Billing Products

Once your app connects to Google Play, you can initiate purchase requests for in-app products. Google Play provides a checkout interface for users to enter their payment method, so your app does not have to handle payment transactions directly.

When a user purchases an item, Google Play recognizes that the user has ownership of that item and prevents the user from purchasing another item with the same product ID until it is consumed. You can control how the user consumes an item in your app, and notify Google Play to make the item available for purchase again.

You can also query Google Play to quickly retrieve the list of purchases made by the user. Make sure to perform this check every time your app launches to restore any purchases that a user may have made since you app last stopped.

Purchase an item

To start a purchase or subscription replacement request from your app, call launchBillingFlow() from the UI thread. The following code shows how you can integrate this method into the BillingManager class:

public void initiatePurchaseFlow(final String skuId, final ArrayList<String> oldSkus,
            final @BillingClient.SkuType String billingType) {
        Runnable purchaseFlowRequest = new Runnable() {
            @Override
            public void run() {
                BillingFlowParams.Builder mParams = BillingFlowParams.newBuilder().
                        setSku(skuId).setType(billingType).setOldSkus(oldSkus);
                mBillingClient.launchBillingFlow(mActivity, mParams.build());
            }
        };

        executeServiceRequest(purchaseFlowRequest);

When you call launchBillingFlow() the Google Play UI purchase screen displays. If the purchase order is successful, the response data from Google Play is stored in a Purchase object that is passed back to the appropriate listener. Google Play then calls the onPurchasesUpdated() method to deliver the result of a purchase order to a listener that implements the PurchasesUpdatedListener interface.

In this training lesson, you implement the PurchasesUpdatedListener interface in the BillingManager class. You pass the listener to the BillingClientImpl constructor class when you create an instance of the Play Billing Client client, as described in Preparing Your In-app Billing App. The following code shows how you can implement the onPurchasesUpdated() method in the BillingManager class:

@Override
public void onPurchasesUpdated(int resultCode, List<Purchase> purchases) {
    if (resultCode == BillingResponse.OK) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
        mBillingUpdatesListener.onPurchasesUpdated(mPurchases);
    } else if (resultCode == BillingResponse.USER_CANCELED) {
        // Skip this purchase as the user cancelled the operation.
    } else {
        // Handle any other result codes.
    }
}

You can then implement a handlePurchase() method in the BillingManager class to process each purchase in the result. The following sample code illustrates an implementation of this method that first verifies the signature of the response for a purchase and then logs the result:

private void handlePurchase(Purchase purchase) {
        // Perform purchase validation on your own secure server.
        if (!verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
            // Skip a purchase if the signature isn't valid.
            return;
        }
        mPurchases.add(purchase);
    }

Security Recommendation: When you receive the purchase response from Google Play, ensure that you check the returned data signature and the orderId. Verify that the orderId exists and is a unique value that you have not previously processed. Perform purchase validation on your own secure server. Don't trust the client, as an Android app can be decompiled and your security checks replaced with stubs. Call the get() method on the Purchases.products resource in the Subscriptions and In-App Purchases API or check the returned data signature and the orderId. You can't perform this check inside tests that use static responses as they don't return the signature.

To learn how to consume purchases, see Consume a purchase. It is good practice to update the UI immediately so that your users can see their newly purchased items.

Query purchased items

Upon a successful purchase, Google Play's In-app Billing service caches the user's purchase data locally. It is good practice to frequently query the In-app Billing service for purchases by the user, for example whenever the app starts up or resumes, so that the user's current in-app product ownership information is always reflected in your app.

To retrieve the user's purchases from your app, call queryPurchases() on the Play Billing Library client. This method fetches results from a cache provided by the Google Play Store app without initiating a network request. The following sample code illustrates how you can query purchased items from the BillingManager class:

public void queryPurchases() {
        Runnable queryToExecute = new Runnable() {
            @Override
            public void run() {
                long time = System.currentTimeMillis();
                PurchasesResult purchasesResult = mBillingClient.queryPurchases(SkuType.INAPP);
                if (areSubscriptionsSupported()) {
                    PurchasesResult subscriptionResult
                            = mBillingClient.queryPurchases(SkuType.SUBS);
                    if (subscriptionResult.getResponseCode() == BillingResponse.OK) {
                        purchasesResult.getPurchasesList().addAll(
                                subscriptionResult.getPurchasesList());
                    } else {
                        // Handle any error response codes.
                    }
                } else if (purchasesResult.getResponseCode() == BillingResponse.OK) {
                    // Skip subscription purchases query as they are not supported.
                } else {
                    // Handle any other error response codes.
                }
                onQueryPurchasesFinished(purchasesResult);
            }
        };

        executeServiceRequest(queryToExecute);
    }

If the query is successful, the query results are stored in a PurchasesResult object. You can then retrieve the List of Purchase objects by calling the getPurchasesList() method on the PurchasesResult object. The In-app Billing service returns only the purchases made by the user account that is currently logged in to the device.

Consume a purchase

You can use the Play Billing Library to track the ownership of purchased items in Google Play. Once a user purchases an item, it is considered to be owned and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again.

How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times, such as in-game currency or replenishable game tokens. You would typically not want to implement consumption for products that are purchased once and provide a permanent effect, such as a premium upgrade.

It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.

Security Recommendation: You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.

To record a purchase consumption on the client, call consumeAsync() on the Play Billing Library client. You pass a reference to a ConsumeResponseListener listener to handle the result of the conume operation. The following sample code illustrates how you can add the consumeAsync() method to the BillingManager class:

public void consumeAsync(final String purchaseToken) {
        if (mTokensToBeConsumed == null) {
            mTokensToBeConsumed = new HashSet<>();
        } else if (mTokensToBeConsumed.contains(purchaseToken)) {
            // Skip this token as it's already scheduled for consumption.
            return;
        }
        mTokensToBeConsumed.add(purchaseToken);

        final ConsumeResponseListener onConsumeListener = new ConsumeResponseListener() {
            @Override
            public void onConsumeResponse(@BillingResponse int responseCode, String purchaseToken) {
                // Try to reconnect once if the billing service was disconnected.
                mBillingUpdatesListener.onConsumeFinished(outToken, billingResult);
            }
        };

        // Create a runnable from the request to use it inside the connection retry policy.
        Runnable consumeRequest = new Runnable() {
            @Override
            public void run() {
                // Consume the purchase asynchronously.
                mBillingClient.consumeAsync(purchaseToken, onConsumeListener);
            }
        };

        executeServiceRequest(consumeRequest);
    }

In this training lesson, you pass the result of the operation to the onConsumeFinished() method in the UpdateListener class in your view controller. The following sample code shows how you can implement onConsumeFinished() in your view controller:

@Override
public void onConsumeFinished(String token, @BillingResponse int result) {
    if (result == BillingResponse.OK) {
        mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
        saveData();
        mActivity.alert(R.string.alert_fill_gas, mTank);
    } else {
        mActivity.alert(R.string.alert_error_consuming, result);
    }

    mActivity.showRefreshedUi();
}

Check for consumable items on startup

It's important to check for consumable items when the user starts your app. First query the In-app Billing service for the items purchased by the user. To perform this query call queryPurchases(), and then get the consumable Purchase objects from the Inventory. If your app detects that the user owns any consumable items, it must send a consumption request to Google Play immediately and provision the items to the user.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)