How to Implement In-App Subscriptions in Android: Google Play Billing Library 7 Guide

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

  1. Navigate to Monetize > Products > Subscriptions.
  2. Click Create subscription and set a Subscription Product ID: premium_pro_membership.
  3. 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.
  4. Offers: Optionally add a 7-day free trial offer targeting new subscribers.
  5. 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
                }
            }
        }
    }
}
Share this Guide Help colleagues and developers learn from this article
In-Article Sponsored Content
Mohit Kumaar
AUTHOR & FOUNDER

Mohit Kumaar

Founder & CEO of JMD WORLD with 8+ Years of industrial software engineering leadership (active since 2018). Creator and manager of 500+ production Google Play applications (proprietary & client solutions) and architect of apps.jmdworld.in. Operating from Pune & Mumbai under MSME Registration: UDYAM-MH-26-1071218 and D-U-N-SĀ® 581707246.

Previous Guide

Docker for Beginners: Containerizing Web & Mobile Backends in 2026

Software Setup
Next Guide

VS Code Ultimate Setup: Top 20 Extensions & Keybindings for Modern Coders

Developer Tools
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.