PAYATHON 2026

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 个月方案。

服务端处理步骤

购买完成后,不要只根据客户端回调开通服务。可以按以下流程处理:

  1. 客户端将 purchaseToken 和商品 ID 发送到服务端。
  2. 服务端通过 Google Play Developer API 验证购买状态。
  3. 根据 Google Play 返回的到期时间授予用户权益。
  4. 确认购买,避免订单因未确认而退款。
  5. 通过 Real-time Developer Notifications 接收续订、到期、退款和撤销等状态变化。
  6. 用户再次购买预付方案后,重新查询订阅状态并更新权益期限。

服务端通常需要保存以下核心数据:

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 的订阅基础方案实现。需要用户每次主动付款时,使用预付费方案更合适;需要系统定期自动扣款时,则使用自动续订方案。

备注:内容仅供参考。