Android SaaS App 订阅版:完整2025指南
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 美元起。
对比表
| 功能 | RevenueCat | Adapty |
|---|---|---|
| SDK 平台 | iOS, Android, Flutter, RN, Unity, Cordova, Ionic | iOS, Android, Flutter, RN, Unity |
| 免费层分析 | 6 metrics | 10+ metrics |
| 实时数据 | No | Yes |
| A/B 测试 | Basic | Advanced 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 购买通知,实现实时状态更新。