iOS内购支付

news/2024/12/2 14:49:40/文章来源:https://www.cnblogs.com/supersr/p/18581883
//import StoreKit@objcMembers public class FastApplePay: NSObject, SKPaymentTransactionObserver, SKProductsRequestDelegate {public static let shared = FastApplePay()public typealias FastApplePayBlock = (FastApplePayState,String?,String?)->Voidpublic 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 = blcokself.isGetProductList = falseprint(param)if let gamebuyGoodId = param.string("productId"),let gamePayCallbackUrl = param.string("notify_url") {self.gamePayCallbackUrl = gamePayCallbackUrlself.gamebuyGoodId = gamebuyGoodIduserPayParame = param.value("data") as? Dictionary<String,Any>if SKPaymentQueue.canMakePayments(){let productsRequest = SKProductsRequest(productIdentifiers: [gamebuyGoodId])productsRequest.start()productsRequest.delegate = selfcallBack(.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"] = gameAppPayIdentifierFastNetWorking.shared.post(inUrl: gamePayCallbackUrl, parameDic: userPayParame, receipt) {[weak self] suc inprint("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 inself?.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: - SKPaymentTransactionObserverpublic 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)breakcase .failed:FastLog.debug("failed")// 处理购买失败的逻辑failedTransaction(transaction: transaction)breakcase .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 = callBackself.isGetProductList = trueif 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 = selfproductsRequest.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 = datanewData["local"] = ["price":product.price,"currencyCode":product.priceLocale.currencyCode ?? "","title":product.localizedTitle,]newProductList.append(newData)}}}self.productListCallBack?(["product_list":newProductList].json)}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845441.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fetch call web api upload or update picture

昨天C# + html + fetch + API + javascript https://www.cnblogs.com/insus/p/18579193 其中有一个图片相关的功能,现把它解说一下。html页面上,简单的input和button,无需何附加<form action="/action_page_binary.asp" method="post" enctype="…

长期主义下的一本经济账:卷价格更要卷性能

「 不做陪跑者,要做支撑者。企业成长的每个关键时刻,在背后默默发力。」今年以来,云的价格战似乎更猛烈了一些。 事实上,云服务降价在规模与创新两重推动力下早就是一种常态。作为云的鼻祖,亚马逊云经常是一年连续降价十几次甚至几十次。这种理性降价,是将规模红利与创新…

“天翼云息壤杯”高校AI大赛福建赛区启动!

11月20日,2024首届全国“天翼云息壤杯”高校AI 大赛(福建赛区)正式启动。中国电信福建公司携手华为公司、福建省计算机学会、福建省自动化学会,正式启动天翼云科技有限公司承办的“天翼云息壤杯”高校AI大赛(福建赛区)赛事。该赛事是中国电信搭建的进一步挖掘培养AI人才、…

从挑战到突破:HBlock定义智算存储新范式!

近日,由DOIT传媒主办,中国计算机学会信息存储专委会、武汉光电国家研究中心、百易存储研究院支持的2024中国数据与存储峰会在北京召开。此次峰会以“智数据 AI未来”为主题,天翼云科技有限公司国际业务事业部存储产品线专家肖夏敏代表参会,并发表“轻量级存储集群控制器HBl…

html2canvas 解决某些站点截图空白问题

业务场景介绍 点击浏览器右上角已安装的chrome插件图标,这个时候会出现一个界面,我们称这个界面为popup,界面上有个"从页面获取产品信息"按钮,单机它会对当前标签页面内容进行截图,最后将截图的图片转成base64发送至xx接口 部分核心代码解读:截取当前可视区域的…

领歌看板助力电商大促筹备

每年的“双11”“双12”“618”等大型电商促销活动是各企业的年度重头戏,但涉及环节众多、协作复杂,稍有疏漏就可能影响活动效果。领歌看板为您提供了一种高效、直观的任务管理方式,确保每一步都尽在掌握。 1. 全面覆盖任务场景,理清活动脉络 利用领歌看板,您可以将大促活…

.NET开发WinForm(C/S)项目整合三种SOA服务访问(直连、WCF、WebAPI)模式

在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。目前主流的方式就三种:数据库直连、WCF模式、WebAPI模式。RDIF…

mysql 之查询条件!=或者存在问题,会被轻易忽略而且影响查询结果

mysql数据库查询,我们再使用sql条件时会经常使用!=(<>),但使用!=之后,这个字段对应的为空的值不会查出来。所以建议!=长春与is null同时用 查询结果测试如下: 我们先查询满足条件的数据;id上下相同,同时此id的对应的paln_status查询如图是空的: 咱们再来查询总…

Postman 安装与汉化超详细步骤全解析教程

下载安装包 首先,我们需要获取 Postman 的安装包。为了方便,链接提供了安装包跟汉化包 点击获取postman安装及汉化包 为什么要提供安装包跟汉化包? 汉化包和postman的版本必须是一致的,如果不一致就会出现汉化后无法打开postman的问题; 注意:如果想要汉化的就不能使用最新…

文档比对新玩法:从文本细节到逻辑洞察

在学术研究和项目管理中,文档的版本对比和差异检查往往是个被低估却至关重要的环节。尤其是在跨学科合作或大型团队中,不同版本的文档往往在细节上存在微妙变化,而这些变化可能直接影响研究结论、策略决策甚至是整个项目的方向。 传统的文档对比工具往往局限于纯文本比对,这…

有效管理win11系统开机启动项

平时如果有你不想随着系统开机就启动的软件,可以通过下面的方式进行设置。个人推荐使用这个办法 1.首先点击开始菜单2.点击“设置”3.再点击左边栏“应用”选项4.然后点击其中的“启动”设置5.选择开关按钮,即可设置启动或禁用

ai大模型流式输出------基于SSE协议的长连接实现ax

传统的http1.0请求开发,已经满足了我们日常的web开发。一般请求就像下图这样子,客服端发起一个请求(触发),服务端做出一个响应(动作): 有时会有诸如实时刷新,实时显示的场景,我们往往是客户端定时发起请求,不断的尝试获取最新的数据。但是每次请求都会创建并释放一个…