Flutter + Revenue Cat 提示用户不允许购买
结论
Android 内购不要求应用正式发布到 Production。通过 Google Play 的 Internal testing、Closed testing 或 Open testing 分发的版本也可以完成购买,前提是安装来源、测试资格、Google 账号、商品地区和付款资料都符合要求。
PurchaseNotAllowedError 通常不代表 RevenueCat 商品 ID 同步失败。它表示 Google Play Billing 判定当前设备或 Google 账号不具备购买资格。RevenueCat 只是把 Google Play 返回的错误包装为:
PurchaseNotAllowedError
如果过去一个月几乎所有 Android 付款都失败,应先排查测试版本的安装渠道、测试人员资格、Play 国家或地区以及 Google Payments Profile,不必反复调整 RevenueCat Offering。
为什么会出现这个错误
Google Play Billing 返回的“设备或用户不允许购买”涵盖的情况较多,常见原因有:
- 应用不是从 Google Play 测试轨道安装,而是通过 APK、ADB 或其他渠道安装。
- 用户没有加入相应的 Internal、Closed 或 Open testing,或者加入测试后仍在使用旧版本。
- 设备上登录了多个 Google 账号,而 Play Store 下载应用时使用的并非测试账号。
- Google Play 账号的国家或地区不在商品开放范围内。
- Google Payments Profile 被暂停、需要重新验证,或者没有适用于当前地区的付款方式。
- 用户使用的是受监管账号,例如儿童账号、Family Link 账号或企业托管账号。
- Play Store、Google Play Services 或设备认证状态异常。
- 商品虽然是 Active 状态,却没有向当前测试轨道、国家或用户群开放。
- 当前应用的
applicationId、签名或安装包与 Play Console 中的应用不一致。
如果 RevenueCat 中的商品 ID 配置有误,通常会表现为商品无法加载、Offering 为空或找不到产品,而不是明确返回 PurchaseNotAllowedError。
建议按以下顺序排查
1. 确认应用来自 Google Play
测试真实购买时,不要使用本地构建的 APK,也不要使用通过 flutter run 安装的版本。测试人员需要:
- 通过测试邀请链接加入相应的测试轨道。
- 在 Google Play 中确认自己已经成为测试人员。
- 卸载设备上原有的应用。
- 使用加入测试的同一个 Google 账号,从 Google Play 重新安装应用。
即使本地 APK 的包名和版本号相同,也不能说明它的购买环境与 Play 分发版本相同。
2. 检查设备上的 Google 账号
设备上有多个 Google 账号时,Play Billing 实际使用的账号可能和预期不同。可以找一台干净的测试设备进行验证,并确保:
- Play Store 中只保留一个 Google 账号。
- 该账号已经加入测试轨道。
- 该账号可以正常打开 Google Play 的付款方式页面。
- 应用由该账号从 Play Store 下载。
- 账号不受 Family Link、企业策略或年龄限制约束。
如果更换账号后购买立即恢复,问题通常出在账号资格或 Payments Profile,而不是 Flutter 代码。
3. 核对国家和地区
如果应用主要在 Singapore 使用,需要分别确认:
- Play Console 中的应用和商品是否向 Singapore 开放。
- 测试用户的 Google Play country 是否属于受支持地区。
- Google Payments Profile 的国家是否与实际付款方式匹配。
- 用户近期是否迁移过国家、使用跨区账号或通过 VPN 访问 Play Store。
设备当前位于 Singapore,不等于 Google Play 账号所属国家就是 Singapore。Google Play 主要根据账号和 Payments Profile 判断购买资格。
4. 检查 Payments Profile
“开发者账号可以接收付款”和“消费者账号可以完成付款”属于两套不同的配置。
开发者的 Merchant/Payments Profile 正常,只能说明应用具备收款条件。每位购买用户仍需拥有可用的消费者付款资料。可以让购买失败的用户在 Play Store 中:
- 打开“Payments & subscriptions”。
- 查看付款方式是否过期或被拒绝。
- 检查是否有身份、地址或付款资料验证提示。
- 尝试购买其他 Google Play 商品。
如果同一账号购买其他应用或商品也失败,需要交由 Google Payments 支持继续处理。
5. 使用 License testing 隔离付款方式问题
在 Play Console 中配置 License testing,并用明确加入测试名单的账号进行测试。这样有助于判断问题来自应用集成,还是实际付款方式和风控。
License tester 与测试轨道中的测试人员不是同一个概念。账号通常既要能够访问相应的测试版本,也要根据测试目标正确配置 License testing。
6. 创建最小化测试矩阵
至少使用以下组合进行交叉验证:
| 安装来源 | Google 账号 | 网络/地区 | 结果 |
|---|---|---|---|
| Play 测试轨道 | 新测试账号 | Singapore | 记录结果 |
| Play 测试轨道 | 原失败账号 | Singapore | 记录结果 |
| Play 测试轨道 | 新测试账号 | 另一台设备 | 记录结果 |
如果新账号可以购买,原账号不行,应重点检查原账号的资格和付款资料。如果所有账号和设备都失败,再检查 Play Console 中的测试轨道、地区、商品和应用发布配置。
Flutter 中的错误处理
客户端无法绕过 Google Play 对购买资格的判定。应用应识别相应错误,停止自动重试,并向用户提供具体的排查提示:
import 'package:flutter/services.dart';
import 'package:purchases_flutter/purchases_flutter.dart';
Future<void> purchasePackage(Package package) async {
try {
final result = await Purchases.purchasePackage(package);
// 根据当前 purchases_flutter 版本读取 CustomerInfo,
// 并在服务端或客户端确认 entitlement 是否已生效。
final customerInfo = result.customerInfo;
final isActive =
customerInfo.entitlements.active.containsKey('premium');
if (!isActive) {
throw StateError('Purchase completed but entitlement is not active.');
}
} on PlatformException catch (e) {
final errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.purchaseNotAllowedError) {
// 不要循环重试。提示用户检查 Play Store 账号、地区和付款资料。
throw StateError(
'Google Play 不允许当前账号完成购买。'
'请确认应用来自 Google Play、账号已加入测试,'
'并检查 Play Store 的国家/地区和付款方式。',
);
}
if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
return;
}
rethrow;
}
}
不同版本的 purchases_flutter 可能会调整返回对象的结构,应以项目锁定版本的 API 为准。错误处理原则不变:识别 purchaseNotAllowedError,不要将其视为用户取消,也不要试图通过反复调用购买接口来绕过限制。
诊断时应记录什么
为了便于 RevenueCat 或 Google 支持定位问题,可以记录以下非敏感信息:
- 应用版本、
versionCode和包名。 - 应用是否从 Google Play 安装。
- 应用所属的测试轨道。
- RevenueCat App User ID。
- RevenueCat 请求时间和相关日志。
- 商品 ID 与商品类型。
- 设备型号、Android 版本和 Play Store 版本。
- Google Play 账号国家以及测试资格。
- 错误码、
readableErrorCode和underlyingErrorMessage。
不要记录银行卡号、完整付款资料、Google 密码或其他认证信息。
注意事项
一次购买成功,只能证明当时使用的账号、设备和商品配置有效,不能说明后续所有用户都具备购买资格。测试轨道、账号地区、付款资料和 Google 风控状态都可能发生变化。
如果失败集中在特定账号或地区,通常需要排查 Google Play 用户资格或支付环境。如果所有测试账号和设备都同时失败,应重点检查测试轨道、商品地区、安装来源、包名和签名。只有当 RevenueCat Dashboard 中出现商品无法加载、产品映射错误或 entitlement 未激活时,才需要把排查重点转到 RevenueCat 配置。
备注:内容仅供参考。
