Android SaaS App with Subscriptions: Complete 2025 Guide

Published: (December 13, 2025 at 08:08 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Market Context 2025

The global SaaS market size is estimated at USD 408.21 billion in 2025, projected to reach USD 1,251.35 billion by 2034.
The subscription billing management market is expected to reach $17.95 billion by 2030, growing at a CAGR of 16.9%.

1. Google Play Billing Library

Current Version

  • Play Billing Library 7.x (Required by August 2025)
  • Important Deadline: By August 31 2025, all new apps and updates must use Billing Library 7 or newer. Extensions are available until November 1 2025.

Key Features in Version 7.0+

  • Installment Subscriptions – Users pay in smaller, manageable installments (available in Brazil, France, Italy, Spain)
  • Pending Transactions for Subscriptions – Handle SUBSCRIPTION_STATE_PENDING before activation
  • ReplacementMode API – Replaces deprecated ProrationMode for upgrades/downgrades
  • User Choice BillingenableUserChoiceBilling() for alternative payment options

Implementation

// build.gradle.kts
implementation("com.android.billingclient:billing-ktx:7.1.1")

// Initialize BillingClient
val billingClient = BillingClient.newBuilder(context)
    .setListener { billingResult, purchases ->
        // Handle purchase updates
        purchases?.forEach { purchase ->
            if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                // Verify on backend, then acknowledge
                verifyAndAcknowledge(purchase)
            }
        }
    }
    .enablePendingPurchases(
        PendingPurchasesParams.newBuilder()
            .enablePrepaidPlans()
            .build()
    )
    .build()

// Connect to Google Play
billingClient.startConnection(object : BillingClientStateListener {
    override fun onBillingSetupFinished(billingResult: BillingResult) {
        if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
            querySubscriptions()
        }
    }
    override fun onBillingServiceDisconnected() {
        // Implement retry logic
    }
})

// Query available subscriptions
fun querySubscriptions() {
    val params = QueryProductDetailsParams.newBuilder()
        .setProductList(
            listOf(
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId("premium_monthly")
                    .setProductType(BillingClient.ProductType.SUBS)
                    .build(),
                QueryProductDetailsParams.Product.newBuilder()
                    .setProductId("premium_yearly")
                    .setProductType(BillingClient.ProductType.SUBS)
                    .build()
            )
        )
        .build()

    billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsList ->
        // Check for installment plans (PBL 7+)
        productDetailsList.forEach { product ->
            product.subscriptionOfferDetails?.forEach { offer ->
                offer.installmentPlanDetails?.let { installment ->
                    // Handle installment subscription display
                    val commitments = installment.installmentPlanCommitment
                }
            }
        }
    }
}

// Launch purchase flow
fun launchPurchase(activity: Activity, productDetails: ProductDetails, offerToken: String) {
    val flowParams = BillingFlowParams.newBuilder()
        .setProductDetailsParamsList(
            listOf(
                BillingFlowParams.ProductDetailsParams.newBuilder()
                    .setProductDetails(productDetails)
                    .setOfferToken(offerToken)
                    .build()
            )
        )
        .build()

    billingClient.launchBillingFlow(activity, flowParams)
}

Google Play Commission Rates 2025

ScenarioRate
First $1 M annual revenue15 %
Subscriptions after first year15 %
First‑year subscriptions (standard)30 %

2. 2025 Policy Update: Alternative Billing in the US

Major Change (October 2025)

Following the Epic Games ruling, Google now allows US developers to offer alternative payment methods:

  • No requirement to use Google Play Billing exclusively
  • Developers may communicate with users about alternative payment options
  • No price restrictions based on the payment method used
  • Payments can be processed through Stripe, PayPal, or custom solutions

External Offers Program (EEA)

For the European Economic Area, developers can lead users outside the app to promote offers, subject to Google Play’s Payments policy.

// User Choice Billing implementation
val billingClient = BillingClient.newBuilder(context)
    .enableUserChoiceBilling(UserChoiceBillingListener { userChoiceDetails ->
        // User selected alternative billing
        val externalTransactionToken = userChoiceDetails.externalTransactionToken
        // Process with your payment provider
        processAlternativePayment(externalTransactionToken)
    })
    .build()

3. Third‑Party Subscription Platforms

RevenueCat

The most popular cross‑platform subscription management SDK.

// Setup
Purchases.configure(
    PurchasesConfiguration.Builder(context, "your_api_key")
        .appUserID(userId)
        .build()
)

// Fetch offerings
Purchases.sharedInstance.getOfferingsWith(
    onError = { error -> /* Handle error */ },
    onSuccess = { offerings ->
        offerings.current?.availablePackages?.let { packages ->
            // Display subscription options
        }
    }
)

// Make purchase
Purchases.sharedInstance.purchase(
    PurchaseParams.Builder(activity, packageToPurchase).build(),
    onError = { error, userCancelled -> },
    onSuccess = { storeTransaction, customerInfo ->
        if (customerInfo.entitlements["premium"]?.isActive == true) {
            // Unlock premium features
        }
    }
)

// Check subscription status
Purchases.sharedInstance.getCustomerInfo(
    onError = { /* Handle */ },
    onSuccess = { customerInfo ->
        val isPremium = customerInfo.entitlements["premium"]?.isActive == true
    }
)

Pricing: Free up to $2,500 MTR, then 1 % of MTR.

Adapty

Strong alternative with superior A/B testing capabilities.

Advantages over RevenueCat

  • More sophisticated multivariate paywall testing
  • More analytics metrics on free plan
  • Real‑time dashboard data
  • Faster customer‑support response times
  • No‑code paywall builder with granular control

Pricing: Starts at $99 per month.

Comparison Table

FeatureRevenueCatAdapty
SDK PlatformsiOS, Android, Flutter, RN, Unity, Cordova, IoniciOS, Android, Flutter, RN, Unity
Free Tier Analytics6 metrics10+ metrics
Real‑time DataNoYes
A/B TestingBasicAdvanced multivariate
Paywall BuilderNative (Paywalls v2)No‑code drag‑drop
Starting PriceFree / $8 mo$99 /mo

4. Backend Architecture with Supabase

Supabase provides an excellent open‑source backend for SaaS apps with PostgreSQL, authentication, and real‑time capabilities.

Database Schema for Subscriptions

-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Users table
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    email TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);

-- Subscriptions table
CREATE TABLE subscriptions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    product_id TEXT NOT NULL,
    purchase_token TEXT NOT NULL,
    status TEXT NOT NULL CHECK (status IN ('active','canceled','past_due','expired')),
    period_start TIMESTAMP WITH TIME ZONE NOT NULL,
    period_end TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);

-- Indexes for fast lookup
CREATE INDEX idx_subscriptions_user_id ON subscriptions(user_id);
CREATE INDEX idx_subscriptions_status ON subscriptions(status);

Use Supabase’s Row‑Level Security (RLS) policies to ensure that users can only read/write their own subscription records, and integrate webhook listeners to handle Google Play purchase notifications for real‑time status updates.

Back to Blog

Related posts

Read more »

Profile

Current Status 🟢 Open for Internship & Entry Level Opportunities Mission Building 30 Apps in 52 Weeks to become a World‑Class Android Engineer. I am a passion...