StoreKit 2:一次购买如何完成
把购买看成可取消、可能待批准、需要验证和交付的状态机,而不是一次成功/失败的网络调用。
用你的前端经验理解
类似创建订单 → 支付状态变化 → 校验 → 履约。StoreKit 的成功结果还包着交易验证结果,pending 也不是已付款成功。
为什么需要它
一次购买是状态机,不是一个只会成功或抛错的函数。用户可以取消,家长批准可能让交易进入 pending,系统也可能在稍后通过更新序列送来交易。把“购买中”“等待处理”“已验证且已交付”分别建模,可以避免按钮卡住或提前解锁。
它是怎样工作的
StoreKit 2 以验证结果包装交易。处理可信交易后交付相应内容,并在已完成所需处理后 finish;如果还未可靠发放消耗型额度就提前结束,可能难以恢复交付。应用需要长期监听相关交易更新,处理启动时尚未完成的工作,并对同一交易 ID 保持幂等。
把关键概念连起来
加载与发起
用 Product.products(for:) 获取商品并处理缺失/失败;调用 purchase() 展示系统购买界面。防止重复点击,不伪造价格或可购买状态。
处理结果
success 中检查 VerificationResult,只有 verified 才进入可靠交付路径;pending 等待后续交易更新,userCancelled 安静返回;抛出的错误单独反馈。
交付与完成
以 transaction ID 做幂等,可靠记录并交付权益后调用 finish()。启动早期监听 Transaction.updates,覆盖延后批准、外部购买等变化,并管理监听任务生命周期。
import StoreKit// async throws 函数内的处理结构;deliverOnce 需自行实现switch try await product.purchase() {case .success(let result): switch result { case .verified(let transaction): try await deliverOnce(transaction) // 可靠、幂等地履约 await transaction.finish() case .unverified: showVerificationFailure() // 不授予权益 }case .pending: showPending() // 等待 Transaction.updatescase .userCancelled: break@unknown default: showUnsupportedResult()}- 购买返回的枚举与交易验证结果属于两层判断:成功分支内部也不能忽略验证。
- pending 与取消都不是已交付。finish 应在所需交易处理可靠完成后调用,重复交易处理必须保持幂等。
用于理解当前概念的代码片段;部分示例需要放入对应工程与作用域,并补齐上下文。
家长批准后的迟到成功
孩子点击购买后显示待批准,先保持未解锁。家长之后批准,应用通过交易更新接收并验证交易,再幂等授予权益并 finish;这可能发生在原购买页面已经关闭之后。
购买十次 AI 生成额度
- 客户端发起商品购买,取消时不改变余额,pending 时显示等待且不重复引导付费。
- 可信交易到达后交给服务端账本验证并发放一次额度,网络失败时保留可重试状态,不直接伪造成功余额。
- 交付确认后完成交易处理;再次收到同一交易时读取原有结果,不再发放十次。
这里需要你亲自判断
不要在拿到 success 外层枚举后就跳过验证发会员;也不要在消耗型权益尚未可靠入账时先 finish。未验证交易不能悄悄当成功。
做一个小练习
在购买实验中依次模拟取消、待批准、校验失败和已验证成功,观察每种结果是否能开启权益。
- 推演购买后立刻断网、交付成功后客户端崩溃、同一交易重复到达三种情况。
- 分别指出何时可以显示权益、何时可以 finish。
展开参考思路与验收标准
支付结果与内容交付可能跨进程完成,所以必须可恢复。完成顺序围绕可靠交付设计,不能把 finish 放在无论成功失败都会执行的清理块里。