In-App Purchases & Subscriptions

Learn how to integrate payments into your app

The InAppPurchaseClient is the central piece for providing in-app purchases and subscriptions in your app.

We provide a thin layer on top of Google’s Billing 5 library. The billing flow is similar and we provide access to the objects used underneath. The InAppPurchaseClient is a simpler Kotlin based API for faster interactions and improved Developer Experience using Jetpack Compose. The client also handles retry connectivity mechanism out of the box.

 

Understand the In-App purchase flow

It is highly recommended to understand the steps of the purchase process, before you start implementing any in-app purchase flows.

The high level steps are:

  1. Register your products and subscriptions on the Play Store Console.
  1. Get the product details from the Play Store
  1. Start the in-app purchase flow, using the product details.
  1. When a payment is successful, acknowledge or consume the purchase and grant the customer the services or goods.
 
🚨
Make sure you acknowledge a purchase. If you do not, Google Play will refund the purchase after a few days.
 

Register your products & subscriptions via the Play Store Console

This step is rather straight forward. Head to the Play Store Console and register your in-app products and subscriptions.

We recommend you to register your products ahead of time in order to save time and headaches. Sometimes it take a while for the Play Store to finish registering new products. This might cause the API to think that you have not registered any products.

Implement In-App Purchases and & subscriptions using the InAppPurchaseClient

 

Get product details from Play Store

Use the inAppPurchaseClient() to get a reference to the InAppPurchaseClient. Use the fetchProductDetails() to get information about the product you are interested in by passing the appropriate product ID.

// in your ViewModel

viewModelScope.launch {
	productDetailsOneTime = inAppPurchaseClient.fetchProductDetails(
	        Product("one_time_purchase", ProductType.InApp),
  ).getOrNull()
}

You can also fetch the product details within a composable function. Use rememberInAppPurchaseClient() to get a reference to the client. Then use a LaunchedEffect() to fetch the details within a coroutine:

val inAppPurchase = rememberInAppPurchaseClient()
var productDetailsOneTime by remember { mutableStateOf<ProductInformation?>(null) }

LaunchEffect(Unit){
	productDetailsOneTime = inAppPurchase.fetchProductDetails(
		        Product("one_time_purchase", ProductType.InApp),
  ).getOrNull()
}
 

Start the in-app purchase flow

Use rememberInAppPurchaseClient() to get a reference to the client. Then start the in-app purchase flow:

Button(
    onClick = {
        val params = PurchaseFlowParams(
            requireNotNull(productDetailsOneTime).productDetails
        )
        inAppPurchaseClient.launchPurchaseFlow(activity, params)
    }
) {
    Text("Purchase")
}
 

Acknowledge or consume purchases

As soon as your customers purchase a product or subscriptions, it is important to acknowledge the purchase.

This is normally where you save the purchase in your backend for your records and deliver the goods to your customer.

 
🚨
If you do not acknowledge (or consume) the purchase, Google will refund the full amount after a few days.
 

If are selling consumable products (such as extra lives in a game) then you need to consume the purchase. Otherwise, you can simple acknowledge the purchase instead.

Use the purchaseEvents() function to be notified for purchasing events (such as successful payments, cancelations or failures). On a successful purchase, consume or acknowledge the payment:

LaunchedEffect(Unit) {
		  inAppPurchase.purchaseEvents()
		      .collect { event ->
							if (event is Completed) {
		              event.purchases.forEach { purchase ->
		                  val token = purchase.googlePurchase.purchaseToken
											inAppPurchase.consumePurchase(PurchaseToken(token))
		              }
		          }
		  }
}

Both acknowledge and consume functions return a Result<Unit>, which you can use to check if the operation was successful or not.

FAQ

“This version of the application is not configured for billing through Google Play”

  1. Make sure the device has Google Play Store installed with a Google account signed in.
  1. People online claim that you need to upload a version of your app to the Google Play for this error to go away.
 

“Can I use the emulator for debugging purchases?”

Yes. You are not forced to use a real device to test purchases. The emulator needs to have the Play Store app installed and a Google account setup.

 

“Why does fetchProductDetails() is returning an empty list?”

Go to the Play Console and double check your products are Active.

Keep in mind that the Play Store might take a while to register new products. If you are sure that you have created them via the console and have activated them, try again in an hour or two.

Did this answer your question?
😞
😐
🤩