Android SaaS App 订阅版:完整2025指南

发布: (2025年12月13日 GMT+8 21:08)
6 min read
原文: Dev.to

Source: Dev.to

市场背景 2025

全球 SaaS 市场规模预计在 2025 年为 4082.1 亿美元,预计到 2034 年将达到 1,2513.5 亿美元
订阅计费管理市场预计在 2030 年达到 179.5 亿美元,复合年增长率为 16.9%。

1. Google Play 计费库

当前版本

  • Play Billing Library 7.x(2025 年 8 月前必需)
  • 重要截止日期:截至 2025 年 8 月 31 日,所有新应用和更新必须使用 Billing Library 7 或更高版本。扩展可使用至 2025 年 11 月 1 日。

版本 7.0+ 的关键特性

  • 分期订阅 – 用户以更小、更易管理的分期付款方式支付(在巴西、法国、意大利、西班牙可用)
  • 订阅待处理交易 – 在激活前处理 SUBSCRIPTION_STATE_PENDING
  • ReplacementMode API – 替代已弃用的 ProrationMode 用于升级/降级
  • 用户选择计费enableUserChoiceBilling() 用于替代支付选项

实现

// 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 2025 年佣金费率

场景费率
首个 100 万美元年收入15 %
首年后的订阅15 %
首年订阅(标准)30 %

2. 2025 政策更新:美国的替代计费

重大变更(2025 年 10 月)

根据 Epic Games 判决,Google 现在允许美国开发者提供替代支付方式

  • 不再强制仅使用 Google Play 计费
  • 开发者可以向用户传达替代支付选项
  • 对使用的支付方式不设价格限制
  • 支付可通过 Stripe、PayPal 或自定义方案处理

外部优惠计划(EEA)

对于欧洲经济区,开发者可在应用外引导用户推广优惠,需遵守 Google Play 支付政策。

// 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. 第三方订阅平台

RevenueCat

最受欢迎的跨平台订阅管理 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
    }
)

定价:免费至 2,500 美元 MTR,之后收取 MTR 的 1%。

Adapty

强大的替代方案,具备更出色的 A/B 测试功能。

相较于 RevenueCat 的优势

  • 更复杂的多变量付费墙测试
  • 免费计划提供更多分析指标
  • 实时仪表盘数据
  • 更快的客户支持响应时间
  • 零代码付费墙构建器,具细粒度控制

定价:每月 99 美元起。

对比表

功能RevenueCatAdapty
SDK 平台iOS, Android, Flutter, RN, Unity, Cordova, IoniciOS, Android, Flutter, RN, Unity
免费层分析6 metrics10+ metrics
实时数据NoYes
A/B 测试BasicAdvanced multivariate
付费墙构建器Native (Paywalls v2)No‑code drag‑drop
起始价格Free / $8 mo$99 /mo

4. 使用 Supabase 的后端架构

Supabase 为 SaaS 应用提供了优秀的开源后端,具备 PostgreSQL、身份验证和实时功能。

订阅的数据库模式

-- 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);

使用 Supabase 的行级安全(RLS)策略,确保用户只能读取/写入自己的订阅记录,并集成 webhook 监听器以处理 Google Play 购买通知,实现实时状态更新。

Back to Blog

相关文章

阅读更多 »

个人资料

当前状态 🟢 开放实习和入门级机会 使命:在 52 周内构建 30 款 App,成为世界级 Android Engineer。 我充满热情……