Flutter应用Google Play内购(IAP)正确设置测试步骤咨询及queryProductDetailsAsync响应码12问题求助
Flutter应用Google Play内购(IAP)正确设置测试步骤咨询及queryProductDetailsAsync响应码12问题求助
看到你遇到的Google Play内购问题,尤其是getSkuDetails() failed响应码12的报错,我之前踩过几乎一模一样的坑,咱们一步步拆解排查,先解决配置问题,再看代码细节。
先搞懂响应码12的本质
Google Play的响应码12本质是SKU查询时的身份验证/配置不匹配,不是代码语法错误,90%的概率是Play Console的配置和本地测试环境没对齐,咱们先从配置入手。
第一步:排查Play Console核心配置(最容易踩坑的点)
1. 应用必须发布到测试轨道,而非仅上传AAB
你提到已经上传了AAB,但如果只是上传到“草稿”或未发布到任何测试轨道,Google Play不会把内购商品和应用关联起来。必须:
- 进入Play Console → 你的应用 → 发布 → 内部测试/封闭测试轨道
- 上传AAB后创建版本,提交审核(内部测试审核很快,一般几分钟)
- 审核通过后发布测试版本,获取测试链接并让你的测试账号点击加入测试计划
2. 内购商品的状态和SKU必须完全正确
- 进入应用内商品页面,确认bronze/silver/gold都是**“激活”状态**(草稿状态的商品完全无法被查询到)
- 核对代码里的
play_product_id和控制台的SKU:大小写、拼写、空格必须完全一致(比如控制台是bronze_plan,代码里不能写成Bronze_Plan)
3. 测试账号和设备的权限必须配置到位
内购测试必须用许可测试账号,不能用普通账号:
- 进入Play Console → 应用内商品 → 测试标签
- 点击“添加许可测试人员”,输入你的测试Google账号邮箱
- 勾选“允许未经授权的购买测试(针对许可测试人员)”(可跳过签名匹配验证,方便debug测试)
- 测试设备必须登录这个许可测试账号,且退出其他所有Google账号
- 确保设备上的Google Play Store是最新版本(设置→关于Play Store→检查更新)
4. 应用签名的匹配(debug包测试必备)
如果用flutter run直接安装debug包测试,需要确保debug签名被Google Play识别:
- 获取本地debug keystore的SHA-1,执行命令:
# Mac/Linux keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android # Windows keytool -list -v -keystore C:\Users\<你的用户名>\.android\debug.keystore -alias androiddebugkey -storepass android -keypass android - 将获取到的SHA-1添加到Play Console → 你的应用 → 设置 → 应用签名 → 点击“添加上传证书”(若使用Google应用签名)
第二步:代码里的潜在问题优化
1. 必须监听购买流的回调
你当前代码仅调用了buyConsumable,但未监听purchaseStream,这会导致完全收不到购买结果回调(成功/失败/待处理),即使购买流程走通也没有反馈。建议在页面的initState里添加流监听:
StreamSubscription<List<PurchaseDetails>>? _purchaseSubscription; @override void initState() { super.initState(); // 初始化内购流监听 final purchaseStream = InAppPurchase.instance.purchaseStream; _purchaseSubscription = purchaseStream.listen((purchaseDetailsList) { _handlePurchaseUpdates(purchaseDetailsList); }, onError: (err) { print('购买流发生错误: $err'); }); } void _handlePurchaseUpdates(List<PurchaseDetails> purchaseDetailsList) { for (var purchase in purchaseDetailsList) { if (purchase.status == PurchaseStatus.pending) { print('购买待处理,请等待'); // 可显示加载弹窗 } else if (purchase.status == PurchaseStatus.error) { print('购买失败: ${purchase.error}'); eventBus.fire(PurchaseFailed(message: purchase.error?.message ?? '购买失败')); } else if (purchase.status == PurchaseStatus.purchased) { print('购买成功,开始消耗商品'); // 消耗型商品必须调用consume才能再次购买 if (purchase.productID == plan['play_product_id']) { InAppPurchase.instance.consumePurchase(purchase); eventBus.fire(PurchaseSuccess()); } } } } @override void dispose() { _purchaseSubscription?.cancel(); super.dispose(); }
2. 补充AndroidManifest的权限
虽然in_app_purchase包会自动添加billing权限,但debug模式下偶尔会失效,建议手动在android/app/src/main/AndroidManifest.xml里添加:
<uses-permission android:name="com.android.vending.BILLING" />
3. 代码逻辑的小优化
在purchaseProduct方法里,建议在queryProductDetails前判断productIds是否为空(防呆处理),同时优化timeout的错误提示:
// ... 其他代码 try { print('Getting product data'); final ProductDetailsResponse response = await InAppPurchase.instance .queryProductDetails(productIds) .timeout(const Duration(seconds: 30), onTimeout: () { print('查询商品详情超时,请检查网络或配置'); throw TimeoutException('查询商品详情超时'); }); // ... 后续逻辑 } on TimeoutException catch (e) { print(e.message); eventBus.fire(PurchaseFailed(message: '连接商店超时,请检查网络')); return 'Failed'; } catch (e) { print('查询商品详情发生未知错误: $e'); eventBus.fire(PurchaseFailed(message: '查询商品信息失败')); return 'Failed'; }
正确的测试流程(按顺序执行)
- 按上述步骤配置好Play Console的所有选项,确保应用已发布到内部测试轨道、商品已激活、测试账号已添加
- 用测试账号点击Play Console生成的内部测试链接,加入测试计划后从Play Store安装应用(不要用
flutter run直接装,Play Store安装的包是Google签名的,和控制台完全匹配) - 打开应用尝试购买商品,此时应能正常查询到SKU并发起购买
最后再排查几个容易忽略的点
- 不要用模拟器测试内购:Google Play模拟器的内购支持极差,必须用物理设备
- 测试设备必须有稳定外网,能正常访问Google Play服务
- 若仍报错,尝试用release模式编译安装(
flutter run --release),debug模式的签名偶尔会有兼容问题
按照这个流程排查,应该能解决你遇到的响应码12和查询超时问题,如果还有问题,可以补充Play Console的配置截图或更详细的Logcat日志,我再帮你分析。




