# iOS 内购 使用 StoreKit 1 兼容项目 iOS 12 最低版本(这些 API 在新 SDK 中已弃用,未来提升最低版本后可迁移 StoreKit 2)。无需额外 CocoaPods。 在 App Store Connect 创建与 Bundle ID 对应的商品,使用准确商品 ID;完成付费协议等配置。 Creator 重新构建 iOS,Xcode 启用 In-App Purchase capability,用 StoreKit Configuration 或 Sandbox 账号测试。 ```ts import iap from '@scripts/platform/IAP/IAP'; const unsubscribe = iap.onTransaction(transaction => { // purchased/restored: 交给业务的验证发货队列。 // deferred: 家长审批等,不发货、不 finish。 }); const catalog = await iap.init(['your.product.id']); // catalog.products 包含本地化价格;invalidProductIds 需要检查后台配置。 const pending = await iap.getPendingTransactions(); // 启动补单,即使此前事件早于 TS 启动 const result = await iap.purchase('your.product.id'); const restored = await iap.restore(); // 用户点击“恢复购买”时执行 // 服务端验证成功且幂等发货完成后才调用: // await iap.finishTransaction(verifiedTransactionId); // unsubscribe(); ``` 上述调用展示各 API,实际购买与恢复由不同按钮触发,不要在启动时自动购买/恢复。 purchase、restore 和 onTransaction 可重复报告同一交易,统一队列按 transactionId 去重,后台必须幂等。 恢复非消耗型商品或订阅权益时,后台还需结合 originalTransactionId、退款/撤销和订阅到期状态,不能仅看到 restored 就永久解锁。 恢复不用于找回已消耗的消耗型商品。这里只提供客户端支付能力,不包含后台验单或发货。 receipt 为 Base64 App Store 收据。必须在服务端验证真实性、Bundle ID、商品、交易、环境及当前权益,并绑定游戏账号。 不应直接信任客户端 status;交易 ID 也不是单独的身份验证凭证。购买前应确认游戏账号,切换账号时防止错绑。 如果 receipt 为空,不发货也不 finish:保留交易,后台可使用已验证的 App Store Server API 查询流程;本实现未提供收据刷新接口。 finishTransaction 必须使用当前 transactionId,不是 originalTransactionId。 超时仅表示客户端等待结束,不表示 Apple 取消交易。继续观察事件/查询 pending,禁止直接重复付款。 原生暂时限制同一时间一笔购买,存在队列交易时先处理或等待;deferred 必须等用户审批,不能 finish。 恢复失败通过 Promise rejection 返回。成功恢复但没有可恢复商品返回空数组。 测试:正常购买、取消、支付限制、无效商品、断网、审批延迟、杀进程补单、重复点击、恢复空列表、恢复已购、验单失败不 finish、发货成功后 finish。 Windows 上只能检查 TS/源码;必须在 Mac 编译并在 Sandbox/StoreKit 测试支付链路。