Understanding Google Play Billing Library 7 Architecture
Recurring subscriptions provide predictable, recurring revenue for mobile applications. With Google Play Billing Library 7, Google decoupled products from base plans and offers, allowing multiple billing cadences (e.g. monthly, annual) and discounted trial offers under a single Subscription ID.
Step 1: Adding the Billing Dependency
In your app/build.gradle.kts, include the latest Billing Library artifact:
dependencies {
implementation("com.android.billingclient:billing-ktx:7.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
}
Step 2: Configuring Subscriptions in Google Play Console
- Navigate to Monetize > Products > Subscriptions.
- Click Create subscription and set a Subscription Product ID:
premium_pro_membership. - Create Base Plans:
- Monthly Plan: ID
monthly-tier, Renewal type: Auto-renewing, Billing period: 1 month, Price: $4.99 / ā¹399. - Yearly Plan: ID
annual-tier, Renewal type: Auto-renewing, Billing period: 1 year, Price: $39.99 / ā¹2,999.
- Monthly Plan: ID
- Offers: Optionally add a 7-day free trial offer targeting new subscribers.
- Click Save > Activate.
Step 3: Initializing BillingClient in Android Studio
class BillingManager(private val context: Context, private val coroutineScope: CoroutineScope) : PurchasesUpdatedListener {
private val billingClient = BillingClient.newBuilder(context)
.setListener(this)
.enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
.build()
fun startBillingConnection(onConnected: () -> Unit) {
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
onConnected()
}
}
override fun onBillingServiceDisconnected() {
// Retry connection with exponential backoff
}
})
}
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList?) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
handlePurchase(purchase)
}
}
}
}
Step 4: Querying Subscription Product Details
suspend fun querySubscriptionDetails(productId: String): ProductDetails? {
val product = QueryProductDetailsParams.Product.newBuilder()
.setProductId(productId)
.setProductType(BillingClient.ProductType.SUBS)
.build()
val params = QueryProductDetailsParams.newBuilder()
.setProductList(listOf(product))
.build()
val result = billingClient.queryProductDetails(params)
return result.productDetailsList?.firstOrNull()
}
Step 5: Launching the Purchase Flow & Acknowledgement
Once user selects the plan, launch the Google Play bottom sheet:
fun launchSubscription(activity: Activity, productDetails: ProductDetails, selectedOfferToken: String) {
val productDetailsParamsList = listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setOfferToken(selectedOfferToken)
.build()
)
val billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.build()
billingClient.launchBillingFlow(activity, billingFlowParams)
}
CRITICAL: Acknowledge the Purchase: If you do not acknowledge a subscription within 3 days, Google will automatically refund the user and revoke access:
private fun handlePurchase(purchase: Purchase) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(acknowledgePurchaseParams) { result ->
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
// Unlock premium access in local Room database / backend
}
}
}
}
}
In-Article Sponsored Content
Suggested Engineering Guides
View All Guides (22+)
Recommended For You
Ads by Google
Comments (0)
No comments yet. Share your thoughts below!
Leave a Comment
Share your thoughts or questions. Your email address remains private.