购买测试
在 TestFlight 中基于 Apple 沙盒测试购买,并验证 webhook 是否触发。
你无法在模拟器里对真实商品完成一次真正的 StoreKit 购买——Apple 的购买弹窗需要真机、一个 TestFlight
构建,以及一个沙盒测试员账户。本页走完整个闭环:沙盒购买 → 确认 RevenueCat 看到权益 → 确认
webhook 写入了你的 subscriptions 行。
仅在 RevenueCat 配置完成、且 Apple 已完成商品同步(应用能加载 offering)之后再做本页。沙盒购买不会产生真实扣费。
两个 Apple 概念,分别配置
| 概念 | 含义 | 位置 |
|---|---|---|
| TestFlight 测试员 | 安装 beta 构建 | App Store Connect → TestFlight |
| 沙盒测试员 | 用于测试购买的假 Apple ID | App Store Connect → 用户和访问 → 沙盒技术员 |
同一个人两者都会用到,但它们在不同地方设置。
1. 发一个 TestFlight 构建
归档并上传
在 Xcode 中归档应用并上传(完整归档流程见 App Store 发布)。等构建在 TestFlight 中处理完成。
创建内部测试群组
在 TestFlight → 创建群组(内部)→ 把自己加为测试员 → 加入该构建。内部群组跳过外部 beta 审核。
若构建显示 Missing Compliance,先完成导出合规提示。
TestFlight/Release 构建里必须用 appl_ SDK 密钥,绝不能用 test_ 密钥。 模拟商店密钥会触发
RevenueCat 的发布守卫,构建在启动时崩溃循环(checkForSimulatedStoreAPIKeyInRelease 处的
EXC_BREAKPOINT)。设好 REVENUECAT_IOS_KEY = appl_…,提升 build number,重新上传。
2. 创建沙盒测试员并登录
创建测试员
在用户和访问 → 沙盒技术员 → +,填一个尚未成为 Apple ID 的邮箱,并选择地区。
在设备上登录
先从 TestFlight 安装应用,然后在 iPhone 上登录沙盒账户。路径因 iOS 版本而异——通常是 设置 → App Store → 沙盒账户或设置 → 开发者 → 沙盒 Apple 账户。(若没有“开发者”菜单,把设备 连一次 Xcode 以开启开发者模式。)
3. 跑一次购买测试
购买
启动应用 → 登录你的应用账户 → 打开付费墙 → 确认 offering 加载出来 → 点继续 → 确认 Apple 的沙盒 弹窗。付费墙应关闭,应用应翻转到已解锁状态。
确认 RevenueCat 看到了
在 RevenueCat 里切到沙盒数据,找到该客户(其 app_user_id 即你的 Supabase 用户 UUID)。所
配置的权益(REVENUECAT_PRO_ENTITLEMENT_ID,默认 pro)应为活跃。
确认 webhook 写入了行
这是账户绑定的另一半。在 Supabase 里检查 subscriptions 表,应有一行以同一 user_id 为键,
status = active(或 trialing)且 product_type 正确。只要它在,EntitlementController 就会读到它,
每个 PremiumGate 都会跨平台解锁。
沙盒事件永远只触及该测试员自己的那一行——RLS 加上以 user_id 为键的 upsert,意味着一个测试员
影响不到另一个。应用的 pollAfterPurchase() 循环(0.8s → 1.6s → 3.0s)会消化购买与 webhook 写入
之间的那几秒。
4. 测试恢复购买
验证一个已购账户能重新解锁:
- 删除并重装 TestFlight 应用。
- 登录同一个沙盒账户。
- 打开付费墙 → 点恢复购买 → 权益解锁。
若要再次测试首次购买流程,请用一个全新的沙盒测试员,或在 App Store Connect 里清空当前测试员的 购买历史。
常见问题
| 症状 | 可能原因 | 解决 |
|---|---|---|
启动即崩溃(SIGTRAP) | Release/TestFlight 构建里用了 test_ SDK 密钥 | 改用 appl_ App Store 密钥,提升 build,重新上传 |
| 付费墙为空 / “无法加载套餐” | offering 未激活、无包,或商品仍是 Missing Metadata | 激活 default、挂上包、补齐商品元数据 |
| 错误码 23(配置错误) | StoreKit 拉不到商品 | 商品 ID + bundle id 完全一致;完成协议 / 税务 / 银行;等待 Apple 同步(可能数小时) |
| RevenueCat 商品显示 “Could not check” | 缺失 / 权限不足的 App Store Connect API 密钥 | 上传具备 App 管理 角色的 API 密钥;核对 Key ID + Issuer ID |
| 已购买,但什么都没解锁 | 权益标识符 ≠ REVENUECAT_PRO_ENTITLEMENT_ID | 匹配标识符(非显示名);默认 pro |
| “已购买”,不弹购买弹窗 | 沙盒测试员已拥有 | 换一个测试员,或清空其购买历史 |
RevenueCat 里权益已活跃,但 subscriptions 行缺失 | webhook URL/密钥有误,或 app_user_id 非 UUID | 复查 webhook URL + REVENUECAT_WEBHOOK_AUTH;确认应用用 Supabase UUID 登录 |
更底层、与 App Store 无关的问题(Keychain 会话、深度链接、xcconfig 替换)见 疑难排查。本页只保留购买流程特有的问题。
有用的日志
在 debug 构建下于真机上看 RevenueCat 的详细日志——模板已在 DEBUG 中设为
Purchases.logLevel = .warn。要临时更详细:
#if DEBUG
Purchases.logLevel = .debug
#endif一次健康的购买前日志显示权益为空;购买 / 恢复后,活跃列表会包含你的权益 id:
activeEntitlements=[] // 购买前
activeEntitlements=["pro"] // 购买 / 恢复后在 Xcode 中,查看调试控制台(View → Debug Area → Activate Console)或设备日志
(Window → Devices and Simulators → Open Console),按 RevenueCat / Purchases / StoreKit
过滤。
