如何通过StoreKit 2获取交易记录以唤起应用内退款申请页?
问题根源
你遇到的是StoreKit 2针对消耗型产品的原生设计逻辑,不属于代码故障:消耗型产品的交易在调用await transaction.finish()完成闭环后,系统会自动将其从currentEntitlements、latest(for:)、currentEntitlement(for:)等公开查询接口的返回结果中移除。消耗型产品本身不具备持久生效的用户权益属性,苹果不会长期在系统侧保留这类交易的可查询记录,这是你调用相关接口始终返回空的核心原因。
可行解决方案
方案1:交易链路内即时持久化存储(生产环境首选)
在交易验证通过的分支,调用finish()之前,直接将交易核心字段持久化存储到本地(UserDefaults、CoreData均可),必需存储的字段为transaction.id(交易唯一标识,退款接口必填参数),可选存储商品ID、购买时间等辅助字段。后续发起退款时直接读取本地存储的交易ID即可调用退款接口,无需获取完整Transaction对象。
存储参考代码:case .verified(let transaction): // 先持久化交易信息 let transactionData: [String: Any] = [ "transaction_id": transaction.id, "product_id": transaction.productID, "purchase_date": transaction.purchaseDate ] UserDefaults.standard.set(transactionData, forKey: "consumable_transaction_\(transaction.id)") // 再完成交易 await transaction.finish()退款调用参考代码:
// 从本地读取对应交易ID guard let transactionID = 本地存储的交易ID else { return } do { let refundResult = try await AppStore.beginRefundRequest(for: transactionID) // 处理退款结果 } catch { // 处理异常 }方案2:从业务服务端拉取交易记录
你提到服务端已经完成了收据校验,服务端侧必然留存了该笔消耗型交易的唯一ID,你可以新增业务接口从服务端拉取当前用户名下的所有消耗型交易记录,拿到对应交易ID后即可发起退款,无需依赖本地StoreKit查询。方案3:开发阶段临时调试方案
如果你当前处于开发调试阶段,需要临时获取交易对象验证退款流程,可以暂时注释掉await transaction.finish()代码,在交易未完成的状态下,调用Transaction.latest(for: productId)等接口即可查询到对应交易记录。注意生产环境必须恢复finish()调用,否则交易长期处于待完成状态,StoreKit会在应用每次启动时重复推送该笔交易。
内容的提问来源于stack exchange,提问作者user1261347

