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)
        
    }
}

 

posted @ 2024-12-02 14:45  super1250  阅读(9)  评论(0编辑  收藏  举报