PAYATHON 2026

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 测试:

  1. 请求并展示商品;
  2. 发起购买;
  3. 处理成功、取消、失败和待处理状态;
  4. 验证交易或收据;
  5. 解锁对应权益;
  6. 处理恢复购买;
  7. 测试订阅续期、过期、退款和撤销等状态。

除了不会真实扣款,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 验证。

备注:内容仅供参考。