沙盒环境下IAP收据无效:恢复购买后验证失败
StoreKit收据验证与恢复购买问题解答
收据是否加载正确?
从错误码22002(收据格式错误)来看,你的收据肯定没加载/处理正确。这个错误是Apple服务器明确识别到提交的收据数据格式不符合要求,常见原因包括:
- 直接读取本地收据二进制数据就提交,没做Base64编码
- Base64编码时带了多余的换行符
- 读取的收据文件不完整(比如恢复交易后还没写入完成就读取)
如何确保存储有效收据?
1. 正确加载并编码收据
必须将本地收据的二进制数据转换为不带换行符的Base64字符串,示例代码:
func loadAndEncodeReceipt() -> String? { guard let receiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: receiptURL.path), let receiptData = try? Data(contentsOf: receiptURL) else { return nil } // 生成无换行的Base64编码,避免格式错误 return receiptData.base64EncodedString(options: []) }
注意:如果appStoreReceiptURL不存在或文件为空,不要强行提交,需先调用SKReceiptRefreshRequest刷新收据。
2. 调整恢复购买后的收据处理时机
不要在paymentQueueRestoreCompletedTransactionsFinished中立刻读取收据——恢复交易完成后,Apple可能还在异步写入本地收据文件。正确流程:
- 调用
SKPaymentQueue.default().restoreCompletedTransactions() - 在
paymentQueue(_:updatedTransactions:)中处理每个交易:func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch transaction.transactionState { case .restored: // 标记对应内购项目已恢复 handleRestoredPurchase(transaction: transaction) // 结束交易 queue.finishTransaction(transaction) case .failed: queue.finishTransaction(transaction) default: break } } // 所有恢复交易处理完成后,主动刷新收据 refreshReceipt() } func refreshReceipt() { let request = SKReceiptRefreshRequest(receiptProperties: nil) request.delegate = self request.start() } - 在
requestDidFinish(_:)回调中再加载收据进行验证。
3. 验证请求的格式必须合规
提交到沙箱验证接口的JSON必须符合要求:
- 包含
receipt-data字段(值为Base64编码的收据) - 自动续期订阅需添加
password字段(你的App内购共享密钥) - 建议添加
exclude-old-transactions: true减少响应体积
示例请求体:
{ "receipt-data": "你的Base64编码收据字符串", "password": "your_shared_secret_key", "exclude-old-transactions": true }
同时确保请求的Content-Type设置为application/json。
4. 有效收据的存储策略
- 验证通过后,将Apple返回的完整验证响应JSON存储到Keychain(敏感信息避免用UserDefaults)
- 每次启动App时,先检查本地存储的响应是否过期(读取
expires_date_ms字段判断) - 若未过期,直接使用本地存储的验证结果;若过期或验证失败,再重新加载收据并提交验证
5. 异常场景处理
- 若收据文件不存在:提示用户检查Apple ID登录状态,或触发
SKReceiptRefreshRequest获取收据 - 网络异常时:依赖本地存储的有效收据,待网络恢复后再重新验证
内容的提问来源于stack exchange,提问作者byJeevan
相关产品推荐
相关产品推荐

