网站建设国内排行,深圳坑梓网站建设,商场网站开发,wordpress 例子前言
Hello#xff01;又是很长时间没有写博客了#xff0c;因为最近又开始从事新项目#xff0c;也是第一次接触关于uniapp开发原生IOS应用的项目#xff0c;在这里做一些关于我在项目中使用苹果内购支付所实现的方式以及要注意的事项#xff0c;希望能给正在做uniapp开…前言
Hello又是很长时间没有写博客了因为最近又开始从事新项目也是第一次接触关于uniapp开发原生IOS应用的项目在这里做一些关于我在项目中使用苹果内购支付所实现的方式以及要注意的事项希望能给正在做uniapp开发ios应用需要使用苹果内购支付的小伙伴一些帮助
问题
为什么开发ios应用需要使用苹果内购支付
原因在于苹果要求所有开发者在上架Appstore中的应用如果应用中出现了虚拟商品的购买必须使用苹果内购支付并且绝对不能出现其他支付方式例如微信、支付宝等支付方面的sdk当然如果你不怕被苹果下架的风险你可以尝试使用webview跳转的方式但是如果你的代码中使用了其他支付方式的sdk或者代码是很大可能无法通过苹果严格的审核的。
ios内购为什么要专门拿出来说对比其他支付方式有什么区别吗
首先他与微信、支付宝等都属于支付渠道的一种本质上没有区别但是由于苹果服务器的原因导致一些非常特殊的问题例如回调时间长甚至没有回调、掉单、回调异常等情况这种情况对比其他支付方式真的很鸡肋特别是在uniapp的开发环境下居然没有超时的回调简直是大坑不过这个在后面我会提到解决方案。
ios内购事务
苹果支付走的是事务列表每生成一笔订单就会走一笔订单如果已经完成的订单需要使用苹果提供的关闭订单的api来进行关闭订单否则会出现回调有误的情况。
实现步骤
Unipay不常用
由于我使用的是uniapp开发原生应用本身uniapp对于支付方式就有专门的封装如果你没有后端那你可以尝试使用uniPay下面是文档的链接 Unipay官方文档
基本用法常用
使用uniapp的uni.requestPayment来实现是比较常用的方式下面是支付的文档不过看看就好还是有挺多坑的具体的支付流程可以参考一下官方文档不过逻辑还有代码的正确性需要自己考量下面我会介绍我的方式
苹果支付
获取iap通道
获取iap通道是判断当前设备是否支持苹果内购支付的必要条件所以一定要先判断是否含有iap支付通道如果含有支付通道才可以走支付逻辑否则直接return即可不需要任何逻辑。
export function Init() {return new Promise((resolve, reject) {//使用uni.getProvider来获取通道uni.getProvider({service: payment,success: (res) {let iapChannel res.providers.find((channel) {return (channel.id appleiap)})//成功之后会返回通道resolve(iapChannel)},})})
}返回示例 如果你获取到的iap通道为null那么你可以直接return因为当前环境是不支持苹果内购支付的也就不用走其他逻辑了。
获取已完成但未支付的订单
由于苹果服务器的原因导致某些情况会出现回调时间长甚至没有回调的情况因此这一步必须要做因为如果不做这一步操作会导致下一次的支付回调了上一次的事务这种异常情况。 其中获取订单和关闭订单是一起操作的所以我把他们整合在了一起。 获取订单
export function restore(iapChannel) {console.log(获取苹果服务器已支付且未关闭的交易列表)return new Promise((resolve, reject) {iapChannel.restoreCompletedTransactions({manualFinishTransaction: true,username: }, (res) {resolve(res)}, (err) {reject(err);})});
}关闭订单
export function finishTransaction(transaction, iapChannel) {console.log(关闭订单)return new Promise((resolve, reject) {iapChannel.finishTransaction(transaction, (res) {console.log(关闭订单成功, res)resolve(res);}, (err) {reject(err);});});
}整合 export function getReview(iapChannel, token, dev) {//请求是否有已完成未关闭的订单restore(iapChannel).then(res {//如果有并且状态为已支付则请求关闭并回调给后端console.log(res)if (res.length 0) {//轮询关闭订单res.map(item {finishTransaction(item, iapChannel)//如果状态为已完成的状态if (item.transactionState 1) {//后端逻辑此处省略通常是完成上报凭证的操作来完成补单//请求后端接口上传支付凭证 submitMisson(PayBack, productId, iapChannel).then(res {uni.showToast({icon: none,title: 上一笔订单已支付成功请稍后留意余额})console.log(res)})}})} })
}注意事项
这里可以选择在合适的时机进行调用可以选择静默处理因为在支付的过程中是不会允许移除事务的所以如果调用获取订单的回调时间长也可以不用处理但一定要做这一步操作。
请求苹果档位列表
这一步一定要做否则无法拉起内购支付目的就是判断当前的内购档位信息是否有配置在苹果后台中。
/*** 调用ID为“appleiap”的PaymentChannel对象的requestOrder方法像Appstore请求有效的商品详情。* 注意IAP支付必须在调用payment.request方法之前调用requestOrder方法否则调用payment.request将会报错。*/
export function requestOrder(iapChannel, productIds) {uni.showLoading({title: 初始化中~,mask: true})return new Promise((resolve, reject) {iapChannel.requestOrder(productIds, (orderList) { //必须调用此方法才能进行 iap 支付console.log(requestOrder success: JSON.stringify(orderList));resolve(orderList)uni.hideLoading()}, (e) {console.log(requestOrder failed: JSON.stringify(e));uni.hideLoading()uni.showToast({icon: none,title: 当前环境不支持内购支付})reject(e)});})
}
拉起支付
这里建议将manualFinishTransaction设置为true,手动关闭订单否则自动关闭订单可能出现订单关闭失效的情况。
uni.requestPayment({provider: appleiap,orderInfo: {manualFinishTransaction: true, //true为手动关闭订单false为自动关闭订单username: res.data.osn, //透传参数productid: productId, //档位id},success: (e) {// e 类型为 Transaction, 详见下面的描述//后端逻辑省略轮询订单情况}
})踩过的坑
回调时间长导致掉单
如果你的应用有客服反馈的功能那么可以申请客服反馈查询后端订单情况进行补单的操作。 如果没有那么你就只能手动补单一般来说补单需要提供订单号和票据信息。 但是由于用户手动关闭应用导致订单号丢失票据信息和订单号对应起来因此我们要做一个手动队列的处理。
解决方案在用户下单时候将订单号和档位id关联起来做一个队列
也就是key档位idvalue: 订单号数组
原因是用户可以关闭应用之后重新点击支付生成了一笔新的订单号但是回调是上一笔的票据因此需要做一个订单号数组。
每次支付的时候获取缓存中的队列数据如果该档位存在订单号说明上一笔订单并没有上报成功因此取队列中的第一个订单号作为上报订单上报成功之后将这笔订单移除这样就不会影响用户的正常支付获取到上一笔订单的回调问题影响页面逻辑。
例如支付成功跳转成功落地页但是回到的信息是上一笔订单这种现象。
主动关闭订单
由于上一步操作虽然正常上报但是并没有将已完成的订单移除所以我们还需要做一个队列用来移除已完成的订单。 上报成功之后将票据和osn作为队列放入缓存中这一步其实是为了判断订单是否已经关闭。
由于苹果服务器的原因很可能你主动调用关闭订单没有立即关闭所以你需要在进入应用的时候重新主动关闭。