都2032年了,你还没使用StoreKit2吗?

StoreKit2对iOS内购进行了重构,相较于原版本StoreKit,API改动较大,且更高效简洁。 StoreKit2抛弃了Objective-C,仅支持Swift且最低支持版本为iOS15。

swift 复制代码
/// Contains properties and methods to facilitate interactions between your app and the App Store.
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)

其中,使用了Swift语言的一些新的特性:

  • @aync/@await: Swift5.5推出的多线程编程API。
  • @MainActor: 防止应用在多线程中造成数据竞争,是保证多线程安全性的新类型。
  • JWS:JSON Web Signature,是一套加密校验体系,在StoreKit2中通过此校验体系来校验订单。

使用StoreKit2,可以更简单地实现内购流程,所有请求可以在回调中返回,而无需通过监听代理方法而造成发起支付和支付结果返回的代码割裂。内购流程也更加清晰,再配合最新的App Store Server API,可以为iOS内购流程带来很大程度上的优化。

获取商品(Product)

swift 复制代码
@MainActor
/// 通过 productIds 请求 Product 列表
/// - Parameter productIds: product ids
/// - Returns: Product 列表
func requestProducts(productIds: [String]) async -> [Product]? {
    products = try? await Product.products(for: Set.init(productIds))
    return products
}

判断商品类型

swift 复制代码
    /// Array of consumable products
    public var consumableProducts: [Product]? {
        guard products != nil else {
            return nil
        }
        
        return products?.filter({ product in
            product.type == .consumable
        })
    }
    
    /// Array of nonConsumbale products
    public var nonConsumbaleProducts: [Product]? {
        guard products != nil else {
            return nil
        }
        
        return products?.filter({ product in
            product.type == .nonConsumable
        })
    }
    
    /// Array of subscriptio products
    public var subscriptionProducts: [Product]? {
        guard products != nil else {
            return nil
        }
        
        return products?.filter({ product in
            product.type == .autoRenewable
        })
    }
    
    /// Array of nonSubscription products
    public var nonSubscriptionProducts: [Product]? {
        guard products != nil else {
            return nil
        }
        
        return products?.filter({ product in
            product.type == .nonRenewable
        })
    }

发起支付

swift 复制代码
    /// 发起支付
    /// - Parameter product: Product对象
    public func purchase(product: Product, uid: String) async throws -> (transaction: Transaction?, purchaseState: PurchaseState) {
        guard purchaseState != .inProgress else {
            throw PurchaseException.purchaseInProgressException
        }
        
        purchaseState = .inProgress
        
        //App account token
        //用于将用户 ID 绑定到交易(Transcation)中,即可建立苹果的交易订单数据与用户信息的映射关系,方便数据整合与追溯
        let uuid = Product.PurchaseOption.appAccountToken(UUID.init(uuidString: uid)!)
        //发起支付流程
        guard let res = try? await product.purchase(options: [uuid]) else {
            purchaseState = .failed
            throw PurchaseException.transactionVerificationFailed
        }
        
        var validateTransaction: Transaction? = nil
        
        switch res {
        case .success(let verificationResult):
            //购买状态:成功
            let checkResult = checkTransactionVerificationResult(verificationResult)
            if !checkResult.verified {
                purchaseState = .failedVerification
                throw PurchaseException.transactionVerificationFailed
            }
            
            validateTransaction = checkResult.transaction
            await validateTransaction!.finish()
            
            purchaseState = .complete
            
        case .userCancelled:
            //购买状态:用户取消
            purchaseState = .cancelled
            
        case .pending:
            //购买状态:进行中
            purchaseState = .pending
            
        default:
            //购买状态:未知
            purchaseState = .unknown
        }
        
        return (transaction: validateTransaction, purchaseState: purchaseState)
    }

这里可以将用户的uidProduct进行绑定,通过支付事务透传,完成支付流程后,从返回的Transaction中可获取appAccountToken参数,以便合并数据。

验证票据

StoreKit2可在客户端本地验证票据,而无需依赖服务端。

swift 复制代码
private func checkTransactionVerificationResult(_ result: VerificationResult<Transaction>) -> (transaction: Transaction, verified: Bool) {
        //Check whether the JWS parses StoreKit verification.
        switch result {
        case .unverified(let transaction, _):
            //StoreKit parses the JWS, but it fails verification.
            return (transaction: transaction, verified: false)
        case .verified(let transaction):
            //The reult is verified. Return the unwrapped value.
            return (transaction: transaction, verified: true)
        }
    }

监听订单

swift 复制代码
 private func listenForTransaction() -> Task<Void, Error> {
        return Task.detached {
            for await verificationResult in Transaction.updates {
                let checkResult = self.checkTransactionVerificationResult(verificationResult)
                
                if checkResult.verified {
                    let validatedTransaction = checkResult.transaction
                    await validatedTransaction.finish()
                } else {
                    print("Transaction failed verification.")
                }
            }
        }
    }

调用

swift 复制代码
let purchaseManager: InAppPurchaseManager = InAppPurchaseManager()
            
            Task.init {
                //获取 Product 列表
                let products = await purchaseManager.requestProducts(productIds: ["com.purdoctid.1", "purdoctid.6", "purdoctid.10"])
                
                print("获取所有商品: \(products!.count)")
                
                //发起内购
                do {
                    let product = purchaseManager.product(from: "purdoctid.10")!
                    
                    let res = try await purchaseManager.purchase(product: product, uid: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")
                    
                    //支付完成,发送凭据给服务端验证,请求发货。
                    print("transaction id: \(res.transaction!.originalID), \(res.transaction!.originalPurchaseDate)")
                } catch {
                    print("Purchase failed")
                }
                
            }

支付结果的验证其实客户端可调用checkTransactionVerificationResult自行认证,但该过程是由客户端借助StoreKit2向Apple Server发起请求完成的,客户端不负责该过程的具体实现。 因此为了安全性和稳定性考虑,需要支付Server介入对支付结果进行验证,再由支付Server根据验证的结果决定是否发货,再通知客户端完成支付流程。

都2032年了,你还没用StoreKit2吗?如果还没有,其实你可以先试试App Store Server API~~

相关推荐
lecepin14 分钟前
AI Coding 资讯 2025-09-17
前端·javascript·面试
IT_陈寒17 分钟前
React 18实战:7个被低估的Hooks技巧让你的开发效率提升50%
前端·人工智能·后端
树上有只程序猿1 小时前
终于有人把数据库讲明白了
前端
猩兵哥哥1 小时前
前端面向对象设计原则运用 - 策略模式
前端·javascript·vue.js
司宸1 小时前
Prompt设计实战指南:三大模板与进阶技巧
前端
RoyLin1 小时前
TypeScript设计模式:抽象工厂模式
前端·后端·typescript
华仔啊1 小时前
Vue3+CSS 实现的 3D 卡片动画,让你的网页瞬间高大上
前端·css
江城开朗的豌豆1 小时前
解密React虚拟DOM:我的高效渲染秘诀 🚀
前端·javascript·react.js
vivo互联网技术1 小时前
拥抱新一代 Web 3D 引擎,Three.js 项目快速升级 Galacean 指南
前端·three.js