动手点关注 干货不迷路 👆
一、背景
2021 年 WWDC,在 iOS 15 系统上推出了一个新的 StoreKit 2 库,该库采用了完全新的 API 来解决应用内购买问题。
Meet StoreKit 2 - WWDC21 - Videos - Apple Developer:重点内容:Storekit 2 API 介绍和代码演示,以及 appAccountToken
Manage in-app purchases on your server - WWDC21 - Videos - Apple Developer:重点内容:JWS 签名交易的服务器验证,新服务器 API,新服务器通知,沙盒测试的新功能
Support customers and handle refunds - WWDC21 - Videos - Apple Developer:重点内容:用来支持用户和处理退款的 Storekit 2 API 以及服务器 API
二、物料
名词 | 解释 | |
---|---|---|
IAP | In-App Purchase:应用内购买 | |
StoreKit 1 | 原始的应用内购买 API | Choosing a StoreKit API for In-App Purchase |
StoreKit 2 | 应用内购买 API | Choosing a StoreKit API for In-App Purchase |
三、StoreKit 1 存在的问题
苹果后台能否查看到退款的订单详情?
不能。只能苹果处理退款后发通知给我们的服务器,告知发生了一笔退款
消耗性、非消耗性、非续期订阅、自动续订能不能在沙盒环境测试退款?
不能。系统没提供这种测试方式。
能够将用户反馈的苹果收据里的 orderID 与具体的交易进行关联吗?
不能。
服务器端 Receipt 收据解析后,没有包含 orderID 信息,所以无法直接关联他们之间的联系。
不支持使用苹果收据里的 orderID 去苹果服务器查询交易信息,没有提供这个 API(StoreKit 2 出来后支持去查询 StoreKit1 的交易了,https://developer.apple.com/documentation/appstoreserverapi/look_up_order_id?language=_9 )。

在开发过程中,无法直接关联 transaction 与 orderID 之间联系,虽然有一个 applicationUserName 字段,可以存储一个信息。但是这个字段是不是 100%靠谱,在某些情况下会丢失存储的数据。
无法主动的去苹果服务器获取交易历史记录,退款信息。无法根据用户提供的苹果收据里的 orderID 主动关联上我们当前已知的订单。
目前 sk1 的 skproduct 无法区分消耗品,非消耗品,订阅商品,非连续订阅商品。
sk1 存在队列监听,每次购买需要通过队列监听对应的购买状态的变更,所有的 transaction 的回调都在监听当中,不好区分哪些是补单的 transaction 和正常购买的 transaction。
四、StoreKit v2 新特性
StoreKit 2 新特性主要包含三部分:
StoreKit 2:关于在 App 里 API 的更新和变化,包含应用内更改订阅、退款等;
Server to Server:苹果服务器与开发者服务器之间的通讯,包括苹果通知、开发者主动请求苹果服务器、新的验证收据流程等;
Sandbox Test:关于沙盒测试环境相关的更新,还有一些注意事件等。
五、StoreKit 2 API
StoreKit 2 主要的更新有这几个:
使用 swift 新特性开发
更新收据和交易(数据格式和字段变更)
更多订阅类型的接口
相同的 StoreKit 框架

5.1 只支持 Swift 开发
StoreKit 2 使用了 Swift 5.5 的新特性进行开发,完全修改了获取商品、发起交易、管理交易信息等接口 API 的实现方式。https://swift.org/blog/
例如获取商品方式语法不同:
原始获取商品方式
// 1. 请求商品
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:identifiers];
request.delegate = pipoRequest;
[request start];
// 2. 实现 SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
// success
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error API_AVAILABLE(ios(3.0), macos(10.7))
{
// failed
}
新获取商品方式
// 获取商品
let products = try await Product.products(for: productIDs)
// 购买商品
func purchase(_ product: Product) async throws -> Transaction? {
//Begin a purchase.
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
//Deliver content to the user.
await updatePurchasedIdentifiers(transaction)
//Always finish a transaction.
await transaction.finish()
return transaction
case .userCancelled, .pending:
return nil
default:
return nil
}
}
5.2 新 API

商品
购买
交易信息
交易历史
订阅状态