uni-app 无法用 uni.requestPayment 调起苹果 IAP,因其未封装 StoreKit;必须使用支持 StoreKit 的原生插件(如 uni-app-iap),并配置开发证书、显式 Bundle ID、启用 IAP 功能、添加测试设备 UDID,且沙盒商品需为 Ready to Submit 或 Approved 状态、使用沙箱账号、关闭密码要求;后端必须用 transactionReceipt 向苹果验签,status === 0 才有效。

uni-app 无法用 uni.requestPayment 直接调起苹果 IAP,这是硬限制——它压根没封装 StoreKit。你写的支付代码再漂亮,只要没走原生桥接,appleiap 通道就永远是 null 或静默失败。
为什么 uni.requestPayment 对 IAP 完全无效
苹果 IAP 是 StoreKit 原生框架,而 uni.requestPayment 只对接了微信、支付宝等第三方 SDK。调用它不会报错,但也不会弹窗、不会返回商品、不会触发任何购买流程。你看到的“没反应”,其实是 JS 层根本没连上 iOS 底层。
必须用支持 StoreKit 的原生插件,比如 HBuilderX 插件市场里的 uni-app-iap(注意:不是 npm 包,也不是 GitHub 上随便搜到的同名库)。
- 插件内部调用
SKProductsRequest查询商品、SKPaymentQueue发起购买,这些 JS 无法直触 -
requestProduct、buy、restore等方法都是插件透出的 JS 接口,不是 uni-app 自带 API - 服务端验签必须用苹果返回的
result.transactionReceipt(base64 字符串),不是transactionId或自定义订单号
自定义基座包配置不正确,appleiap 通道一定为 null
云打包或用发布证书生成的 ipa,哪怕装在真机上,plus.payment.getChannels 也拿不到 appleiap。只有开发证书(Development)+ 正确 Provisioning Profile 才能激活沙盒环境。
- HBuilderX → 运行 → 运行到手机或模拟器 → 「制作自定义基座」→ 必须勾选「开发证书」,不能勾「发布证书」
- Provisioning Profile 必须绑定显式 Bundle ID(如
com.example.myapp),Wildcard ID(*)不支持 IAP - App ID 在 Apple Developer 后台必须已启用
In-App Purchase功能 - 测试设备的 UDID 必须提前加进开发者账号的「Devices」列表,否则安装失败或 IAP 不可用
requestProduct 返回空数组的 4 个硬性条件
即使 appleiap 通道存在,requestProduct([productId]) 仍可能返回空或静默失败——这不是网络问题,而是沙盒识别失败。
- 内购商品状态必须是
Ready to Submit或Approved(Draft 状态不会出现在沙盒产品列表中) - 商品 ID(
productId)必须和 App Store Connect 中创建的完全一致,大小写敏感,不能含空格或特殊字符 - 测试账号必须是沙箱账号(
@test.com后缀),且已在「设置 → Apple ID → 媒体与购买项目」里退出当前 Apple ID 并重新登录该沙箱账号 - 首次运行前,需手动在「设置 → Apple ID → 媒体与购买项目」里关闭「密码要求」,否则支付面板卡死在输入密码页
后端验签不是可选项,是上线前提
前端收到的 transactionReceipt 是 base64 字符串,必须由你自己的服务器向苹果校验接口(https://buy.itunes.apple.com/verifyReceipt 生产环境 / https://sandbox.itunes.apple.com/verifyReceipt 沙盒)发起 POST 请求验证。苹果返回的 status === 0 才代表交易真实有效。
跳过后端验签=把支付控制权交给客户端,用户改个 receipt 就能白嫖会员。
- 验签失败时,不要直接提示“支付失败”,应记录日志并返回通用错误,避免暴露校验逻辑
- 自动续期订阅需额外处理
latest_receipt_info和pending_renewal_info字段 - receipt 需存档,苹果只保留最近 6 次交易的 receipt 数据,历史订单靠你自己存
最容易被忽略的一点:沙盒测试阶段所有商品价格都按地区自动换算,但你看到的只是模拟值;真正上线后,用户看到的价格由 App Store Connect 中设置的价格等级决定,和你本地代码里写的数字毫无关系。别在前端硬编码价格显示逻辑。



















