苹果内购新版的StoreKit2只支持iOS15以上,新的nsync同步接口,简单的使用如下:
@available(iOS 15.0, *) public class MXLiveIAPStoreV2 { static let shared: MXLiveIAPStoreV2 = MXLiveIAPStoreV2() typealias Transaction = StoreKit.Transaction private(set) var fuel: [Product] = [] var updateListenerTask: Task<Void, Error>? = nil // var statusChanged:(MXLiveIAPStatus) -> Void = {_ in // // } private var currentTransaction:Transaction? private var currentOrder: MXLiveIAPOrder? private init() { } weak var delegate: MXLiveIAPDelegate? func install(delegate:MXLiveIAPDelegate){ currentOrder = MXLiveIAPOrder.getLastOrderForKeychain() //Start a transaction listener as close to app launch as possible so you don't miss any transactions. self.updateListenerTask = listenForTransactions() } deinit { updateListenerTask?.cancel() } func getCurrentOrder()->MXLiveIAPOrder?{ return currentOrder } func canStartNewIAP() -> Bool{ return currentOrder == nil } func finishCurrentOrder(){ MXLiveIAPPayment.shared.finishCurrentOrder() currentOrder?.deleteKeychainOrderRecord() currentOrder = nil guard let tran = currentTransaction else { return } currentTransaction = nil Task{ await tran.finish() } } private func listenForTransactions() -> Task<Void, Error> { return Task.detached { //Iterate through any transactions that don't come from a direct call to `purchase()`. for await result in Transaction.updates { do { _ = try self.checkVerified(result) // transaction.appAccountToken?.uuidString //Always finish a transaction. self.finishCurrentOrder() //MARK: - update gems self.delegate?.orderStatusChanged(order: self.currentOrder, status: .complete) } catch { self.delegate?.orderStatusChanged(order: self.currentOrder, status: .failed(error)) self.finishCurrentOrder() //StoreKit has a transaction that fails verification. Don't deliver content to the user. print("Transaction failed verification") } } } } func startIAPPayment(ids:[String], order:MXLiveIAPOrder){ self.currentOrder = order currentOrder?.saveToKeyChain() Task { if let pro = await requestProducts(ids:ids)?.last{ _ = try? await purchase(pro) } } } private func requestProducts(ids:[String]) async -> [Product]?{ //During store initialization, request products from the App Store. do { //Request products from the App Store using the identifiers that the Products.plist file defines. let storeProducts = try await Product.products(for: ids) var newFuel: [Product] = [] //Filter the products into categories based on their type. for product in storeProducts { switch product.type { case .consumable: newFuel.append(product) case .nonConsumable: break case .autoRenewable: break case .nonRenewable: break default: //Ignore this product. print("Unknown product") } } //Sort each product category by price, lowest to highest, to update the store. fuel = newFuel return newFuel } catch let error{ self.delegate?.orderStatusChanged(order: currentOrder, status: .failed(MXLiveIAPError(reason: "get product faile", code: -1))) finishCurrentOrder() print("Failed product request from the App Store server: \(error)") return nil } } private func purchase(_ product: Product) async throws -> Transaction? { /* UUID 是苹果定义的接口 UUID().uuidString 获取,格式如:4713AE2D-11A5-40EA-B836-CBCD1EC96A76。如果需要关联 用户ID 和开发者订单号,需要开发者自动映射,或者服务器端生成返回等 */ //Begin purchasing the `Product` the user selects. //6e738162-133f-4d11-b446-4293709529799328312 let uuidString = UUID().uuidString//367E28C7-CF53-438A-98C3-24DFA11706BF print("------uuid ------: \(uuidString)") let uuid = Product.PurchaseOption.appAccountToken(UUID.init(uuidString: uuidString)!) let result = try await product.purchase(options: [uuid])//options: Set<Product.PurchaseOption>([.appAccountToken(UUID(uuidString: "uid1")!)])) switch result { case .success(let verification): //Check whether the transaction is verified. If it isn't, //this function rethrows the verification error. let transaction = try checkVerified(verification) self.currentTransaction = transaction //The transaction is verified. Deliver content to the user. currentOrder?.transactionId = "\(transaction.id)" currentOrder?.updateTokeyChain() self.delegate?.orderStatusChanged(order: currentOrder, status: .complete) print(transaction.debugDescription) //Always finish a transaction. // await transaction.finish() return transaction case .userCancelled, .pending: self.delegate?.orderStatusChanged(order: currentOrder, status: .failed(MXLiveIAPError(reason: "user Cancelled", code: -1))) self.finishCurrentOrder() return nil default: return nil } } //Check whether the JWS passes StoreKit verification. func checkVerified<T>(_ result: VerificationResult<T>) throws -> T { switch result { case .unverified: //StoreKit parses the JWS, but it fails verification. throw StoreError.failedVerification case .verified(let safe): //The result is verified. Return the unwrapped value. return safe } } /*All transactions:全部的购买交易订单 Latest transactions:最新的购买交易订单。(分为订阅品项和除订阅品项外的所有类型二种) Current entitlements:当前用户有购买的权限。(全部的订阅品项、和非消耗品项) */ func allTransaction() async -> [Transaction] { var all = [Transaction]() for await result in Transaction.all { do { let tran = try checkVerified(result) all.append(tran) } catch let error { print("error:----\(error)") } } return all //Transaction.latest(for: "pid") } //获取推广内购商品 func Promotion() async -> [SKProduct]?{ let promotion = SKProductStorePromotionController() let prodicts = try? await promotion.promotionOrder() return prodicts } }
标签:内购,transaction,return,StoreKit,self,currentOrder,let,func,IAP From: https://www.cnblogs.com/duzhaoquan/p/17058141.html