Android 是否有支持每两个月付费的订阅 API?
结论
可以实现,但 Android 系统没有提供通用的“每两个月收费”API。
如果应用通过 Google Play 分发,应使用 Google Play Billing 的订阅功能。对于“预付 2 个月或 4 个月,到期后由用户再次付款续订”的模式,可以优先配置 预付费订阅方案(prepaid plan)。如果需要到期后自动扣款,则配置 自动续订方案(auto-renewing plan)。
能否选择 2 个月或 4 个月作为计费周期,要看 Google Play Console 当前对目标地区、商品类型和基础方案开放了哪些周期选项。请以控制台中的实际选项为准,不要只在客户端计算到期时间,以此绕过 Play Billing。
推荐实现方式
在 Google Play Console 中创建订阅商品,再按业务需求配置基础方案:
- 2 个月预付方案:用户付款后获得 2 个月服务,到期后主动续订。
- 4 个月预付方案:用户付款后获得 4 个月服务。
- 自动续订方案:计费周期结束后,Google Play 自动尝试扣款。
- 如果控制台没有所需周期,可以选择允许的相近周期,也可以设计为一次性商品。使用一次性商品时,需要自行管理权益期限,并遵守 Google Play 的支付政策。
客户端负责展示商品和启动购买流程。订阅是否有效、何时到期等权益判断,最好由服务端查询 Google Play Developer API 后完成。
客户端接入示例
以下示例使用 Google Play Billing Library 的 Kotlin API。依赖版本应采用接入时官方文档要求的稳定版本,因此这里不固定版本号。
val billingClient = BillingClient.newBuilder(context)
.setListener { billingResult, purchases ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
purchases.orEmpty().forEach { purchase ->
sendPurchaseTokenToServer(
productId = purchase.products.firstOrNull().orEmpty(),
purchaseToken = purchase.purchaseToken
)
}
}
}
.enablePendingPurchases()
.build()
连接 Google Play:
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(result: BillingResult) {
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
querySubscription()
}
}
override fun onBillingServiceDisconnected() {
// 网络恢复或应用回到前台后重试连接
}
})
查询订阅商品:
private fun querySubscription() {
val product = QueryProductDetailsParams.Product.newBuilder()
.setProductId("service_subscription")
.setProductType(BillingClient.ProductType.SUBS)
.build()
val params = QueryProductDetailsParams.newBuilder()
.setProductList(listOf(product))
.build()
billingClient.queryProductDetailsAsync(params) { result, productDetailsList ->
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
val details = productDetailsList.firstOrNull() ?: return@queryProductDetailsAsync
showSubscriptionOptions(details)
}
}
}
启动购买流程时,需要传入目标方案对应的 offerToken:
private fun launchSubscriptionPurchase(
activity: Activity,
productDetails: ProductDetails,
offerToken: String
) {
val productParams =
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setOfferToken(offerToken)
.build()
val billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(productParams))
.build()
billingClient.launchBillingFlow(activity, billingFlowParams)
}
不要硬编码 offerToken。它来自 ProductDetails.subscriptionOfferDetails。应用可以根据其中的基础方案、优惠标识和计费阶段,选择 2 个月或 4 个月方案。
服务端处理步骤
购买完成后,不要只根据客户端回调开通服务。可以按以下流程处理:
- 客户端将
purchaseToken和商品 ID 发送到服务端。 - 服务端通过 Google Play Developer API 验证购买状态。
- 根据 Google Play 返回的到期时间授予用户权益。
- 确认购买,避免订单因未确认而退款。
- 通过 Real-time Developer Notifications 接收续订、到期、退款和撤销等状态变化。
- 用户再次购买预付方案后,重新查询订阅状态并更新权益期限。
服务端通常需要保存以下核心数据:
user_id
product_id
purchase_token
subscription_status
expiry_time
last_verified_at
注意事项
- 预付费与自动续订不同:预付费方案到期后,通常需要用户主动购买或续订;自动续订方案会按周期扣款。
- 不要自行认定付款成功:
BillingResponseCode.OK只表示购买流程成功返回,最终是否授予权益应以服务端验证结果为准。 - 处理待处理交易:部分支付方式不会立即完成付款。在状态变为
PURCHASED前,不要提供完整权益。 - 及时确认购买:验证购买成功后,需要执行 acknowledge。可以由客户端或服务端完成,但同一订单只需成功确认一次。
- 不要用固定天数替代自然月:2 个月不一定等于 60 天。订阅到期时间应使用 Google Play 返回的数据。
- 测试恢复购买:应用启动或用户登录后,应查询现有订阅,以处理换机、重装和购买回调丢失等情况。
- 遵守支付政策:如果应用内销售数字服务,并通过 Google Play 分发,通常需要使用 Google Play Billing。具体适用范围和例外,以应用发布时的最新政策为准。
这类需求可以通过 Google Play Billing 的订阅基础方案实现。需要用户每次主动付款时,使用预付费方案更合适;需要系统定期自动扣款时,则使用自动续订方案。
备注:内容仅供参考。
