【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

这篇具有很好参考价值的文章主要介绍了【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

Hello!又是很长时间没有写博客了,因为最近又开始从事新项目,也是第一次接触关于uniapp开发原生IOS应用的项目,在这里做一些关于我在项目中使用苹果内购支付所实现的方式以及要注意的事项,希望能给正在做uniapp开发ios应用需要使用苹果内购支付的小伙伴一些帮助!

问题

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

原因在于,苹果要求所有开发者在上架Appstore中的应用,如果应用中出现了虚拟商品的购买,必须使用苹果内购支付,并且绝对不能出现其他支付方式,例如微信、支付宝等支付方面的sdk,当然,如果你不怕被苹果下架的风险,你可以尝试使用webview跳转的方式,但是如果你的代码中使用了其他支付方式的sdk或者代码,是很大可能无法通过苹果严格的审核的。

ios内购为什么要专门拿出来说,对比其他支付方式有什么区别吗?

首先,他与微信、支付宝等都属于支付渠道的一种,本质上没有区别,但是由于苹果服务器的原因,导致一些非常特殊的问题,例如:回调时间长甚至没有回调、掉单、回调异常等情况,这种情况对比其他支付方式真的很鸡肋,特别是在uniapp的开发环境下,居然没有超时的回调,简直是大坑,不过这个在后面我会提到解决方案。

ios内购,事务

苹果支付走的是事务列表,每生成一笔订单就会走一笔订单,如果已经完成的订单需要使用苹果提供的关闭订单的api来进行关闭订单,否则会出现回调有误的情况。

前期准备

开通内购

你需要拥有ios开发者平台的开发者账号,申请开通内购支付,并配置相应的内购档位名称和参数。

内购档位需要配置ios后台有的档位,ios档位是有规定指定的金额,不是自定义档位金额的。

注意:此处的档位id需要配置到后端返回给前端,需要跟苹果后台配置的一一对应,否则也会拉起失败!

自定义基座包

注意,测试支付需要制作自定义基座包,需要配置相应的证书,证书可以参考uniapp的文档进行配置。测试证书制作正式包无法测试支付,只能用于自定义基座包。
【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)
获取内购证书

正式上线

正式上线需要将证书替换为正式证书,通过testfight软件进行进一步测试!

实现步骤

Unipay(不常用)

由于我使用的是uniapp开发原生应用,本身uniapp对于支付方式就有专门的封装,如果你没有后端,那你可以尝试使用uniPay,下面是文档的链接
Unipay官方文档

基本用法(常用)

使用uniapp的uni.requestPayment来实现是比较常用的方式,下面是支付的文档,不过看看就好,还是有挺多坑的,具体的支付流程可以参考一下官方文档,不过逻辑还有代码的正确性需要自己考量,下面我会介绍我的方式

苹果支付

开启内购模块

在manifest.json文件中勾选Payment(支付)中的Apple应用内支付。

注意:不要勾选其他支付模块,如果你开发ios原生应用的话。
【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

获取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)
      },
    })
  })
}
返回示例

【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)
如果你获取到的iap通道为null,那么你可以直接return,因为当前环境是不支持苹果内购支付的,也就不用走其他逻辑了。

获取已完成但未支付的订单

由于苹果服务器的原因,导致某些情况会出现回调时间长甚至没有回调的情况,因此,这一步必须要做,因为如果不做这一步操作,会导致下一次的支付回调了上一次的事务这种异常情况。
其中,获取订单和关闭订单是一起操作的,所以我把他们整合在了一起。

【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

获取订单

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)
          })
        }
      })
    } 
  })
}
注意事项

这里可以选择在合适的时机进行调用,可以选择静默处理,因为在支付的过程中,是不会允许移除事务的,所以如果调用获取订单的回调时间长,也可以不用处理,但一定要做这一步操作。
【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

请求苹果档位列表

这一步一定要做,否则无法拉起内购支付,目的就是判断当前的内购档位信息是否有配置在苹果后台中。

