uni-app 无法直接调起 iOS 应用内购买(IAP),因 uni.requestPayment 等 API 对 IAP 无效,真机静默失败;需通过原生插件 uni-app-iap 初始化并正确配置商品 ID、沙盒环境及服务端验签。

uni-app 无法直接用 uni.requestPayment 或 uni.pay 调起 iOS 应用内购买(IAP),这些 API 对 IAP 完全无效——真机上静默失败,控制台无报错,也不弹窗。
为什么 uni.getProvider({ service: 'payment' }) 返回 appleiap 却调不起支付?
这个返回值只是框架“声称支持”,不代表原生层真正集成了 StoreKit。HBuilderX 自带的旧版 uni-pay 插件在 iOS 16+ 上大概率闪退,且多年未更新;plus.payment.getChannels() 查到的 appleiap 通道若未经正确原生插件桥接,调用 requestProduct 或 requestPayment 会直接返回空或抛出 not initialized。
- 必须通过 HBuilderX「原生插件管理」手动添加可靠插件,如社区广泛验证的
uni-app-iap(插件 ID 精确为该字符串,不是 npm 包) - 初始化必须在
App.vue的onLaunch中执行iap.init(),否则后续所有方法均不可用 - 调试时务必打开 Xcode 控制台,关注是否出现
SKErrorDomain Code=0(沙盒未启用)或Code=2(测试账号未登录)
商品查不到、iap.getProducts 返回空数组怎么办?
商品 ID 大小写、下划线、拼写必须与 App Store Connect 后台 **完全一致**,差一个字符就查不到。常见疏漏包括:后台填的是 com.myapp.monthly,代码里传了 com.myapp.Monthly 或 com.myapp.monthly_。
- 确保 App ID 在 Apple Developer Center 已开启
In-App Purchasecapability,并关联了对应描述文件 - 商品状态必须是「准备提交」或「已批准」,「元数据丢失」或「已拒绝」状态无法在沙盒环境查询
- 真机测试必须使用 Apple ID 登录沙盒测试账号(非个人主账号),且设备未退出 App Store
- 首次查询前建议先调用
iap.refreshReceipt(),避免 receipt 过期导致商品列表加载失败
客户端验签没有意义,服务端怎么安全验签?
客户端拿到的 receipt-data 是 base64 字符串,前端解码或校验纯属徒劳——攻击者可伪造任意 receipt 并绕过。唯一有效方式是:你的服务器向 Apple 接口发起 POST 请求,由 Apple 返回交易真实状态。
- 沙盒环境必须用
https://sandbox.itunes.apple.com/verifyReceipt,正式环境切回https://buy.itunes.apple.com/verifyReceipt;混用会导致 21007 / 21008 错误码 - 请求体是 JSON:
{"receipt-data": "base64_string", "password": "shared_secret"},其中password仅对自动续订订阅商品必需(在 App Store Connect 商品页生成) - Apple 返回的
status === 0才代表验签成功,但还需检查latest_receipt_info中的product_id、expires_date_ms(订阅)、transaction_id(防重入) - 服务端必须记录已处理的
transaction_id,同一笔交易多次回调需幂等处理
恢复购买和续订降级逻辑容易被忽略的关键点
用户换设备、重装 App 后需要「恢复购买」,这不是简单重发 receipt,而是要触发原生 StoreKit 的 restoreCompletedTransactions 流程,并逐条比对本地已有商品与恢复列表中的 product_id。
-
iap.restorePurchases()返回的是完整交易历史,JS 层需自行过滤出本 App 支持的商品 ID,不能全盘接受 - 自动续订订阅发生降级(如年订→月订)时,原订阅不会立即失效,而是进入
grace period,服务端需解析pending_renewal_info字段判断用户意图 - 用户退款后,Apple 不会主动通知你的服务端,只能靠定期调用
https://api.storekit.itunes.apple.com/inApps/v1/notifications订阅 Server-to-Server 通知(需配置密钥和 endpoint) - 所有交易状态变更(购买、续订、取消、退款)都应以 Apple 的 Server-to-Server 通知为准,而非客户端回调


















