This document describes how to migrate from Google Play Billing Library (PBL) 7 or 8 to PBL 9 and how to integrate with the new features.
For a full list of the changes in version 9.0.0, refer to the release notes.
Overview
PBL 9 contains improvements to existing APIs along with the removal of previously deprecated APIs. This version of the library also introduces richer error context through new sub-response codes.
Backward-compatibility for PBL upgrade
To migrate to PBL 9, you need to update or remove some of your existing API references from your app, as described in the release notes and later in this migration guide.
Upgrade from PBL 7 or 8 to PBL 9
To upgrade from PBL 7 or 8 to PBL 9, do the following steps:
Update the Play Billing Library dependency version in your app's
build.gradlefile.dependencies { def billing_version = "9.0.0" implementation "com.android.billingclient:billing:$billing_version" }If you're using Kotlin, the Google Play Billing Library KTX module contains Kotlin extensions and coroutines support that enable you to write idiomatic Kotlin when using the Google Play Billing Library. To include these extensions in your project, add the following dependency to your app's
build.gradlefile as shown:dependencies { val billing_version = "9.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }(Applicable only for upgrade from PBL 7 to PBL 9). Update the implementation of the
queryProductDetailsAsyncmethod.There is a change in the signature of the
ProductDetailsResponseListener.onProductDetailsResponsemethod, which requires changes in your app for thequeryProductDetailsAsyncimplementation. For more information, see Show products available to buy.Handle the removed APIs.
The following table lists the APIs that are removed and the corresponding alternate APIs that you must use in your app.
Upgrade from
PBL 9 no longer supports the APIs listed in the following table. If your implementation uses any of these removed APIs, refer to the table for their corresponding alternate APIs.
Previously deprecated API removed Alternate API to use queryPurchaseHistoryAsync APIs See Query Purchase History. If you were using queryPurchaseHistoryAsync to determine eligibility for free trials, you should now use ProductDetails.getSubscriptionOfferDetails() to determine which offers a user is eligible for. BillingClient.SkuType BillingClient.ProductType. The INAPP and SUBS product type constants remain functionally similar to the deprecated SKU type constants. SkuDetails ProductDetails. This is the new data model that supports the one-time products. SkuDetailsParams Use QueryProductDetailsParams with queryProductDetailsAsync. SkuDetailsResponseListener Use ProductDetailsResponseListener with queryProductDetailsAsync. QueryPurchaseHistoryParams - Use queryPurchasesAsync for active or pending purchases.
- Track consumed purchases on your backend servers.
- Use the server-side Voided Purchases API for canceled or voided purchases.
getSkuDetailsList and setSkuDetailsList Use BillingFlowParams.Builder.setProductDetailsParamsList querySkuDetailsAsync queryProductDetailsAsync enablePendingPurchases() (API without parameters) enablePendingPurchases(PendingPurchasesParams params)
Note that the deprecated enablePendingPurchases() is functionally equivalent toenablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()).queryPurchasesAsync(String skuType, PurchasesResponseListener listener) queryPurchasesAsync Upgrade from
The following table lists the APIs that are removed in PBL 9, and the corresponding alternate APIs that you must use in your app.
Previously deprecated API removed Alternate API to use BillingClient.SkuType BillingClient.ProductType. The INAPP and SUBS product type constants remain functionally similar to the deprecated SKU type constants. SkuDetails ProductDetails. This is the new data model that supports the one-time products. SkuDetailsParams Use QueryProductDetailsParams with queryProductDetailsAsync. SkuDetailsResponseListener Use ProductDetailsResponseListener with queryProductDetailsAsync. QueryPurchaseHistoryParams - Use queryProductDetailsAsync for active or pending purchases.
- Track consumed purchases on your backend servers.
- Use the server-side Voided Purchases API for canceled or voided purchases.
getSkuDetailsList and setSkuDetailsList Use BillingFlowParams.Builder.setProductDetailsParamsList (Recommended) Enable automatic service reconnection.
The Play Billing Library can attempt to automatically re-establish the service connection if an API call is made while the service is disconnected. For more information, see Enable automatic service reconnection.
Handle new sub-response codes.
The BillingResult returned from
launchBillingFlow()will now include a sub-response code field. This field will only be populated in some cases to provide a more specific reason for the failure. The sub-response field can have the following values:PAYMENT_DECLINED_DUE_TO_INSUFFICIENT_FUNDS- Returned when the user's funds are less than the price of the item they are attempting to purchase.USER_INELIGIBLE- Returned when the user doesn't meet the configured eligibility requirements for a subscription offer.NO_APPLICABLE_SUB_RESPONSE_CODE- The default value, returned when no other sub-response code is applicable.
Migration step: Update your
PurchasesUpdatedListeneror equivalent result handling to recognize and respond to these specific sub-response codes to provide a better user experience. For example, prompting to fix payment methods or showing a specific error message.Error-code reclassification awareness.
For instances where the Play Store app is blocked by the system (for example, in OEM-customized kids mode), the response code from PBL has changed from
ERRORtoBILLING_UNAVAILABLE.Migration step: Ensure your error handling logic accommodates this change and doesn't rely on receiving a generic error in these specific scenarios.
Handle
DeveloperProvidedBillingDetails.getLinkUri()nullability.If you use
DeveloperProvidedBillingDetailsas part of an external payments integration,getLinkUri()is now@Nullable.Migration step: To handle this change safely, ensure your integration code handles both
nulland empty string ("") values from theDeveloperProvidedBillingDetails.getLinkUri()method before parsing or launching browser intents. For example:Kotlin
val linkUri = details.getLinkUri() if (!linkUri.isNullOrEmpty()) { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(linkUri)) context.startActivity(intent) }Java
String linkUri = details.getLinkUri(); if (!android.text.TextUtils.isEmpty(linkUri)) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(linkUri)); context.startActivity(intent); }Optional changes.
Support pending purchases for prepaid plans. For more information, see Handle Subscriptions and Pending Transactions.
Virtual installment subscriptions. For more information, see Installment Subscriptions Integration.