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

相关推荐
喵叔哟29 分钟前
重构代码之取消临时字段
java·前端·重构
还是大剑师兰特1 小时前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解1 小时前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django