TestFlight 中能否使用真实付款测试 In-App Purchase?
结论
不能。通过 TestFlight 安装的 App 会在 Apple 的 Sandbox 环境中执行 In-App Purchase,不会从真实信用卡扣款,也不会产生真实收入。
即使测试设备登录的是正常 App Store 账号,TestFlight 构建中的购买仍然属于沙盒交易。要测试真实付款,App 及其 In-App Purchase 项目必须符合 Apple 的审核和上架要求。用户从 App Store 安装正式版本后,才能进行真实购买。
为什么 TestFlight 不能进行真实扣款
TestFlight 用于 App 发布前的测试。Apple 会将 TestFlight 构建发起的 StoreKit 交易转到 Sandbox 环境。在这个环境中:
- 真实信用卡或其他付款方式不会被扣款;
- 交易不会产生可结算的销售收入;
- 订阅通常会按加速后的测试周期续期;
- Sandbox 交易记录不能作为正式订单;
- 收据和 StoreKit 交易中的环境信息会显示交易来自 Sandbox。
交易环境由 App 的分发渠道决定。无论修改代码、调整 App Store Connect 配置还是更换账号,都无法把 TestFlight 交易切换为真实付款。
正确的测试方式
1. 继续使用 TestFlight 测试完整购买流程
先在 App Store Connect 中配置 In-App Purchase,并确认产品信息和协议状态符合当前的测试要求。然后通过 TestFlight 测试:
- 请求并展示商品;
- 发起购买;
- 处理成功、取消、失败和待处理状态;
- 验证交易或收据;
- 解锁对应权益;
- 处理恢复购买;
- 测试订阅续期、过期、退款和撤销等状态。
除了不会真实扣款,TestFlight 已经能覆盖大多数购买逻辑。
2. 使用 StoreKit Configuration 做本地测试
测试商品加载、异常状态和订阅生命周期时,可以在 Xcode 中创建 .storekit 配置文件。这种方式快速且容易重复执行,但它只是本地模拟,不能代表真实支付结果。
3. 上架正式版本后进行真实购买
如果需要核对真实账单和扣款,必须等 App 及相关 In-App Purchase 项目通过审核,并可从 App Store 正式下载后再购买。
可以考虑先通过范围受控的正式渠道发布,例如只在指定地区上架。能否使用分阶段发布、非公开分发或其他方式,要看应用类型、账号资格以及 App Store Connect 当时提供的选项。无论选择哪种方式,都要确认 App 来自正式的 App Store 分发渠道,而不是 TestFlight。
真实购买会产生实际扣款,还可能涉及退款、税务、结算和消费者权益问题,因此不适合用作普通调试环境。
StoreKit 2 购买示例
下面的代码既可用于 Sandbox,也可用于正式环境。App 最终连接哪个环境,取决于它的安装和分发方式,业务代码不应尝试强制切换。
import StoreKit
func purchase(_ product: Product) async throws {
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
// 在这里发放或更新用户权益。
// 生产环境中应结合自己的服务端或持久化逻辑,
// 避免仅依赖界面状态判断是否已购买。
await transaction.finish()
case .pending:
// 交易需要额外批准,例如 Ask to Buy。
break
case .userCancelled:
// 用户取消购买,不应视为错误。
break
@unknown default:
break
}
}
func checkVerified<T>(
_ result: VerificationResult<T>
) throws -> T {
switch result {
case .verified(let value):
return value
case .unverified:
throw PurchaseError.failedVerification
}
}
enum PurchaseError: Error {
case failedVerification
}
还需要监听后续交易,特别是订阅续期、跨设备购买,以及 App 未运行时完成的交易:
import StoreKit
func observeTransactions() -> Task<Void, Never> {
Task.detached {
for await result in Transaction.updates {
guard case .verified(let transaction) = result else {
continue
}
// 根据 transaction 更新用户权益。
await transaction.finish()
}
}
}
如果服务端需要验证 App Store Server API 返回的数据或签名交易信息,应根据环境字段分别处理 Sandbox 和 Production 数据,防止测试订单进入正式的财务或权益流程。具体字段及验证方式应以当前的 StoreKit 和 App Store Server API 文档为准。
注意事项
- 不要在 TestFlight 中反复更换真实信用卡,这不会让交易离开 Sandbox。
- 不要根据商品价格、账号类型或客户端开关判断交易环境。
- 不要在业务代码中硬编码”TestFlight 一定使用某个固定测试账号”。测试账号的登录方式可能随系统和 StoreKit 流程变化。
- Sandbox 和 Production 的订单、收据及服务端通知应分开存储和验证。
- 提交审核前,确认付费协议、税务和银行信息,以及 In-App Purchase 项目状态均符合 App Store Connect 的要求。
- 审核人员会在 Apple 提供的测试环境中检查购买流程,因此商品要能正常加载,购买入口和权益说明也要完整。
- 如果只是要确认信用卡能否使用,应检查 Apple ID 的付款方式,不需要也不应通过 TestFlight App 验证。
备注:内容仅供参考。
