如何通过 Google Api 测试 In App Billing v3 订阅取消?
结论
可以使用 Google Play 许可测试账号测试取消订阅。先用测试账号购买订阅,再前往 Google Play 的“付款和订阅”页面手动取消,最后由服务器重新查询该 purchaseToken 的订阅状态。
需要注意,取消订阅不会让订阅立即失效。用户取消后,通常仍可使用订阅权益,直到当前计费周期结束。此时常见的状态是:
- 自动续订已关闭;
- 订阅权益暂时有效;
- 到达过期时间后,订阅才会失效。
服务器不能只在购买时验证一次订阅状态。应通过 Real-time Developer Notifications 接收状态变更通知,并定期调用 Google Play Developer API 进行校验。
如何执行取消测试
1. 配置测试账号
在 Google Play Console 中,将测试用的 Google 账号配置为许可测试账号,并确保该账号可以安装测试轨道中的应用。
测试前需要确认:
- Play 商店登录的是测试账号;
- 安装包来自 Google Play 测试轨道;
- 应用包名和签名与 Play Console 中的版本一致;
- 订阅商品已经启用,并对相应测试轨道开放。
许可测试订阅通常采用加速后的续订周期,便于测试续订和过期。具体周期和续订次数可能随 Google Play 的测试规则调整,因此不要将其写死在业务代码中。
2. 购买测试订阅
购买成功后,应用需要将以下信息发送给自己的服务器:
{
"packageName": "com.example.app",
"subscriptionId": "premium_monthly",
"purchaseToken": "purchase-token-from-google-play"
}
服务器使用 purchaseToken 查询这笔订阅。不要只保存订单号,因为在续订、升级和替换订阅时,订单与购买令牌的含义并不相同。
3. 在 Google Play 中取消
使用购买订阅的测试账号打开:
Google Play → 头像 → 付款和订阅 → 订阅
选择对应应用的订阅,然后点击“取消订阅”。
也可以在浏览器中打开该 Google 账号的 Google Play 订阅管理页面进行取消。取消后不要立即删除用户权益,因为当前计费周期通常尚未结束。
服务器如何验证取消状态
如果后端仍在使用旧版订阅查询接口,可以发送以下请求:
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{purchaseToken}
例如:
curl \
-H "Authorization: Bearer ACCESS_TOKEN" \
"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.app/purchases/subscriptions/premium_monthly/tokens/PURCHASE_TOKEN"
旧版接口的响应中常见以下字段:
{
"startTimeMillis": "1710000000000",
"expiryTimeMillis": "1710003600000",
"autoRenewing": false,
"cancelReason": 0,
"userCancellationTimeMillis": "1710001800000"
}
这些字段的含义如下:
autoRenewing: false:订阅不会继续自动续订,通常表示用户已经取消订阅,或自动续订已被关闭;expiryTimeMillis:当前订阅权益预计失效的时间;cancelReason:取消原因,只能在接口实际返回该字段时使用;userCancellationTimeMillis:用户执行取消操作的时间,该字段不一定会出现在所有状态下。
判断用户是否仍有订阅权益时,不能只检查 autoRenewing:
function evaluateLegacySubscription(subscription, now = Date.now()) {
const expiryTime = Number(subscription.expiryTimeMillis);
return {
entitled: expiryTime > now,
autoRenewing: subscription.autoRenewing === true,
canceled:
subscription.autoRenewing === false &&
subscription.userCancellationTimeMillis != null
};
}
用户刚取消订阅时,结果可能是:
entitled = true
autoRenewing = false
canceled = true
计费周期结束后,结果才会变为:
entitled = false
autoRenewing = false
使用当前订阅状态接口
新接入或正在升级的系统,应优先评估 Google Play Developer API 的 purchases.subscriptionsv2.get:
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptionsv2/tokens/{purchaseToken}
示例:
curl \
-H "Authorization: Bearer ACCESS_TOKEN" \
"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.app/purchases/subscriptionsv2/tokens/PURCHASE_TOKEN"
该接口会返回订阅级状态和 lineItems。判断订阅权益时,至少需要结合以下信息:
subscriptionState;lineItems[].expiryTime;- 自动续订计划相关字段;
- 是否处于暂停、宽限期、账号保留或待处理状态。
不要看到状态名称中包含 CANCELED 就直接撤销服务。订阅即使已经取消,只要尚未过期,仍应根据有效期和具体状态判断是否保留权益。
推荐的完整处理方式
只依赖客户端在取消后主动通知服务器并不可靠。用户可能直接在 Play 商店取消订阅,而应用之后可能没有再次启动。可以按以下流程处理:
- 购买成功后,客户端将
purchaseToken发送给服务器。 - 服务器调用 Google Play Developer API 验证购买。
- 服务器保存用户、商品与
purchaseToken的对应关系。 - 配置 Real-time Developer Notifications,接收取消、续订、过期和暂停等事件。
- 收到通知后,服务器使用通知关联的购买令牌再次查询 Developer API。
- 服务器根据查询结果更新权益,不能完全依赖通知内容。
- 定期校验未收到通知或通知处理失败的记录。
通知只负责告诉服务器“订阅状态发生了变化”。服务器更新状态时,应以 Google Play Developer API 的查询结果为依据。
测试时应验证的状态
测试范围不应只有“购买成功”和“用户取消”,至少还应覆盖:
- 首次购买并确认;
- 正常自动续订;
- 用户取消但订阅尚未过期;
- 取消后恢复订阅;
- 到期后权益失效;
- 支付失败后的宽限期或账号保留状态;
- 退款或撤销;
- 升级、降级或替换订阅。
如果只测试取消流程,最重要的断言是:取消后自动续订关闭,但订阅权益一直保留到有效期结束。订阅过期后,服务器才拒绝提供订阅服务。
In-app Billing v3 是较早期的客户端接口。如果项目仍在直接使用它,建议规划迁移到当前版本的 Google Play Billing Library。无论客户端使用哪个版本,服务器都应通过 Google Play Developer API 验证订阅的最终状态。
备注:内容仅供参考。
