问题为什么开发ios应用需要使用苹果内购支付?原因是什么?

2024-03-25
来源:网络整理

前言

! 很久没有写博客了,因为最近开始做新的项目,第一次接触到开发原生IOS应用程序的项目。 以下是我在项目中如何使用 的应用内购买支付以及如何实现它的一些信息。 要注意的事情,希望能给正在开发ios应用,需要使用苹果内购支付的朋友一些帮助!

问:为什么开发ios应用时需要使用苹果的内购支付?

原因是苹果要求所有开发者在上架的应用程序中购买虚拟商品。 必须使用苹果的应用内购买,不得使用其他支付方式,如微信、支付宝等支付SDK。 当然,如果你不怕被苹果下架的风险,你可以尝试使用跳转方式,但如果你的代码使用了其他支付方式的SDK或者代码,那么很有可能不会通过的严格审查。

为什么特别提到iOS应用内购买? 与其他付款方式相比有什么区别吗?

首先,它和微信、支付宝等一样都是支付渠道的一种,本质上没有区别。 但由于苹果服务器的原因,导致了一些很特殊的问题,比如:回调时间长甚至不回调、掉单、回调异常等。这种情况相对于其他支付方式来说确实没什么用,尤其是在开发环境下,没有超时回调,这是一个很大的坑,不过稍后我会提到解决方案。

ios应用内购买、交易

Pay 使用交易列表。 每次生成订单时,都会下订单。 如果已完成的订单需要使用提供的平仓API进行平仓,否则会出现回调错误。

前期准备启用应用内购买

您需要在iOS开发者平台拥有开发者账号,申请内购支付,并配置相应的内购装备名称和参数。

应用内购买级别需要配置为ios后端可用的级别。 ios等级有指定数量,不是自定义等级数量。

注意:这里的齿轮ID需要配置到后端并返回到前端。 需要和苹果后台配置一一对应,否则上拉失败!

定制基础包

注意,测试支付需要制作自定义基础包并配置相应的证书。 证书可以参考文档进行配置。 测试证书制作官方包无法测试和付费,只能用于定制基础包。

获取应用内购买凭证

正式上线

正式上线需要将证书更换为官方证书,并通过软件进行进一步测试!

实施步骤(不常用)

由于我使用的是本机应用程序,因此我有一个针对付款方式的特殊包。 如果您没有后端,可以尝试使用它。 这是该文档的链接。

基本用法(常用)

这是使用uni的常见方式。 下面是付款单据,不过看一下,还是有很多坑的。 具体的支付流程可以参考官方文档,但是代码的逻辑和正确性需要大家自己思考,下面介绍一下我的方法

启用应用内购买模块

检查 .json 文件中的 () 中的应用内支付。

注意:如果您开发原生iOS应用,请勿勾选其他支付模块。

获取iap频道

获取iap通道是判断当前设备是否支持苹果内购支付的必要条件,所以首先要判断是否包含iap支付通道。 如果包含支付通道,则可以使用支付逻辑。 否则直接就可以了,没有任何逻辑。

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,那么直接就可以了,因为当前环境不支持苹果内购支付,所以不需要使用其他逻辑。

完成但未付款的订单

由于苹果服务器的原因,在某些情况下,回调时间可能会较长,甚至可能没有回调。 所以这一步是必须要做的,因为如果不做这一步,下次支付就会回调之前的交易。 异常情况。

其中拿单和平单是一起操作的,所以我把它们整合到了一起。

获取订单

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

拉起付款

建议将 ion 设置为 true 并手动关闭订单。 否则如果订单自动平仓,可能会导致平仓失败。

uni.requestPayment({ provider: 'appleiap', orderInfo: { manualFinishTransaction: true, //true为手动关闭订单,false为自动关闭订单 username: res.data.osn, //透传参数 productid: productId, //档位id }, success: (e) => { // e 类型为 Transaction, 详见下面的描述 //后端逻辑省略 轮询订单情况 } })

踩过的坑回调时间长,导致掉单。

如果您的应用有客服反馈功能,您可以申请客服反馈来查看后端订单状态并进行补货操作。

如果没有,那么您只能手动填写订单。 一般来说,填写订单需要提供订单号和账单信息。

但是,由于用户手动关闭了应用程序,导致订单号丢失,而订单号对应的票证信息,所以我们不得不进行手动排队过程。

解决方案:用户下单时,关联订单号和摊位id,创建队列

即key:摊位id,:订单号数组

原因是用户关闭应用再次点击支付后,生成了新的订单号,但回调的是之前的订单号,所以需要创建一个订单号数组。

每次支付时获取缓存中的队列数据。 如果槽位中有订单号,则说明之前的订单没有上报成功。 因此,将队列中的第一个订单号作为报告的订单。 举报成功后,会将这笔金额的订单移除,这样就不会影响用户正常支付,获取上一笔订单的回调问题,影响页面逻辑。

例如:支付成功,登陆页面重定向,但返回的信息是之前的订单。

主动平仓

由于之前的操作正常上报,所以没有移除已完成的订单,所以我们还需要创建一个队列来移除已完成的订单。

上报成功后,将和osn作为队列,放入缓存中。 这一步实际上是判断订单是否已平仓。

由于苹果服务器的原因,很有可能你主动调用了关闭指令并没有立即关闭,所以需要在进入app时再次主动关闭。

苹果召回了之前订单中的注释

这是一个比较奇怪的问题,但回想起来也是可以理解的。 由于苹果服务器的回调时间较长,不仅支付回调慢,就连关闭订单的回调也很慢,导致用户付款后无法支付。 下单时,之前的订单并未完全平仓。 结果,当用户支付第二笔订单时,回调的结果是上一笔订单的票。 因此,建议手动平仓,并选择合适的平仓时间。

解决方案:

我们可以在本地创建一个本地队列。 当有回调时,检查本地队列中是否有该票对应的订单号。 如果存在,则取出用于上报的osn,并删除对应的队列。 如果不存在,只需将工单与订单号关联存储,然后进行报单、平仓操作即可。 这主要是考虑到用户主动关闭app长时间没有回调的情况,以便用户下次点击时主动上报。

整体流程图

注意:验证格式不正确

如果您举报凭证并发现返回的凭证格式不正确:

请查看官方文档:

https://developer.apple.com/documentation/appstorereceipts/verifyreceipt

这里的凭证是需要通过的,但是我们通过官方API调用的支付方式,返回的凭证已经通过了,请不要再重复,否则验证无效!

错误

如果之前后端验证凭证正确,但是沙盒验证时突然报错,很可能是因为苹果在后端配置了续费类型产品,所以验证时需要额外传入一个字段。

消耗类型的传这个参数:{ "receipt-data": "交易凭证" } 订阅类型的要传多一个参: { "receipt-data": "交易凭证", "password" : "将生成的专用秘钥填入" }

注:只要是非消耗品的产品,都可能需要添加关键验证参数(即使使用苹果原生产品不通过验证也能通过,笔者对此很困惑)

分享