iOS内购支付
// import StoreKit @objcMembers public class FastApplePay: NSObject, SKPaymentTransactionObserver, SKProductsRequestDelegate { public static let shared = FastApplePay() public typealias FastApplePayBlock = (FastApplePayState,String?,String?)->Void public enum FastApplePayState :String{ case start = "商品开始购买" case success = "商品购买成功" case failed = "商品购买失败" case productContent = "商品信息列表获取失败" case payFailed = "商品支付失败" case cancel = "用户取消交易" case error = "商品交易失败" case catchError = "后台验证接口崩溃" case end = "商品交易完成" case transactionEnd = "扣款成功" case guaJiePayURLError = "挂接中心回调地址请求失败" } /** 回调 */ var callBack:FastApplePayBlock? /** 商品ID */ var gamebuyGoodId:String? /** 服务器回调地址 */ var gamePayCallbackUrl:String? /** 订单号 */ var gameAppPayIdentifier:String? /** 商品 */ var product:SKProduct? /** 服务器验证字典参数 */ var userPayParame:Dictionary<String,Any>? var productList:Array<Dictionary<String,Any>> = [] // 商品列表 var isGetProductList = false // 是否是获取商品列表信息 var productListCallBack:FastStrBlock? // 商品列表回调 /** 购买商品 */ public func buyProduct(param:Dictionary<String,Any>,blcok:@escaping FastApplePayBlock) { self.callBack = blcok self.isGetProductList = false print(param) if let gamebuyGoodId = param.string("productId"),let gamePayCallbackUrl = param.string("notify_url") { self.gamePayCallbackUrl = gamePayCallbackUrl self.gamebuyGoodId = gamebuyGoodId userPayParame = param.value("data") as? Dictionary<String,Any> if SKPaymentQueue.canMakePayments(){ let productsRequest = SKProductsRequest(productIdentifiers: [gamebuyGoodId]) productsRequest.start() productsRequest.delegate = self callBack(.start, orderid: nil, desc:nil) }else{ FastLog.error("无法支付-----") print("无法支付-----") } }else{ FastLog.error("参数错误") print("参数错误") } } /** 支付状态回调 */ func callBack(_ state:FastApplePayState,orderid:String?,desc:String?){ self.callBack?(state,orderid,desc) } /** 成功处理 */ func completeTransaction(transaction: SKPaymentTransaction){ if let gamePayCallbackUrl = self.gamePayCallbackUrl,let gameAppPayIdentifier = transaction.transactionIdentifier,let url = Bundle.main.appStoreReceiptURL{ if let data = try? Data(contentsOf: url) { // 凭证 let receipt = data.base64EncodedString(options: .endLineWithLineFeed) userPayParame?["transaction_id"] = gameAppPayIdentifier FastNetWorking.shared.post(inUrl: gamePayCallbackUrl, parameDic: userPayParame, receipt) {[weak self] suc in print("status:\(suc.dic?.value(Int.self,"status"))") //判断服务器凭证验证状态 if let status = suc.dic?.value(Int.self,"status"){ if status != 1{ self?.callBack(.payFailed, orderid: gameAppPayIdentifier, desc: suc.dic?.string("msg")) return } SKPaymentQueue.default().finishTransaction(transaction) self?.callBack(.end, orderid: gameAppPayIdentifier, desc: suc) }else{ self?.callBack(.payFailed, orderid: gameAppPayIdentifier, desc: suc.dic?.string("msg")) } } fai: {[weak self] str in self?.callBack(.payFailed, orderid: gameAppPayIdentifier, desc: str) } }else{ callBack(.payFailed, orderid: nil, desc: nil) } }else{ callBack(.payFailed, orderid: nil, desc: nil) } } /** 失败处理 */ func failedTransaction(transaction: SKPaymentTransaction){ if let err:SKError = transaction.error as? SKError { if err.code == SKError.Code.paymentCancelled{ //交易取消 callBack(.cancel, orderid: nil, desc: nil) }else{//购买失败 callBack(.failed, orderid: nil, desc: nil) } } SKPaymentQueue.default().finishTransaction(transaction) } // MARK: 商品信息回调 public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { print("商品信息回调 response.products = \(response.products)") FastLog.debug(response.products) if response.products.count > 1{ if self.isGetProductList{ self.callBackProductList(list: response.products) } }else{ if let product = response.products.first { print("Product title: \(product.localizedTitle)") print("Product description: \(product.localizedDescription)") print("Product price: \(product.price)") print("Product productIdentifier: \(product.productIdentifier)") print("Product priceLocale: \(product.priceLocale)") print("地区编码: \(product.priceLocale.identifier)") print("货币代码: \(String(describing: product.priceLocale.currencyCode))") print("货币符号: \(String(describing: product.priceLocale.currencySymbol))") if #available(iOS 16, *) { FastLog.log("地区语言: \(product.priceLocale.language)") } else { // Fallback on earlier versions } self.product = product // 发起请求 let payment = SKPayment(product: self.product!) SKPaymentQueue.default().add(payment) SKPaymentQueue.default().add(self) }else{ print("商品信息列表获取失败 response.products = \(response.products)") //商品信息列表获取失败 callBack(.productContent, orderid: nil, desc: nil) } } } // MARK: 失败执行的方法 public func request(_ request: SKRequest, didFailWithError error: Error) { callBack(.error, orderid: nil, desc: nil) print("货币符号error: \(error)") } // MARK: 购买完成 public func requestDidFinish(_ request: SKRequest) { callBack(.success,orderid: gamebuyGoodId,desc: nil) } // MARK: - SKPaymentTransactionObserver public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { FastLog.debug(transaction.transactionState) switch transaction.transactionState { case .purchased: FastLog.debug("purchased") // 交易完成 completeTransaction(transaction: transaction) callBack(.transactionEnd, orderid: nil, desc: nil) break case .failed: FastLog.debug("failed") // 处理购买失败的逻辑 failedTransaction(transaction: transaction) break case .restored: FastLog.debug("restored") // 处理购买或恢复购买的逻辑 queue.finishTransaction(transaction) default: break } } } /// 查询苹果是否有需要补单的订单 /// - Returns: 结果 public func selectPayDropOrder() -> Bool{ if SKPaymentQueue.default().transactions.count > 0{ return true }else{ return false } } /// 返回掉单支付所有订单对象 /// - Returns: 结果 public func allTransaction() -> Array<SKPaymentTransaction>{ return SKPaymentQueue.default().transactions } public func getLocalInfo(productList:String,callBack:@escaping FastStrBlock){ self.productListCallBack = callBack self.isGetProductList = true if let dic = productList.dic{ if let arr = dic.value(Array<Dictionary<String,Any>>.self, "product_list"){ var productIds:Set<String> = [] for product in arr{ if let data:Dictionary<String,Any> = product as? Dictionary<String, Any>{ self.productList.append(data) if let product_id = data.string("product_id"){ productIds.insert(product_id) } } } if productIds.count > 0{ let productsRequest = SKProductsRequest(productIdentifiers: productIds) productsRequest.delegate = self productsRequest.start() print("productId start .. ") }else{ print("productIds 为空 直接返回JSON数据\(productList)") callBack(productList) } }else{ print("productList JSON解析错误 直接返回JSON数据\(productList)") callBack(productList) } }else{ FastLog.debug("productList JSON解析错误 直接返回JSON数据\(productList)") callBack(productList) } } func callBackProductList(list:Array<SKProduct>){ var newProductList:Array<Dictionary<String,Any>> = [] for product in list{ print("新商品列表 product = \(product)") for data in self.productList{ print("新商品列表 data = \(data)") if product.productIdentifier == data.string("product_id"){ var newData = data newData["local"] = ["price":product.price, "currencyCode":product.priceLocale.currencyCode ?? "", "title":product.localizedTitle, ] newProductList.append(newData) } } } self.productListCallBack?(["product_list":newProductList].json) } }