如何取消 Google In App Purchases 自动续订
结论
用户订阅成功后,服务端可以立即关闭自动续订。只要执行的是“停止后续续费”,而不是退款或撤销购买,订阅权益通常会保留到当前计费周期结束,不需要另外设置定时任务。
以下几种操作需要分清:
cancel:停止下一周期续费,当前周期一般仍然有效。revoke:立即终止订阅权益。refund:退款不一定会立即撤销权益,结果取决于具体调用方式。- 因付款失败被系统取消:可能涉及宽限期、账号保留期等状态,不能按照用户主动取消来处理。
通过服务端 API 取消订阅,也不代表 cancelReason = 1。cancelReason = 1 表示 Google Play 因计费等问题执行的系统取消。开发者主动取消在较新的状态模型中有单独的表示方式。旧版接口与新版 subscriptionsv2 的字段并不完全一致,因此不能只根据 cancelReason 判断权益是否有效。
推荐实现方式
订阅完成后,服务端可以按以下顺序处理:
- 接收客户端提交的
purchaseToken。 - 调用 Google Play Developer API 验证购买结果。
- 确认订单、商品与用户相匹配。
- 对订阅执行 acknowledge。
- 为用户开通权益。
- 调用取消接口,关闭后续自动续订。
- 保存 Google Play 返回的到期时间。
- 到期前继续允许用户使用,到期后再关闭权益。
acknowledge 不能省略。如果没有在 Google Play 规定的期限内确认购买,订单可能被自动退款并撤销。
使用新版 SubscriptionsV2 API
如果当前接入版本支持 purchases.subscriptionsv2.cancel,应明确指定停止续费类型:
POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.app/purchases/subscriptionsv2/tokens/PURCHASE_TOKEN:cancel
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"cancellationContext": {
"cancellationType": "USER_REQUESTED_STOP_RENEWALS"
}
}
USER_REQUESTED_STOP_RENEWALS 表示停止后续续费。用户通常仍可使用已经付费的当前周期。
不要误用:
DEVELOPER_REQUESTED_STOP_PAYMENTS
该类型表示开发者要求停止付款,可能立即终止订阅,不适合“购买一个周期后自然到期”的场景。具体行为应以项目当前使用的 Google Play Developer API 版本说明为准。
旧版取消接口示例
使用旧版 purchases.subscriptions.cancel 时,请求形式类似:
curl -X POST \
-H "Authorization: Bearer ACCESS_TOKEN" \
"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.app/purchases/subscriptions/monthly_plan/tokens/PURCHASE_TOKEN:cancel"
该操作用于停止自动续订,无法通过客户端 Billing Library 代替。访问凭据和取消操作都必须放在可信的服务端。
旧版查询结果可能包含:
{
"autoRenewing": false,
"expiryTimeMillis": "1735689600000",
"cancelReason": 3
}
不同接口版本的取消原因枚举可能不同。例如,较新的旧版订阅资源可能使用 3 表示开发者取消,而最早的文档只列出 0、1 和 2。解析时应以实际调用接口的 schema 为准,不能因为取消由服务端发起,就直接推断为系统因计费问题取消。
权益判断方式
取消成功不等于权益立即失效。服务端需要结合订阅状态和到期时间进行判断:
boolean entitlementActive =
expiryTimeMillis > System.currentTimeMillis()
&& !isRevoked;
实际项目还需要处理宽限期、账号保留期、暂停、退款和撤销等状态。不能仅凭 autoRenewing == false 关闭权限。该字段只表示订阅不会再次续费,不代表当前周期已经到期。
建议保存以下信息:
purchaseToken
productId / basePlanId
latestOrderId
subscriptionState
autoRenewing
expiryTime
cancellationType
acknowledgementState
同时订阅 Real-time Developer Notifications。收到通知后,应重新查询 Google Play,不要完全依赖本地定时器或客户端上报。
更合适的商品模型
如果业务模式本来就是“购买固定时长,到期后由用户手动再次购买”,可以先检查 Google Play Console 是否支持为该商品配置 prepaid plan。预付费方案不会自动续订,比购买后立即取消更符合商品本身的含义,也能减少状态同步工作和客服解释成本。
如果目标地区、商品配置或当前接入能力不支持 prepaid plan,再采用确认购买后立即停止续费的方案。界面上需要明确告知用户,本次购买只包含一个周期,不会自动续订。
注意事项
- 取消操作必须由服务端完成,不能将服务账号凭据放入 APK。
- 应先验证购买并执行 acknowledge,再取消自动续订。
- 不要通过
revoke实现自然到期,否则权益可能立即终止。 - 取消请求应支持幂等,避免网络重试引发错误处理。
purchaseToken可能因订阅升级、降级或替换而变化,需要处理关联购买。- 权益的最终状态应以 Google Play API 查询结果和实时通知为准。
- 上线前应使用许可测试账号,验证取消、到期、退款和重新订阅流程。测试订阅的周期长度及状态变化可能与正式环境不同。
备注:内容仅供参考。