

支付
uni.requestPayment是一个统一各平台的客户端支付API,不管是在某家小程序还是在App中,客户端均使用本API调用支付。
本API运行在各端时,会自动转换为各端的原生支付调用API。
注意支付不仅仅需要客户端的开发,还需要服务端开发。虽然客户端API统一了,但各平台的支付申请开通、配置回填仍然需要看各个平台本身的支付文档。
比如微信有App支付、小程序支付、H5支付等不同的申请入口和使用流程,对应到uni-app,在App端要申请微信的App支付,而小程序端则申请微信的小程序支付。
如果服务端使用uniCloud (opens new window),那么官方提供了uniPay (opens new window)云端统一支付服务,把App、微信小程序、支付宝小程序里的服务端支付开发进行了统一的封装。
前端统一的uni.requestPayment
和云端统一的uniPay
搭配,可以极大提升支付业务的开发效率,强烈推荐给开发者使用。uniPay
的文档另见:https://uniapp.dcloud.io/uniCloud/unipay (opens new window)
平台差异说明
App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | 飞书小程序 | QQ小程序 | 快手小程序 | 京东小程序 |
---|---|---|---|---|---|---|---|---|---|
√ | 说明 | √ | √ | √ | √ | x | √ | √ | x |
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
provider | String | 是 | 服务提供商,通过 uni.getProvider 获取。 | |
orderInfo | String/Object | 是 | 订单数据,注意事项 | App、支付宝小程序、百度小程序、字节跳动小程序 |
timeStamp | String | 微信小程序必填 | 时间戳从1970年1月1日至今的秒数,即当前的时间。 | 微信小程序 |
nonceStr | String | 微信小程序必填 | 随机字符串,长度为32个字符以下。 | 微信小程序 |
package | String | 微信小程序必填 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=xx。 | 微信小程序 |
signType | String | 微信小程序必填 | 签名算法,应与后台下单时的值一致 | 微信小程序 |
paySign | String | 微信小程序必填 | 签名,具体签名方案参见 微信小程序支付文档 (opens new window) | 微信小程序 |
bannedChannels | Array<String> | 否 | 需要隐藏的支付方式,详见 百度小程序支付文档 (opens new window) | 百度小程序 |
service | Number | 字节跳动小程序必填 | 固定值:1(拉起小程序收银台)开发者如果不希望使用字节跳动小程序收银台,service设置为3/4时,可以直接拉起微信/支付宝进行支付:service=3: 微信API支付,不拉起小程序收银台;service=4: 支付宝API支付,不拉起小程序收银台。其中service=3、4,仅在1.35.0.1+基础库(头条743+)支持 | 字节跳动小程序 |
_debug | Number | 否 | 仅限调试用,上线前去掉该参数。_debug=1时,微信支付期间可以看到中间报错信息,方便调试 | 字节跳动小程序 |
getOrderStatus | Function | 字节跳动小程序必填 | 商户前端实现的查询支付订单状态方法(该方法需要返回个Promise对象)。 service=3、4时不需要传。 | 字节跳动小程序 |
success | Function | 否 | 接口调用成功的回调 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
微信小程序 signType
说明
合法值 | 说明 |
---|---|
MD5 | 仅在 v2 版本接口适用 |
HMAC-SHA256 | 仅在 v2 版本接口适用 |
RSA | 仅在 v3 版本接口适用 |
1.35.0+
版本基础库支持了 canIUse ,在1.19.4+
版本基础库支持了新版支付接口 tt.pay ,所以应避免使用 canIUse 判断是否为新版接口。各平台支持的支付情况说明
流程:支付平台功能申请 -> manifest.json
里配置支付参数 -> uni-app
里调用 API 进行支付
支付宝App支付功能申请
登录支付宝账号,创建应用接入支付宝App支付能力,包括以下步骤:
具体可参考支付宝官方文档: App支付快速接入 (opens new window)
微信App支付功能申请
具体可参考微信官方文档: 移动应用开发 (opens new window)
注意微信的App支付、小程序支付、H5支付是不同的体系。微信小程序支付在 微信商户平台 (opens new window) 申请支付时,选择公众号支付;普通浏览器里也可以调起微信进行支付,这个在微信叫做H5支付,此功能未开放给普通开发者,需向微信单独申请,详见 (opens new window)
苹果iap应用内支付申请
使用苹果开发者账号登录 App Store Connect (opens new window),在应用的功能选项卡页面,添加 App 内购项目。注意:
uni.requestPayment
前必须先使用 5+Plus 的方法调用 requestOrder 获取订单信息,否则会导致无法支付PayPal支付 [参考] (https://uniapp.dcloud.io/app-payment-paypal)
Stripe支付 [参考] (https://uniapp.dcloud.io/app-payment-stripe)
Google Pay支付 [参考] (https://uniapp.dcloud.io/app-payment-google)
manifest.json - App模块权限选择
中勾选 payment(支付)manifest.json - App SDK配置
中,勾选需要的支付平台,目前有微信支付、支付宝支付、苹果应用内支付(IAP),其中微信支付需要填写从微信开放平台获取的AppID
uni.getProvider
可以得到配置的结果列表,注意这里返回的是manifest配置的,与手机端是否安装微信、支付宝无关。如果手机端未安装支付宝,调用时会启动支付宝的wap页面登录,如果已安装相应客户端,会启动其客户端登录。
unicloud.callfunction
调用指定的云函数。uniPay
可极快的完成支付业务开发。uni.request
请求服务端接口,得到订单数据,使用 uni.requestPayment
向支付平台发起支付请求,拉起支付平台的客户端进行支付。在hello uni-app里详细代码。Q:如何使用ping++等聚合支付
A:uni-app的js API 已经完成跨端统一,客户端无需使用三方聚合支付。如果服务器选择uniCloud
,也无需三方聚合支付。如果服务端使用php、java等传统服务器开发,可以在服务端使用三方聚合支付。
Q:App端如何使用其他支付,比如银联、PayPal。 A:App 3.4+ 已支持 PayPal,App 3.4 以前的版本使用下面的方案 1、可以在web-view组件里使用它们的wap版支付;2、可以集成原生sdk,插件市场均有,详见 (opens new window)。也可以自行开发原生插件,开发文档见https://ask.dcloud.net.cn/article/35428 (opens new window)。
Q:Appstore审核报PGPay SDK不允许上架的问题 A:数字类产品(比如购买会员等不需要配送实物的商品),Apple规定必须使用苹果IAP应用内支付,给Apple分成30%。打包的时候不要勾选微信或支付宝等其他支付方式。如果你提交的包里包含了微信支付宝等支付的sdk,即使没使用,Appstore也会认为你有隐藏方式,以后会绕过IAP,不给Apple分成,因此拒绝你的App上线。云打包时,manifest里选上支付模块,但sdk配置里去掉微信支付和支付宝支付。很多开发者的Android版是包含微信和支付宝支付的,此时注意分开判断。详见https://ask.dcloud.net.cn/article/36447 (opens new window)
示例
App 支付
uni.requestPayment({
provider: 'alipay',
orderInfo: 'orderInfo', //微信、支付宝订单数据 【注意微信的订单信息,键值应该全部是小写,不能采用驼峰命名】
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
微信小程序支付
// 仅作为示例,非真实参数信息。
uni.requestPayment({
provider: 'wxpay',
timeStamp: String(Date.now()),
nonceStr: 'A1B2C3D4E5',
package: 'prepay_id=wx20180101abcdefg',
signType: 'MD5',
paySign: '',
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
微信 App 支付
uni.requestPayment({
"provider": "wxpay",
"orderInfo": {
"appid": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
"noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
"package": "Sign=WXPay", // 固定值
"partnerid": "148*****52", // 微信支付商户号
"prepayid": "wx202254********************fbe90000", // 统一下单订单号
"timestamp": 1597935292, // 时间戳(单位:秒)
"sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
},
success(res) {},
fail(e) {}
})
支付流程
获取支付通道 (uni.getProvider)
通过支付通道获取产品列表 (iapChannel.requestProduct 可选)
检查是否存在未关闭的订单 (iapChannel.restoreCompletedTransactions)
请求支付,传递产品信息 (uni.requestPayment)
客户端接收苹果返回的支付票据发送到服务器,在服务器请求苹果服务器验证支付是否有效
服务器验证票据有效后在客户端关闭订单 (iapChannel.finishTransaction)
3.5.1 之前因自动关闭订单导致某些情况下丢单的问题
3.5.1 + 增加了手动关闭订单参数 manualFinishTransaction
, 在合适的时机调用 iapChannel.finishTransaction
关闭订单
3.5.1+ 开始支持通过 uni.getProvider
获取IAP支付通道的方法
获取IAP支付通道
uni.getProvider({
service: 'payment',
success: (res) => {
const iapChannel = res.providers.find((channel) => {
return (channel.id === 'appleiap')
})
// 如果 iapChannel 为 null,说明当前包没有包含iap支付模块。注意:HBuilder基座不包含 iap 通道
}
});
IAP支付通道相关方法
向苹果服务器获取产品列表
iapChannel.requestProduct(<Function> success, <Function> fail)
success
回调值类型 Array<Product>
获取苹果服务器已支付且未关闭的交易列表
iapChannel.restoreCompletedTransactions(<Function> success, <Function> fail)
success
回调值类型 Array<Transaction>
关闭苹果服务器订单
iapChannel.finishTransaction(Transaction, <Function> success, <Function> fail)
所有 fail
回调格式为 { errCode: xxx, errMsg: '' }
uni.requestPayment()
说明
uni.requestPayment({
provider: 'appleiap',
orderInfo: {},
success: (e) => {
// e 类型为 Transaction, 详见下面的描述
}
})
orderInfo
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
productid | String | 产品id,在苹果开发者中心配置 | |
username | String | 透传参数,一般用于标记订单和用户的关系,向苹果服务器二次验证票据时返回此字段 | |
quantity | Number | 1 | 购买数量,至少大于等于 1 |
manualFinishTransaction | Boolean | false | 3.5.1+ 支持,手动关闭订单,值为 false 时支付完成后自动关闭订单,true 时不关闭订单,需要在合适的时机调用 finishTransaction 关闭订单。建议设置为 true , 默认值为 false 是为了向下兼容 |
Product
属性 | 类型 | 说明 |
---|---|---|
title | String | 产品标题 |
description | String | 产品描述 |
productid | String | 产品id,在苹果开发者中心配置 |
price | Number | 价格 |
pricelocal | String | 币种,例如: zh_CN@currency=CNY |
Transaction
属性 | 类型 | 说明 |
---|---|---|
payment | Object | 支付信息,详见下面的说明 |
transactionDate | String | 交易日期,示例 2022-01-01 08:00:00 |
transactionIdentifier | String | 交易唯一标识 |
transactionReceipt | String | 支付票据,用于在开发者的服务器向苹果的服务器二次验证交易是否有效 |
transactionState | String | 交易状态码 |
Payment
属性 | 类型 | 说明 |
---|---|---|
productid | String | 产品id |
quantity | String | 购买数量 |
username | String | 透传参数 |
transactionState
值类型:String
值 | 说明 |
---|---|
1 | 交易成功 |
注意事项
restoreCompletedTransactions
后 transactionReceipt
会发生变化,并非唯一值AppStore
支付方式,调用 uni.requestPayment()
准备支付,触发失败 fail
回调,errCode=2,用户未绑定支付方式,app内支付流程结束。
系统弹出框引导用户绑定支付方式,此过程将跳转到系统应用 AppStore
进行绑定支付方式,绑定成功同步支付成功,用户成功付款下面为未处理丢单的示例代码,后续提供完整代码
<template>
<view>
<view class="uni-list">
<radio-group @change="applePriceChange">
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in priceList" :key="index">
{{item.text}}
<radio :value="item.value" :checked="item.checked" />
</label>
</radio-group>
</view>
<view class="uni-padding-wrap">
<button class="ipaPayBtn" @click="requestPayment" :loading="loading" :disabled="disabled">确认支付</button>
</view>
</view>
</view>
</template>
<script>
let iapChannel = null,
productId = 'HelloUniappPayment1',
productIds = ['HelloUniappPayment1', 'HelloUniappPayment6'];
export default {
data() {
return {
title: 'request-payment',
loading: false,
disabled: true,
priceList: [{
value: 'HelloUniappPayment1',
text: '支付1元',
checked: true
}, {
value: 'HelloUniappPayment6',
text: '支付6元',
checked: false
}]
}
},
onLoad: function() {
plus.payment.getChannels((channels) => {
console.log("获取到channel" + JSON.stringify(channels))
for (var i in channels) {
var channel = channels[i];
if (channel.id === 'appleiap') {
iapChannel = channel;
this.requestOrder();
}
}
if(!iapChannel){
this.errorMsg()
}
}, (error) => {
this.errorMsg()
});
},
methods: {
requestOrder() {
uni.showLoading({
title:'检测支付环境...'
})
iapChannel.requestOrder(productIds, (orderList) => { //必须调用此方法才能进行 iap 支付
this.disabled = false;
console.log('requestOrder success666: ' + JSON.stringify(orderList));
uni.hideLoading();
}, (e) => {
console.log('requestOrder failed: ' + JSON.stringify(e));
uni.hideLoading();
this.errorMsg()
});
},
requestPayment(e) {
this.loading = true;
uni.requestPayment({
provider: 'appleiap',
orderInfo: {
productid: productId
},
success: (e) => {
uni.showModal({
content: "感谢您的赞助",
showCancel: false
})
},
fail: (e) => {
uni.showModal({
content: "支付失败,原因为: " + e.errMsg,
showCancel: false
})
},
complete: () => {
console.log("payment结束")
this.loading = false;
}
})
},
applePriceChange(e) {
productId = e.detail.value;
},
errorMsg(){
uni.showModal({
content: "暂不支持苹果 iap 支付",
showCancel: false
})
}
}
}
</script>