如何在 Google Play Store 中更改订阅频率?
结论
在应用内实现订阅升级或降级,并不会让 Google Play 的“管理订阅”页面自动出现“更改方案/更改频率”选项。Billing API 和 Play Store 的订阅管理界面是两个独立入口,Play Store 不会分析应用代码,也不会据此判断哪些订阅可以互相切换。
按照目前的 Google Play 订阅模型,如果月付和年付对应同一项会员服务,通常应将它们配置为同一个订阅产品下的两个自动续订基础方案(base plans)。基础方案发布后,还要满足地区、价格和用户资格等条件,Google Play 才可能在“管理订阅”页面为符合条件的用户显示切换入口。
是否显示该入口,最终由 Google Play 决定,开发者无法强制开启。因此,应用内仍需实现方案切换,不能完全依赖 Play Store 的管理页面。
推荐的订阅配置
如果月付和年付只是同一项会员服务的不同计费周期,建议采用以下结构:
Subscription product: premium_membership
├── Base plan: monthly
│ └── Billing period: P1M
└── Base plan: yearly
└── Billing period: P1Y
需要在 Play Console 中确认:
- 月付和年付属于同一个订阅产品,而非两个相互独立的订阅产品。
- 两个基础方案都已激活。
- 两个方案在目标国家或地区均可购买,并且配置了有效价格。
- 用户当前使用的应用版本可以识别这些基础方案。
- 服务端可以处理基础方案变更后的购买状态。
如果项目仍使用旧式的独立订阅 SKU,迁移时要格外谨慎。对于仍有存量订阅用户的旧产品,不要直接删除或停用。应先确认 Google Play Console 当前支持的迁移和兼容方式。
在应用内切换订阅
在应用内切换方案时,需要查询目标基础方案的 ProductDetails,取得相应的 offerToken,再将用户当前订阅的 purchaseToken 作为旧订阅令牌传入 SubscriptionUpdateParams。
下面是简化后的 Kotlin 示例:
fun launchPlanChange(
activity: Activity,
billingClient: BillingClient,
targetProductDetails: ProductDetails,
targetOfferToken: String,
currentPurchaseToken: String
) {
val productDetailsParams =
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(targetProductDetails)
.setOfferToken(targetOfferToken)
.build()
val updateParams =
BillingFlowParams.SubscriptionUpdateParams.newBuilder()
.setOldPurchaseToken(currentPurchaseToken)
.setSubscriptionReplacementMode(
BillingFlowParams.SubscriptionUpdateParams.ReplacementMode
.CHARGE_PRORATED_PRICE
)
.build()
val billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(productDetailsParams))
.setSubscriptionUpdateParams(updateParams)
.build()
val result = billingClient.launchBillingFlow(
activity,
billingFlowParams
)
if (result.responseCode != BillingClient.BillingResponseCode.OK) {
// 记录错误,并根据 responseCode 向用户显示合适的提示
}
}
示例中的 CHARGE_PRORATED_PRICE 只是其中一种替换方式,不能不加判断地用于所有场景。月付转年付、年付转月付,以及立即生效或下个周期生效,可能需要使用不同的 ReplacementMode。具体模式应根据产品规则选择,同时要在购买确认页面清楚显示扣款金额和生效时间。
选择月付或年付时,也不能依赖基础方案在数组中的位置。应通过 basePlanId、标签或后端下发的配置来识别目标方案。
Play Store 中是否会显示切换入口
订阅结构和用户状态符合要求时,Google Play 可能在以下位置显示方案切换入口:
Google Play
→ 个人资料
→ 付款和订阅
→ 订阅
→ 选择对应订阅
→ 管理
以下情况可能导致该入口不显示:
- 月付和年付被创建为两个互不关联的订阅产品;
- 目标基础方案尚未激活,或未在用户所在地区销售;
- 当前订阅处于暂停、宽限期、账号保留、取消待到期等特殊状态;
- 目标方案或优惠不适用于该用户;
- 用户的订阅不是通过 Google Play 建立的;
- Google Play 客户端、账号类型或商店界面暂不支持该入口;
- Play Console 中的订阅配置尚未完成发布,或仍在传播中。
因此,不能只根据“管理订阅”页面是否出现按钮来判断应用功能是否正确。
可以提供 Play Store 管理入口
应用可以提供一个按钮,将用户引导至 Google Play 的订阅管理页面:
val uri = Uri.parse(
"https://play.google.com/store/account/subscriptions" +
"?sku=premium_membership" +
"&package=com.example.app"
)
val intent = Intent(Intent.ACTION_VIEW, uri)
activity.startActivity(intent)
这里的 sku 通常填写订阅产品 ID,而不是自行拼接的基础方案 ID。该链接只能打开管理页面,不能保证页面中一定会显示方案切换功能,也不能替代应用内的 launchBillingFlow()。
服务端处理不能遗漏
无论用户是在应用内切换方案,还是通过 Google Play 管理页面操作,服务端都必须以 Google Play 返回的购买状态为准:
- 使用 Google Play Developer API 校验购买;
- 处理 Real-time Developer Notifications;
- 保存当前订阅产品、基础方案和到期时间;
- 正确处理新的购买令牌及可能存在的关联令牌;
- 对需要确认的购买及时执行 acknowledgement;
- 以幂等方式处理续订、取消、暂停、恢复和方案切换。
不要只通过客户端回调更新会员权益。用户从 Play Store 操作时,应用可能并未运行,客户端也不一定能立即收到回调。
实施建议
可以按以下方式实施:
- 将月付和年付配置为同一个订阅产品下的两个基础方案。
- 在应用内使用 Google Play Billing Library 实现清晰的月付和年付切换流程。
- 在设置页面提供跳转至 Google Play 订阅管理页的入口。
- 将 Play Store 自行显示的“更改方案”作为补充渠道,而非唯一渠道。
- 使用测试账号分别验证月转年、年转月、取消后切换及特殊付款状态。
Google Play Console 和 Billing Library 的界面及规则会不断调整。如果控制台中没有单独的“允许更改频率”开关,通常不代表遗漏了开发步骤。需要重点检查的是订阅产品与基础方案的建模是否正确。至于切换入口是否显示,则由 Google Play 根据用户资格和商店能力决定。
备注:内容仅供参考。
