当前位置: 首页 > news >正文

【苹果内购支付】关于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:档位id,value: 订单号数组

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

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

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

主动关闭订单

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

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

相关文章:

【苹果内购支付】关于uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑

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

一:BT、BLE版本说明及对比

蓝牙版本说明1.常见名词说明2.BT&BLE特性对比3.BT各版本对比4.BLE各版对比1.常见名词说明 名称说明BR(Basic Rate)基本码率EDR(Enhanced Data Rate)增强码率BLE(Bluetooth Low Energy)低功耗蓝牙HS(High Speed)高速蓝牙BT(BlueTooth)蓝牙技术LE(Low Energy)低能耗AFH(Adap…...

php宝塔搭建部署实战多模板cms管理系统源码

大家好啊,我是测评君,欢迎来到web测评。 本期给大家带来一套php开发的多模板cms管理系统源码。感兴趣的朋友可以自行下载学习。 技术架构 PHP7.0 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码,宝塔添加一…...

【数据结构初阶】手把手带你实现栈

前言 在进入数据结构初阶的学习之后,我们学习了顺序表和链表,当然栈也是一种特殊的数据结构,他的特点是后进先出。 栈的概念及结构 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删…...

liunx 端口号开放和关闭

1.先查看防火墙是否开启的状态,以及开放端口的情况: systemctl status firewalld.service(查看防火墙开启还是关闭) sudo firewall-cmd --list-all(可以查看端口开放情况) 2.使用以下命令来开启或者关闭虚拟机的防火墙 systemctl stop firewalld.ser…...

【oracle】问题分析常用查询语句

1、查看当前的数据库连接数 select count(*) from v$process ; --当前的数据库连接数2、数据库允许的最大连接数 select value from v$parameter where name processes; --数据库允许的最大连接数3、查看当前有哪些用户正在使用数据 select osuser, a.username, cpu_time/ex…...

将vue-devtools打包成edge插件

文章目录一、从github拉vue-devtools源码二、用npm安装yarn三、使用yarn安装并编译源码四、将vue-devtools打包成edge插件五、离线安装edge插件一、从github拉vue-devtools源码 目前最新的版本是v6.5.0,地址:https://github.com/vuejs/devtools 二、用n…...

SpringBoot常见面试题汇总(超详细回答)

1.什么是SpringBoot?Spring Boot 是一个基于 Spring 框架的开源框架,用于快速创建独立的、生产级别的、可运行的 Spring 应用程序。它采用了约定优于配置的理念,使开发者可以不需要手动配置大量的 Spring 配置文件,而快速搭建出符…...

上海亚商投顾:沪指窄幅震荡 ChatGPT概念再度走高

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。市场情绪沪指今日窄幅震荡,创业板指低开低走,午后跌幅扩大至1%,宁德时代一度跌近4%。6G概…...

【C语言进阶:指针的进阶】函数指针

本章重点内容: 字符指针指针数组数组指针数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数指针和数组面试题的解析⚡函数指针 函数指针:指向函数的指针。 通过之前的学习我们知道数组指针中存放的是数组的地址,那么函…...

Sqoop 使用详解

Sqoop 概述Sqoop 是Apache 旗下的一款开源工具,用于Hadoop与关系型数据库之间传送数据,其核心功能有两个:导入数据和导出数据。导入数据是指将MySQL、Oracle等关系型数据库导入Hadoop的HDFS、Hive、HBase等数据存储系统;导出数据是…...

基于MATLAB开发AUTOSAR软件应用层Code mapping专题-part 1 code mapping总体介绍与Function标签页介绍

Hello,大家好,这篇文章开始我们进入一个新的专题,code mapping,即讲解AUTOSAR的元素和哪些模型元素是对应,这也是很多初学的朋友很疑惑的点,最近也有不少粉丝和朋友咨询我,说看了之前的文章基本了解了AUTOSAR有哪些元素()在数据字典的专题里我们逐个讲解过),但是就是…...

第十四节 包、权限修饰符、final、常量

包 1.同一个包下的类,相互可以直接访问。 2.不同包下的类要导包后才能访问。 AIT回车键导包。 权限修饰符 什么是权限修饰符? ●权限修饰符:是用来控制一个成员能够被访问的范围。 ●可以修饰成员变量,方法,构造器,内部类&…...

C++类和对象:初始化列表、static成员和友元

目录 一. 初始化列表 1.1 对象实例化时成员变量的创建及初始化 1.2 初始化列表 1.3 使用初始化列表和在函数体内初始化成员变量的效率比较 1.4 成员变量的初始化顺序 1.5 explicit关键字 二. static成员 2.1 static属性的成员变量 2.2 static属性的成员函数 三. 友元 …...

Windows 11 安装 Docker Desktop

Windows 环境安装 WSL2 WSL 简介 WSL 全称是 Windows Subsystem for Linux ,适用于 Linux 的 Windows 子系统,可让开发人员按原样运行 GNU/Linux 环境,包括大多数命令行工具、实用工具和应用程序,且不会产生传统虚拟机或双启动设…...

设计模式-第6章(工厂模式)

工厂模式简单工厂实现工厂模式实现简单工厂 VS 工厂方法商场收银程序再再升级(简单工厂策略装饰工厂方法)工厂方法模式总结简单工厂实现 在简单工厂类中,通过不同的运算符,创建具体的运算类。 public class OperationFactory {pu…...

【JAVA】线程和进程

🏆今日学习目标:线程和进程 😃创作者:颜颜yan_ ✨个人主页:颜颜yan_的个人主页 ⏰本期期数:第三期 🎉专栏系列:JAVA 线程和进程前言一、进程与线程1.进程2.线程二、线程的创建2.1 继…...

移动app安全测试工具好物分享

移动互联网时代,我们的生活和工作深受移动app的影响。随着移动app的广泛应用,安全问题成为人们最关注的话题之一。移动app安全除了和软件开发密不可分之外,软件测试的作用也是不容忽视的。移动app安全测试是指测试人员利用各种测试手段验证Ap…...

原生微信小程序引入npm和安装Vant Weapp

目录一、引入npm安装Vant Weapp1、引入npm2、安装Vant Weapp3、修改 app.json4、修改 project.config.json二、构建npm一、引入npm安装Vant Weapp 环境:Windows10 开发工具:微信开发者工具 本地环境:已安装过node.js 1、引入npm cmd进入到你…...

ChatGPT文章自动发布WordPress

WordPress可以用ChatGPT发文章吗?答案是肯定的,ChatGPT官方有提供api接口,多以目前有很多的SEO工具具有自动文章生成自动发布的功能,使用SEO工具,我们可以通过疑问词和关键词进行文章生成,并定时发布到我们…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线, n r n_r nr​ 根接收天线的 MIMO 系…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...