PAYATHON 2026

Android 服务端无法验证 in-app subscription

支付小周

结论

这个错误通常与应用是否处于 draft mode 无关。更常见的原因是,调用 Google Play Developer API 的身份无权访问该应用,或者请求中的 packageName 不属于当前开发者账号。

有效的 access_token 只能说明 OAuth 认证成功,不能证明对应身份拥有目标应用。即使 tokeninfo 中的 audience、issued_to 等字段与 client ID 一致,也只能证明令牌签发给了该 OAuth 客户端,无法证明授权用户拥有 Play Console 中的应用。

重点检查项

1. 确认 packageName 完全一致

API 请求中的包名必须与 Google Play Console 中登记的包名完全一致,包括大小写和后缀。例如:

com.example.myapp

不要传入:

  • 商品 ID 或订阅 ID;
  • application label;
  • 测试版本使用的其他 applicationId;
  • 带 .debug、.staging 等后缀的测试包名,除非 Play Console 登记的正是这个包名。

如果包名错误,Google 可能返回 developerDoesNotOwnApplication,因为当前调用身份确实不拥有请求指定的应用。

2. 确认 API 调用身份拥有应用权限

使用用户 OAuth 授权时,完成 consent flow 的 Google 账号必须是该 Play Console 开发者账号的所有者,或者已经获得目标应用以及订单、订阅相关权限。

使用服务账号时,需要:

  1. 在对应的 Google Cloud 项目中启用 Google Play Android Developer API。
  2. 创建服务账号。
  3. 将服务账号的邮箱添加到 Google Play Console 的用户和权限配置中。
  4. 授予该账号访问目标应用的权限,以及查看订单和管理订阅所需的权限。
  5. 使用该服务账号获取包含以下 scope 的令牌:
https://www.googleapis.com/auth/androidpublisher

仅在 Google Cloud 项目中创建服务账号或 OAuth client 还不够。Play Console 也必须明确授权这个身份访问应用。

Play Console 的菜单名称可能会随界面版本变化,但判断方式不变:调用 API 所使用的邮箱身份必须出现在开发者账号的权限配置中,而且有权访问目标应用。

3. 不要把 client ID 当作开发者身份

通过下面的接口验证,只能确认 token 可用,不能证明它有权访问应用:

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ACCESS_TOKEN

需要区分以下几项:

  • client_id、audience 或 issued_to 表示申请 token 的 OAuth 客户端;
  • 实际授权用户或服务账号决定其是否有权访问 Play Console 应用;
  • Play Console 权限决定该身份能否读取订阅和订单。

如果使用 OAuth 用户授权,可以撤销旧授权,再明确选择拥有该应用权限的 Google 账号,重新完成 authorization flow。浏览器同时登录多个账号时,很容易误用其他账号完成授权。

API 调用示例

当前订阅查询接口可以通过 purchaseToken 查询:

curl \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.myapp/purchases/subscriptionsv2/tokens/PURCHASE_TOKEN"

旧版订阅验证接口还需要传入订阅商品 ID:

curl \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.myapp/purchases/subscriptions/SUBSCRIPTION_ID/tokens/PURCHASE_TOKEN"

其中:

  • com.example.myapp 必须是 Play Console 中登记的真实包名;
  • SUBSCRIPTION_ID 必须是购买时使用的订阅商品 ID;
  • PURCHASE_TOKEN 应原样使用客户端返回的 token,不能传订单号;
  • ACCESS_TOKEN 必须由已经获得 Play Console 权限的身份签发。

服务端还需要校验接口响应中的订阅状态、商品信息、到期时间和购买确认状态,不能只因请求成功就判定订阅有效。

draft mode 与订单记录

应用处于 draft、内部测试或尚未公开发布状态时,安装渠道、测试账号和商品可见性可能会受到影响。但 developerDoesNotOwnApplication 指向的是应用所有权或授权问题,不能据此认定 Purchase Status API 不支持草稿应用。

客户端 getPurchases 能返回记录,只能说明当前 Google Play 账号在设备本地或 Play 服务端存在这笔购买,不能证明服务端使用的 API 身份有权读取该记录。

信用卡已经扣款,也不能排除授权问题。支付处理与 Developer API 权限验证是两套独立流程。

如果 Google Merchant Center 或相关订单页面暂时没有显示订单,也不应直接归因于 draft mode。还需要检查:

  • 当前登录的账号是否与 Play Console 付款资料关联;
  • 查看的是不是正确的商家付款资料;
  • 是否存在订单同步或报表延迟;
  • 交易是否仍处于授权、待处理或取消状态;
  • 购买时使用的是测试支付方式还是真实支付方式;
  • Google Play 收据中是否有以 GPA. 开头的订单号。

应优先修正 API 调用身份、Play Console 权限和 packageName。确认同一个授权身份能够访问目标应用后,再单独排查订单展示问题。

备注:内容仅供参考。