/**
 * 调用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:档位id,value: 订单号数组

原因是用户可以关闭应用之后,重新点击支付,生成了一笔新的订单号,但是回调是上一笔的票据,因此需要做一个订单号数组。

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

例如:支付成功跳转成功落地页,但是回到的信息是上一笔订单这种现象。

主动关闭订单

由于上一步操作虽然正常上报,但是并没有将已完成的订单移除,所以我们还需要做一个队列,用来移除已完成的订单。
上报成功之后,将票据和osn作为队列,放入缓存中,这一步其实是为了判断订单是否已经关闭。

由于苹果服务器的原因,很可能你主动调用关闭订单,没有立即关闭,所以你需要在进入应用的时候重新主动关闭。

苹果回调了上一笔订单的票据

这也算是一个比较奇怪的问题,不过回想也是可以理解的,由于苹果服务器回调时间长的问题,不仅仅是支付回调慢,就连关闭订单的回调也是非常慢,这就导致了用户在支付下一笔订单时,上一笔订单并没有完全关闭,结果就是用户在支付第二笔订单时回调的结果是上一笔订单的票据,因此推荐手动关闭订单,自己选择合适的时机去关闭订单

解决方案:
我们可以在本地做一个本地队列,在有回调的时候,检查本地队列是否含有本次票据对应的订单号,如果存在,就将osn拿出来进行上报,并删除对应的队列,如果不存在,就将票据和订单号进行关联存放,然后进行上报和关闭订单的操作,这里主要是考虑到长时间没有回调用户主动关闭app的情况,在用户下一次点击的时候能够主动帮他进行上报

总体流程图

【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

注意事项

校验格式不正确

如果上报苹果凭证发现苹果返回凭证格式不正确的问题:

请注意查看官方文档:

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

这里的凭证需要经过base64,但是我们通过uniapp官方api调用的支付方式,返回的凭证是已经经过了base64的,请不要再base64,否则就会校验失效!

21003错误

如果之前后端校验凭据无误,但是突然沙箱校验报21003的错误,很大可能是由于苹果后台配置了续费类型的产品,那么你需要在校验的时候多传一个password字段

【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

消耗类型的传这个参数:{
                                          "receipt-data": "交易凭证"
                                          }

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

注意:只要存在不属于消耗型的产品,就可能需要加上密钥校验参数(使用苹果原生不传也能校验通过,作者对此表示非常疑惑)文章来源地址https://www.toymoban.com/news/detail-424453.html

到了这里,关于【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • uniapp之boundingClientRect注意事项

    1.页面中使用 2.组件中使用增加 in(this) 或使用 this.createSel.....   3.其他写法 4.boundingClientRect返回值为null    1.确保页面已经渲染完成再计算高度,即已存在该id标识的元素,常见解决办法是 增加定时器延迟100ms,或在onLoad中去调用。    2.对view动态设置id时, 确保id首位是字母

    2024年02月11日
    浏览(28)
  • RN_iOS项目编译注意事项

    打包脚本(buildRNiOSBunble.sh) 1 编译RN代码 bjy_rnreactnative分支和bjy_ios原生分支放在同级目录下,进入bjy_rn目录 更新最新rn代码 编译rn代码 node_modules引入 yarn install 2 生成.jsbundle文件 react-native bundle --entry-file index.js --bundle-output …/bjy_ios/ w o r k s p a c e n a m e / {workspace_name}/ w or k s p a c

    2024年02月05日
    浏览(42)
  • 个人首次使用UniAPP使用注意事项以及踩坑

    uni-create-view 快速nui-app页面的 uni-helper uni-app代码提示的 uniapp小程序扩展 鼠标悬停查文档 TypeScript Vue Plugin (Volar) Vue Language Features (Volar) Eslint Prettier 禁用 Error Lens 行内提示报错 Turbo Console Log 打log插件 Code Spell Checker 检查拼写插件 files.associations 官网解释: https://cn.vuejs.org/guide/t

    2024年02月11日
    浏览(34)
  • 51单片机io口的应用,注意事项及实例代码并标注

      51单片机是一种广泛使用的8位微控制器,它具有多个I/O(输入/输出)端口。根据不同的厂商,51单片机可能有不同数量的I/O端口。在此,我们以常见的AT89C51单片机为例,讨论其各I/O端口的区别及应用实例。 1. P0端口:P0端口为地址/数据复用端口,其控制信号线共用。在实际

    2024年02月06日
    浏览(39)
  • uniapp开发安卓App注意事项(HTML5+规范 plus调用安卓原生能力:广播,扫描,相机等)

    使用安卓调试基座进行调试大大降低了uniapp开发安卓app的门槛 安卓开发经常需要调用到安卓原生的api,例如广播,扫码,相机等等,uniapp内置了App端的HTML5+规范,可以使用js直接调用丰富的原生能力。例如在安卓中调用原生的激光扫描能力: 该plus对象便是uniapp内置的HTML5+规

    2024年03月19日
    浏览(38)
  • uniApp微信小程序唤出授权头像昵称(微信授权登录)弹窗,及服务端用户信息解密注意事项

    头像昵称弹窗弹出条件:button授权按钮 + uni.getUserProfile API请求 1.H5部分 2.JS部分 注意事项: 不能嵌入其他API内调用,一定要在调用的方法中第一层执行(优先执行 uni.getUserProfile ) 正确做法 :必须第一步用户点击按钮,第二步调取 uni.getUserProfile API(调取 uni.getUserProfile 操作

    2024年02月11日
    浏览(47)
  • Electron中苹果支付 Apple Pay inAppPurchase 内购支付

    正在开发中,开发好了,写一个完整详细的过程,保证无脑集成即可 一般情况下,在你看这篇文章的时候,说明你已经开发的app差不多了。 但是要上架app到Mac App Store,则要在appstoreconnect这个地方创建一个app。 在此处创建一个有两种方法:一是 在mac上下载transfore的一个官方

    2024年01月19日
    浏览(26)
  • iOS_苹果内购详细步骤

    什么是Apple Pay? 简单说是一种“支付工具”。对于国外流行信用卡,Apple Pay很符合美国的国情。但对于中国,微信支付、支付宝支付更加便利符合中国的人的行为习惯。 说到这你可能就理解了,Apple Pay,就是类比支付宝类似的线上线下支付工具。 Apple Pay和 支付宝、微信一样

    2023年04月09日
    浏览(28)
  • 学习Linux的注意事项(使用经验;目录作用;服务器注意事项)

    本篇分享学习Linux过程中的一些经验 Linux严格区分大小写 Linux中所有内容以文件形式保存 ,包括硬件,Linux是以管理文件的方式操作硬件 硬盘文件是 /dev/sd[a-p] 光盘文件是 /dev/sr0 等 对于设置需要写入文件,命令行的设置在重启之后就会失效,只有下入文件才可以保存下来 文

    2024年02月11日
    浏览(56)
  • uniapp - 超详细实现播放 svg / svga 格式动画组件插件,用于直播间赠送礼物特效动画或项目动画特效较多的应用(新手小白保姆级教程,提供插件+详细运行示例+使用文档+注意事项+格式说明)

    网上关于 uniapp 播放 svg / svga 格式动画的教程很乱,基本上全是 BUG 和各种不兼容,很难复制过来自己用。 本文实现了 在 uniapp 项目中(完美兼容 H5 / App / 微信小程序平台),播放 svg / svga 格式动画功能的详细介绍, 您只需要使用我提供的 “组件源码及插件”,放到项目中去

    2023年04月24日
    浏览(149)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包