About this codelab
1. Overview
Optimize your revenue streams and launch your app confidently with this Play Billing Library integration codelab by Google Play. This structured codelab guides you through setting up, testing, and implementing reliable purchase processing, enabling you to support your monetization goals and deliver a more seamless user experience.
We'll help you set up Real-time developer notifications (RTDNs) and Play Billing Lab for subscriptions and one-time products for your apps and games. You'll learn how to reduce subscriber churn; protect against fraud and abuse; test edge cases; simulate, reproduce, and address potential issues; and experiment with offers and price changes without impacting users.
By the end, you'll be ready to implement win-back strategies, quickly solve integration challenges, improve ROI, deliver a premium experience, and roll out your app and updates with confidence.
Prerequisites
- Familiarity with the basic Play Billing Library integration
- Familiarity with Android app development (Java)
What you'll learn
- How to properly manage your purchase lifecycles to help optimise growth with techniques to improve purchase conversions and customer retention
- How to set up Real-time developer notifications (RTDN) using Google Cloud Pub/Sub, which can then be leveraged to implement win-back campaigns and other lifecycle management strategies
- How to set up a receiver on your backend server to securely handle the notifications with accurate tracking and entitlement to reduce unintended refunds or fraud and abuse risks
- How to test your integration and simulate errors using the Play Billing Lab to improve your user experience while reducing development costs
What you'll need
- Access to the Play Developer account for your app in Google Play Console
- Access to your Google Cloud Platform Project with Google Play Developer API enabled
- A backend server to handle accounts and entitlements for your Android app
- License testers registered for your app in Play Developer Console
- Play Billing Lab installed on your testing device
2. Monetization strategies for subscriptions and one-time purchases
When selling digital products through your app, a successful monetization strategy must consider the entire user experience, both for one-time purchases and subscriptions. A seamless experience can increase purchase readiness and reduce churn.
A common purchase flow for a one-time purchase or subscription will involve multiple stages:
- The user browses items to buy.
- Launch the purchase flow for the user to complete the purchase and payment.
- Notify your server about the completed purchase
- Verify the purchase on your server.
- Give content to the user.
- Acknowledge delivery of the content. For consumable products, consume the purchase at the appropriate time so that the user may buy the item again.
In-app integration allows you to launch purchase flows and manage this user experience, but it's crucial to keep your backend up-to-date on the entitlements that users are purchasing. This is important for tracking purchases and managing other aspects of the user experience, such as cross-platform entitlements.
Real-time developer notifications (RTDN) are a great way to recognise these different stages in the purchase lifecycle and can be effectively used both as a real-time performance tracking tool, and as a tool to enable subscriber win-back strategies.
For example: Say your user has just purchased a new item or has just missed their payment so the subscription has entered the grace period. With the right RTDN, you can recognise, near real time, that the status of the user has changed and act accordingly by either getting the user even more engaged with the item they just bought or, by sending them reminder emails to update their payment details to continue their subscription.
RTDNs are also a great way to add additional server side controls to help you manage purchases even when the user's client has issues. Say a user made a successful purchase and received confirmation from Google, but their device loses network connectivity before their device and your app receives notification of the purchase through the purchase listener. With RTDNs you would receive an independent notification through your server, allowing you to recognise the purchase and grant the entitlement to the user independently of the client issue, ensuring a reliable process of the purchase.
You can learn more about all the types of RTDNs currently supported here. Each type of RTDN signals a distinct purchase status. It is crucial to implement corresponding handling mechanisms to ensure proper processing as needed in your use cases. This codelab will walk you through an example that handles the RTDN message in your secure backend server, including receiving the message, validating the purchase and granting the entitlement to the correct user, when a user successfully completes a purchase in your app. And next, we will show you how to configure RTDNs for your app.
3. Configure real-time developer notifications (RTDN)
Real-time developer notifications (RTDN) leverage Google Cloud Pub/Sub to allow you to react immediately to the purchase state changes. Cloud Pub/Sub is a fully-managed real-time messaging service that you can use to send and receive messages between independent applications. Google Play uses Cloud Pub/Sub to publish push notifications on topics to which you subscribe.
To enable RTDN, you must first set up Cloud Pub/Sub using your own Google Cloud Platform (GCP) project and then enable the notifications for your app. If you're not familiar with GCP and Cloud Pub/Sub, see the Quickstart guide.
Create a topic
To start receiving notifications, you must create a topic to which Google Play should publish the notifications. To create a topic, follow the instructions in Create the topic.
Create a Pub/Sub subscription
To receive messages published to a topic, you must create a Pub/Sub subscription to that topic. To create a Pub/Sub subscription, do the following:
- Read the Cloud Pub/Sub Subscriber Guide to get yourself familiar with how to configure the subscription as either a push subscription or a pull subscription. In this codelab, we will work with a pull subscription that requires your secure backend server to initiate requests to the Cloud Pub/Sub server to retrieve messages.
- Follow the instructions in Add a subscription to create a subscription.
Grand publish rights on your topic
Cloud Pub/Sub requires that you grant Google Play privileges to publish notifications to your topic.
- Open the Google Cloud Console.
- Select your project, and then search for "Pub/Sub" in the search bar and navigate to the Pub/Sub config page.
- Find your topic, and open the permissions setting.
- Click ADD PRINCIPAL to add the service account
google-play-developer-notifications@system.gserviceaccount.com
, and grant it the role of Pub/Sub Publisher. - Click Save to complete the topic set up.
Enable RTDN for your app
Learn to set up Real-time developer notifications (RTDN) to significantly enhance your Play Billing integration. You can improve purchase reliability with personalized messaging and also prevent fraud and abuse to improve your overall ROI.
RTDNs provide immediate server-to-server updates directly from Google Play for key events, like subscription renewals, new purchases, and payment issues. They help your backend systems synchronize automatically with the true status of user entitlements, moving beyond client-side limitations and enabling you to react instantly and appropriately.
How to enable Real-time developer notifications for your app:
- Open the Google Play Console.
- Select your app.
- Go to Monetize with Play > Monetization setup.
- Scroll to the Real-time developer notifications section.
- Check Enable real-time notifications.
- In the Topic name field, enter the full Cloud Pub/Sub topic name that you configured earlier. The topic name should be in the format of projects/{project_id}/topics/{topic_name} where project_id is the unique identifier for your project, and topic_name is the name of the topic created earlier.
- Click Send Test Message to send a test message. Performing a test publish helps to ensure that everything is set up and configured properly. If the test publish succeeds, a message is displayed stating that the test publish was successful. If you have attached a subscription for this topic, you should receive the test message. For a pull subscription, go to the subscription in Cloud Console, click View Messages, and proceed to pull messages. You should acknowledge any message you have pulled to avoid repeated delivery by Cloud Pub/Sub. For a push subscription, check if the test message is delivered to your push endpoint. A successful response code will serve as a message of acknowledgement. If the publish fails, an error is shown. Ensure that the topic name is correct and that the
google-play-developer-notifications@system.gserviceaccount.com
service account has Pub/Sub Publisher access to the topic. - Choose which notification types you'd like to receive.
- Get notifications for subscriptions and all voided purchases - receive real-time developer notifications related to subscriptions and voided purchases. You won't receive notifications for one-time product purchases.
- Get all notifications for subscriptions and one-time products - receive notifications for all subscription and voided purchase events. You'll also receive one-time product purchase events, such as
ONE_TIME_PRODUCT_PURCHASED
andONE_TIME_PRODUCT_CANCELED
. See One-time purchase lifecycle to learn more about these purchase events.
- Click Save changes.
Now you have completed the real-time developer notifications for your app, providing you with the tools to address common challenges, like user churn through win-back messaging, or fraud and abuse. In the next section, we will build a subscriber in your secure backend server to consume the messages sent to your Cloud Pub/Sub topic.
4. Receive notifications
It is critical to keep your backend server up-to-date on the status of the purchases for the best user experience in your app. For example, when a user successfully completes a purchase with a payment in the app, they should get the content delivered to their account as soon as possible.
This requires the completion of the purchase to be detected and processed in a timely manner. Play Billing Library provides multiple ways to detect the purchases in your app. Upon detection of a completed purchase, your app must notify your backend server to verify the purchase, grant the content to the correct user and then notify Google the purchase has been processed. However, it could happen that your app didn't detect the purchase in a timely manner due to various reasons. For example, a user can make a successful purchase and receive confirmation from Google, but their device loses network connectivity before their device and your app receives notification through the Play Billing Library interface. RTDN provides additional server side controls to help you manage purchases even when the user's client has issues. RTDN guarantees independent notifications to your server upon purchase status changes, allowing you to recognise the purchase status changes almost immediately through a second path independently of the potential client issues, ensuring a more reliable process of the purchase.
In this section you will build a subscriber to consume the messages sent to your Cloud Pub/Sub topic by using the Cloud Pub/Sub Client Libraries. These libraries are available in a variety of languages. In the following sections, we will add to the subscriber to verify the purchase, grant entitlement to the correct user and acknowledge/consume the purchase on the server. For this codelab, we are using Java.
Each publish made to a Cloud Pub/Sub topic contains a single base64-encoded data field.
{
"message": {
"attributes": {
"key": "value"
},
"data": "eyAidmVyc2lvbiI6IHN0cmluZywgInBhY2thZ2VOYW1lIjogc3RyaW5nLCAiZXZlbnRUaW1lTWlsbGlzIjogbG9uZywgIm9uZVRpbWVQcm9kdWN0Tm90aWZpY2F0aW9uIjogT25lVGltZVByb2R1Y3ROb3RpZmljYXRpb24sICJzdWJzY3JpcHRpb25Ob3RpZmljYXRpb24iOiBTdWJzY3JpcHRpb25Ob3RpZmljYXRpb24sICJ0ZXN0Tm90aWZpY2F0aW9uIjogVGVzdE5vdGlmaWNhdGlvbiB9",
"messageId": "136969346945"
},
"subscription": "projects/myproject/subscriptions/mysubscription"
}
After you decode the base64-encoded data field, the DeveloperNotification
contains the following fields:
{
"version": string,
"packageName": string,
"eventTimeMillis": long,
"oneTimeProductNotification": OneTimeProductNotification,
"subscriptionNotification": SubscriptionNotification,
"voidedPurchaseNotification": VoidedPurchaseNotification,
"testNotification": TestNotification
}
Please refer to Real-time developer notifications reference for more information.
The following is the sample code of a NotificationReceiver for your secure backend server to process the Pub/Sub messages. To authenticate to the Security Command Center, set up Application Default Credentials, see Set up authentication for a local development environment.
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.PubsubMessage;
import java.util.Base64;
import org.json.JSONObject;
/** Real-time developer notifications receiver. */
public class NotificationReceiver {
private NotificationReceiver() {}
/*
* Receive notification messages from the subscription.
*
* @param projectId The project ID of your Google Cloud Project.
* @param subscriptionId The subscription ID of the subscriber to the pub/sub topic.
*/
public static void receiveNotificationMessages(String projectId, String subscriptionId) {
ProjectSubscriptionName subscriptionName =
ProjectSubscriptionName.of(projectId, subscriptionId);
try {
Subscriber subscriber =
Subscriber.newBuilder(subscriptionName, new NotificationMessageReceiver()).build();
// Start the subscriber.
subscriber.startAsync().awaitRunning();
subscriber.awaitTerminated();
} catch (IllegalStateException e) {
System.out.println("Subscriber stopped: " + e);
}
}
static class NotificationMessageReceiver implements MessageReceiver {
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
// Decode the data into a String from the message data field.
String jsonString = new String(Base64.getDecoder().decode(message.getData().toStringUtf8()));
// Parse the String into a JSON object.
JSONObject messageJson = new JSONObject(jsonString);
// Fetch the value for certain fields.
String version = messageJson.getString("version");
String packageName = messageJson.getString("packageName");
System.out.println("version: " + version);
System.out.println("packageName: " + packageName);
// Validate the purchase and grant the entitlement as needed.
// More details in the following sections.
// ......
// Acknowledge the message to avoid repeated delivery.
consumer.ack();
}
}
}
Now, you have a notification receiver that consumes the messages sent to your Cloud Pub/Sub topic in your secure backend server. In the following sections, we will cover the best practices to process the RTDN messages in your backend server.
5. Attach user identifiers in the purchase flow in your app
When your server receives the RTDN message about the purchase status update, your server needs to know which user made the purchase to process it, such as delivering the content to the correct user. You can achieve this by attaching any user identifiers you have for the user making the purchase using obfuscatedAccountId when launching the purchase flow in your app. An example identifier could be an obfuscated version of the user's login in your system. Setting this parameter can help Google detect fraud. Additionally, it can help you ensure purchases are attributed to the right user as discussed in granting entitlements to users.
The following shows the sample codes to attach the user identifier when launching the purchase flow in the app by setting obfuscatedAccountId.
// An activity reference from which the billing flow will be launched.
Activity activity = ...;
// A user identifier, e.g. an obfuscated user id in your system.
String obfuscatedAccountId = ...;
ImmutableList<ProductDetailsParams> productDetailsParamsList =
ImmutableList.of(
ProductDetailsParams.newBuilder()
// retrieve a value for "productDetails" by calling queryProductDetailsAsync()
.setProductDetails(productDetails)
// set the offer token to specify the offer to purchase when applicable, e.g., subscription products
// .setOfferToken(offerToken)
.build()
);
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setObfuscatedAccountId(obfuscatedAccountId)
.build();
// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
As you will see in the next section, the user identifier set in the purchase flow will be included in the purchase and can be used to grant entitlements to the correct user.
6. Verify purchases before granting entitlements
In this section, we will go over the best practices to verify purchases before granting entitlements in your secure backend server.
After a user has made a one-time product purchase, the Pub/Sub subscriber in your secure backend server will receive a Pub/Sub message. You should do the following in your backend server:
- Parse the
purchaseToken
from the Pub/Sub message. You should maintain a record of allpurchaseToken
values for all purchases. - Verify that the
purchaseToken
value for the current purchase does not match any previouspurchaseToken
values.purchaseToken
is globally unique, so you can safely use this value as a primary key in your database. - Use the purchases.products:get endpoint in the Google Play Developer API to verify with Google that the purchase is legitimate.
- If the purchase is legitimate and has not been used in the past, you can then safely grant entitlement to the in-app item or subscription.
- You should grant entitlement only when the purchase state is
PURCHASED
and make sure to handle thePENDING
purchases correctly. You can find more information at Handling pending transactions.
The following code example creates an API client for the Google Play Developer API. We will use it to make the api calls later.
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
/** Helper class to initialize the publisher APIs client library. */
public class AndroidPublisherHelper {
/* Your application name */
private static final String APPLICATION_NAME = "YourApplicationName";
/* Load credentials from a JSON key file. Replace with the actual path to your downloaded service
* account key file.
*/
private static final String RESOURCES_CLIENT_SECRETS_JSON =
"/path/to/your/service_account_key.json";
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
/* The API client */
private static final AndroidPublisher ANDROID_PUBLISHER = init();
/**
* Performs all necessary setup steps for running requests against the API.
*
* @return the {@link AndroidPublisher} service
*/
private static AndroidPublisher init(){
try {
// Authorization.
Credential credential =
GoogleCredential.fromStream(
AndroidPublisherHelper.class.getResourceAsStream(RESOURCES_CLIENT_SECRETS_JSON))
.createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Set up and return API client.
return new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(ApplicationConfig.APPLICATION_NAME)
.build();
} catch (GeneralSecurityException | IOException ex) {
throw new RuntimeException("fail to initialize the publisher APIs client library", ex);
}
}
}
Then, we add the logic to make the API call and modify the receiver built previously to validate the purchase and grant the entitlement to the correct user.
In AndroidPublisherHelper
, add the following method to fetch the ProductPurchase from the Purchases.products:get endpoint in the Google Play Developer API.
/* Fetch the ProductPurchase for the one-time product purchase from
* Purchases.products.get endpoint in the Google Play Developer API
*/
public static ProductPurchase executeProductPurchasesGet(
String packageName, String sku, String purchaseToken) {
try {
ProductPurchase productPurchase =
ANDROID_PUBLISHER.purchases().products().get(packageName, sku, purchaseToken).execute();
return productPurchase;
} catch (IOException ex) {
log.error("Exception was thrown while getting a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to fetch the purchase in case of transient failures.
return null;
}
}
In NotificationMessageReceiver
, validate the purchase and grant the entitlement to the correct user in your system based on the data included in the notification. You should keep tracking the purchaseToken
in your server to avoid duplicate processing.
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
// Decode the data into a String from the message data field.
String jsonString = new String(Base64.getDecoder().decode(message.getData().toStringUtf8()));
// Parse the String into a JSON object.
JSONObject messageJson = new JSONObject(jsonString);
// Fetch the value for certain fields.
String version = messageJson.getString("version");
String packageName = messageJson.getString("packageName");
// Process notification data based on your business requirements.
// Process oneTimeProductNotification in the message.
JSONObject oneTimeProductNotificationJson =
messageJson.getJSONObject("oneTimeProductNotification");
if (oneTimeProductNotificationJson != null) {
String purchaseToken = oneTimeProductNotificationJson.getString("purchaseToken");
String sku = oneTimeProductNotificationJson.getString("sku");
int notificationType = oneTimeProductNotificationJson.getInt("notificationType");
if (notificationType == 1) {
// ONE_TIME_PRODUCT_PURCHASED - A one-time product was successfully purchased by a user.
// Verify that the purchaseToken value does not match any previous purchaseToken values in
// your backend system to avoid duplicate processing.
......
// Fetch the ProductPurchase from Purchases.products.get endpoint
ProductPurchase productPurchase =
AndroidPublisherHelper.executeProductPurchasesGet(packageName, sku, purchaseToken);
if (productPurchase != null && productPurchase.getPurchaseState() == 0) {
// The purchase is valid and in PURCHASED state.
// The account Id set in the App when launching the billing flow.
String obfuscatedExternalAccountId = productPurchase.getObfuscatedExternalAccountId();
// Grant the entitlement to the correct account for obfuscatedExternalAccountId in your
// system.
......
}
}
// Process subscriptionNotification in the message.
JSONObject subscriptionNotificationJson = messageJson.getJSONObject("subscriptionNotification");
if (subscriptionNotificationJson != null) {
......
}
// Process other notification data in the message as needed.
......
}
// Acknowledge the message to avoid repeated delivery.
consumer.ack();
}
7. Notify Google that the purchase has been processed
After granting entitlement, you should notify Google that the purchase has been processed by calling the purchases.products:consume or purchases.products:acknowledge endpoint points in Play Developer API from your secure backend server to consume a consumable product or acknowledge a non-consumable product.
In AndroidPublisherHelper
, add the following methods to call purchases.products:consume or purchases.products:acknowledge in the Google Play Developer API.
/* Consume the one-time product purchase by calling
* Purchases.products.consume endpoint in the Google Play Developer API
*/
public static void executeProductPurchasesConsume(
String packageName, String sku, String purchaseToken) {
try {
ANDROID_PUBLISHER
.purchases().products().consume(packageName, sku, purchaseToken).execute();
} catch (IOException ex) {
log.error("Exception was thrown while consuming a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to ensure the purchase is correctly consumed in case of transient failures.
}
}
/* Acknowledge the one-time product purchase by calling
* Purchases.products.acknowledge endpoint in the Google Play Developer API
*/
public static void executeProductPurchasesAcknowledge(
String packageName, String sku, String purchaseToken) {
try {
ANDROID_PUBLISHER
.purchases().products().acknowledge(packageName, sku, purchaseToken, new ProductPurchasesAcknowledgeRequest()).execute();
} catch (IOException ex) {
log.error("Exception was thrown while acknowledging a product purchase", ex);
// It is recommended to apply some retry mechanism, such as exponential backoff, to ensure the purchase is correctly acknowledged in case of transient failures.
}
}
In NotificationMessageReceiver
, consume the consumable product purchase or acknowledge the non-consumable product purchase after granting the entitlement in your backend server.
@Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
......
String obfuscatedExternalAccountId = productPurchase.getObfuscatedExternalAccountId();
// Grant the entitlement to the correct account for obfuscatedExternalAccountId in your
// system.
......
// If the product is a consumable product, consume the purchase.
AndroidPublisherHelper.executeProductPurchasesConsume(packageName, sku, purchaseToken);
// Or if the product is a non-consumable product, acknowledge the purchase.
// AndroidPublisherHelper.executeProductPurchasesAcknowledge(packageName, sku, purchaseToken);
......
}
Acknowledgment is required, as it notifies Google Play that the user has been granted entitlement to the purchase. You should acknowledge the purchase immediately after granting entitlement.
Great job! You've successfully integrated with Real-time developer notifications, enabling reliable purchase processing as demonstrated in this codelab. Now, to ensure everything is working perfectly, let's explore the Play Billing Lab, a user-friendly tool designed to help test your Play Billing integration.
8. Test with Play Billing Lab
In order to launch with confidence, you should be testing your integration throughout development. Play Billing Lab is a free Android app that helps developers test their integration with Google Play's billing system, providing an easy and convenient way for developers to test Play Billing features, integrate faster, and launch with higher confidence.
Play Billing Lab offers various testing features to help test different scenarios, including:
- Change Play Country from within Play Billing Lab and apply the settings to your test. This enables testing custom user-experiences in different countries/regions regardless of where the tester is physically testing
- Test trial or introductory offers repeatedly with the same account
- Test subscription price changes without affecting other active subscribers
- Simulate Play Billing Library response code to test under various error scenarios
- Accelerate subscription renewals to speed up testing
- Test with real payment methods to bypass certain purchase flow risk signals
We are continuously adding new test capabilities to the Play Billing Lab app. You can download and install Play Billing Lab from the Play Store, or check out Test your integration for more information about testing with Play Billing Lab.
Use Play Billing Lab to test BillingResponseCode
It is a common challenge to test all the BillingResponseCode flows when integrating your app with the Play Billing Library, because you don't have much control over the communication between the Play Store and Play's backend. The Response Simulator feature in the Play Billing Lab app lets you configure error code responses for the Play Billing Library to test various complex error scenarios.
For example, you implemented the logic in your app to consume the purchase after your app detects the successful purchase. You would like to test the scenario that your app failed to consume the purchase due to network failure and the RTDN receiver in your backend server picks up the message and handles the purchase correctly. You can leverage Response Simulator to simulate the scenario for your testing. The following will guide you through the steps to test with Play Billing Lab Response Simulator.
Test with Response Simulator
When testing with Response Simulator, your app will communicate with Play Billing Lab to get the response code you configured in Play Billing Lab Response Simulator.
Enable billing overrides testing for the Play Billing Library
To enable communication between the Response Simulator and your app, you must first enable billing overrides testing for the Play Billing Library from within your app. To do this, add the following metadata tags to your app's AndroidManifest.xml
file.
<manifest ... >
<application ... >
...
<meta-data
android:name="com.google.android.play.largest_release_audience.NONPRODUCTION"
android:value="" />
<meta-data
android:name="com.google.android.play.billingclient.enableBillingOverridesTesting"
android:value="true" />
</application>
</manifest>
Build your app with the updated AndroidManifest.xml
file. Now, your app is ready for the Play Billing Lab Response Simulator.
When you deploy your app to the production environment after testing, you should either use a separate AndroidManifest.xml
file that doesn't include these metadata tags or ensure that you've removed these tags from the AndroidManifest.xml
file.
Simulate Play Billing Library errors
To test with simulated Play Billing Library errors, first, configure the response code in the Play Billing Lab app, then perform the test in your app.
Configure a response code
- Sign in Play Billing Lab app with a license tester account for your app. The following picture displays the Play Billing Lab Dashboard, including the Response Simulator card.
- Click Manage on the Response Simulator card to navigate to the Response Simulator screen.
- When prompted, allow notifications from Play Billing Lab to see the connection status of your app.
- Enable the Simulate Play Billing Library response switch, if it isn't already enabled.
- Select a response code for the Play Billing Library APIs that you want to test. To simulate the error for the consuming purchase, select an error code for the
consumeAsync
api. Your selections are automatically saved. Now the Response Simulator is ready to send the selected response codes to your app.
Test your app
Now you can test your app to verify if everything works as expected in the configured error scenario. Open your app and trigger the Play Billing Library API method. If your app makes the consumeAsync
call to consume the purchase, your app will receive the error code as you just configured. You can verify if your app is working correctly upon the error code and your backend server is processing the purchase correctly.
After you have done with your testing, just turn off the Simulate Play Billing Library response switch to stop simulating the response.
Learn more about testing with Play Billing Lab, or visit the Help Center for more on testing in-app billing with License Testers.
9. Congratulations!
You have finished this codelab and are now equipped to strategically optimize your app monetization to improve your user experience to drive improvements in user satisfaction, purchase conversions, and subscriber churn.
By leveraging Real-time Developer Notifications and the Play Billing Lab companion app, you can proactively address purchase lifecycle events for both one-time purchases and subscriptions.
With these tools, you can effectively implement engaging win-back strategies, swiftly resolve integration challenges, and ultimately enhance user experience and revenue streams to launch your app or game with confidence.
By completing this codelab, you now possess the skills to manage the entire purchase journey and rigorously test your implementation with the Play Billing Lab, ensuring a seamless user experience and maximizing your monetization potential on Google Play.