都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~~

相关推荐
学习使我快乐013 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19953 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈4 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水5 小时前
简洁之道 - React Hook Form
前端
正小安7 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch9 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光9 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   9 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   9 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d