iOS React Native订阅验证返回21002状态及沙箱登录问题求助
iOS React Native 订阅问题解决方案
问题1:沙箱测试用户登录提示不弹出
排查与修复步骤
- 退出设备真实Apple ID:前往「设置」→「App Store」退出当前登录的真实账号,触发订阅时系统会自动弹出沙箱用户登录界面,输入你的沙箱测试账号即可。
- 匹配地区设置:确保沙箱测试用户的地区,与App Store Connect中订阅产品的可用地区完全一致。
- 验证应用权限与签名:
- 在Xcode项目的「Signing & Capabilities」中确认「In-App Purchase」已开启。
- 检查
entitlements文件是否包含com.apple.developer.in-app-purchase权限。
- 确认网络环境:沙箱验证需连接Apple测试服务器,确保设备可正常访问境外网络(可尝试切换境外网络测试)。
- 核对产品ID:代码中
subscriptionSkus的['Monthly', 'Yearly']必须与App Store Connect中创建的订阅产品ID完全匹配(包括大小写、前缀,比如com.yourapp.Monthly)。
问题2:verifyReceipt返回21002状态码(收据格式错误)
Apple官方定义21002为「提供的收据数据格式不正确」,以下是具体修复方案:
排查与修复步骤
- 校验收据数据有效性:
验证前打印收据内容,确认transactionReceipt不为空且是有效Base64字符串:
若存在换行符,可清理后再使用:console.log('Receipt Data:', receipt);const cleanedReceipt = receipt.replace(/\n/g, ''); - 确认共享密钥正确性:
确保IOS_SHARED_SECRET是从App Store Connect「用户和访问」→「密钥」中生成的共享密钥,完全复制无多余空格或换行。 - 匹配验证环境:
代码中isTestEnvironment = __DEV__的逻辑正确,但需注意:- 开发环境(__DEV__为true)使用沙箱验证服务器
- 生产环境或TestFlight测试时,需将第二个参数改为false,使用生产服务器
- 补全交易流程:
验证成功后必须调用finishTransaction,否则会导致重复验证或状态异常。修改checkCurrentPurchase函数:const checkCurrentPurchase = async purchase => { if (purchase) { try { const receipt = purchase.transactionReceipt; if (receipt && Platform.OS === 'ios') { const isTestEnvironment = __DEV__; const cleanedReceipt = receipt.replace(/\n/g, ''); const appleReceiptResponse = await validateReceiptIos( { 'receipt-data': cleanedReceipt, password: IOS_SHARED_SECRET, }, isTestEnvironment, ); if (appleReceiptResponse) { const { status } = appleReceiptResponse; if (status === 0) { // 0表示验证成功 await finishTransaction(purchase); // 完成交易 // 此处处理订阅成功后的业务逻辑 // navigation.navigate('Home'); } else { console.log('Receipt validation failed with status:', status); } } } } catch (error) { console.log('Validation error:', error); } } }; - 避免使用历史收据:
不要用getPurchaseHistory返回的历史收据验证,应使用当前购买产生的currentPurchase中的transactionReceipt,历史收据可能已失效或格式不符。
内容的提问来源于stack exchange,提问作者Ahmad Fahim
相关产品推荐
相关产品推荐

