uniapp各平台支付功能
目录
APP端支付参考资料
申请开通各平台APP支付
在使用支付前,需要向各支付平台申请开通支付功能【要有营业执照才可以开通】。
Apple应用内支付(IAP)
因为苹果应用内置流程与其他三方支付平台存在差异,需要单独参考ios平台使用Apple应用内支付文档。
注意事项:
- 要成为Apple 开发者人员,需要向Apple支付开发人员年费。【 https://developer.apple.com】,【https://developer.apple.com/cn】
- iOS平台苹果审核规范要求,应用中虚拟物品交易必需使用Apple应用内支付,实物交易才能使用第三方支付(支付宝和微信支付)
HBuilder 里的调试基座默认不带IAP支付通道,如果需要调试IAP需要使用开发证书生成一个自定义调试基座,用来实现IAP的开发和调试。 自定义调试基座使用方法请参考文档。
支付宝支付
登录支付宝账号,创建应用接入支付宝APP支付如下步骤【前提需要营业执照】支付宝官方文档App支付快速接入。
-
步骤一、 创建应用,登录支付宝开放平台,创建应用并提交审核,审核通过后会生成应用唯一标识,APPID,并且可以申请开通开放产品使用权限,通过AppID应用才能调用开放产品的接口能力。
点击上面设置后,在加签管理,选择公钥证书,然后下载工具生csr文件
-
步骤二、开通App支付功能,应用创建完成后,系统会自动跳转到应用详情页面。开发者可以点击 添加能力 来添加 App 支付能力。添加功能后开发者需要在商家中心中进行 签约,第三方应用开发者可以 代商户签约。
得到沙箱测试账号
步骤三、 配置密钥(获取公钥、私钥)
为了保证交易双方(商户和支付宝)的身份和数据安全,商户在调用接口前,需要配置双方密钥,对交易数据进行双方校验。密钥包含应用私钥APP_PRIVATE_KEY
和应用公钥 APP_PUBLIC_KEY
。生成密钥后,商户需要在开放平台控制台进行密钥配,配置完成后可以获取支付宝公钥 ALIPAY_PUBLIC_KEY
,配置的详细步骤请参考 配置应用环境。您还可以通过 生成密钥并上传 学习密钥的配置。密钥的配置旨在对交易数据进行双方校验。
微信支付【参考】
步骤一、创建应用
- 使用微信支付功能需到微信开放平台 申请移动应用并开通支付功能 微信APP
支付接入商户服务中心 申请应用后可以获取AppID和AppSecret值。
步骤二、开通
开通支付功能后可获取支付业务服务器配置数据(要先交300元开发者认证费用,个人不行)。
PARTNER
:财付通商户号
PARTNER_KEY
:财付通密钥
PAYSIGNKEY
:支付签名密钥
服务端生成支付订单接口
在App端调用支付功能时,需要先在调用服务器上生成预支付订单接口,再将预支付订单信息传递给支付接口。
支付宝业务流程图【官方参考】
客户端请求后台服务端获取签名后的订单信息,客户端带上订单信息(字符串)请求支付接口。
微信支付业务流程图【官方参考】
客户端请求后台服务端获取代签名的支付订单信息,然后客户端带上订单信息(Object类型)请求支付接口,其中订单信息请求请参考官网文档【APP调起支付API】
HBuilderX中配置使用支付功能
从微信开放平台申请获取配置参数后(Apple应用内支付和支付宝无需配置),需要再HBuilderX中配置并提交云端打包才能生效。
勾选后会显示支持的支付模块,可根据应用需要进行选择配置
Apple应用内支付【仅支持IOS平台】
支付宝支付【支持Android及iOS平台】
微信支付【参考】
获取appid填入,去微信开放平台申请应用的AppId值,UniversalLinks:iOS平台通用链接,必须与微信开放平台配置的一致,参考iOS平台微信SDK配置通用链接(UniversalLinks)
功能实现
APP端支付宝/微信支付实现
发送请求到后台服务端,后台服务端生成订单信息,相应预支付订单信息,通过预支付订单信息请求支付接口。
import api from '@/api/order.js'
export default {
methods: {
// 获取订单信息 (微信小程序支付需要openid)
getOrderInfo(openid) {
// 不要少了async
return new Promise( async (resolve, reject) => {
let res = null
let data = {} // 服务接口请求参数
if(this.provider === 'alipay') {
res = await api.getOrderInfoAlipay(data)
}else if(this.provider === 'wxpay') {
res = await api.getOrderInfoWxpay(data)
}
if (res && res.code === 20000) {
resolve(res.data)
} else {
reject(new Error('获取支付信息失败' + res.message))
}
})
},
// 微信、支付宝等支付
async payHandler() {
// 支付中
this.loading = true
// #ifdef APP-PLUS
// 1. 发送请求到服务端,服务端生成订单信息,响应预支付订单
let orderInfo = await this.getOrderInfo();
if (!orderInfo) {
uni.showModal({
content: '获取支付信息失败',
showCancel: false
})
return
}
// 2. 请求支付
uni.requestPayment({
provider: this.provider, // 支付渠道
orderInfo: orderInfo,
success: (e) => {
console.log("success", e);
uni.showToast({
title: "支付成功!"
})
},
fail: (e) => {
console.log("fail", e);
uni.showModal({
content: "支付失败!",
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
// #endif
},
}
微信小程序支付功能实现
微信小程序运行在微信里面,需要支付的话,首先要知道是谁的微信里面,就需要将当前微信进行登录获取获取code,再根据code获取openid的值。
步骤一、先登录微信小程序获取用户code,再请求服务端获取openid,微信小程序登录参考:
// 登录微信小程序
loginWeixinMp() {
return new Promise((resolve, reject) => {
// 1. 先使用微信登录小程序响应 code,
uni.login({
provider: 'weixin',
success: (res) => {
console.log('登录', res)
const code = res.code
// 2. 请求服务端通过code获取openid
let openid = 'xx'
uni.setStorageSync('openid', openid)
resolve(openid)
},
fail(err) {
reject(err)
}
})
})
},
步骤二、通过openid
再获取订单预支付信息,直接在getOrderInfo
写死一个模拟预支付信息即可。
getOrderInfo(openid) {
return new Promise(async (resolve, reject) => {
if (openid) {
// 微信小程序获取订单信息,发送请求
// let orderInfo = await api.getOrderInfoWxpayMP(openid) 如果有真实接口替换即可
let orderInfo = {
"timeStamp": "1414561699",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx201410272009395522657a690389285100", //预支付交易会话标识( prepay_id)
"signType": "RSA",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ",
}
resolve(orderInfo)
return
}
let res = null
let data = {} // 服务接口请求参数
if (this.provider === 'alipay') {
res = await api.getOrderInfoAlipay(data)
} else if (this.provider === 'wxpay') {
res = await api.getOrderInfoWxpay(data)
}
if (res && res.code === 20000) {
resolve(res.data)
} else {
reject(new Error('获取支付信息失败' + res.message))
}
})
},
步骤三、通过订单预支付信息,去调用支付接口
// 微信小程序支付
async wxPayHandler() {
this.loading = true
// 1. 先获取用户code, 再获取openid
let openid = uni.getStorageSync('openid')
if (!openid) {
try {
openid = await this.loginWeixinMp()
} catch (e) {
console.error(e)
}
if (!openid) {
uni.showModal({
content: '获取openid失败',
showCancel: false
})
this.loading = false
return
}
}
// 2. 通过 openid 再获取订单信息,
let orderInfo = await this.getOrderInfo(openid)
// 3. 通过订单预支付信息,去调用支付接口
uni.requestPayment({
...orderInfo,
success: (res) => {
uni.showToast({
title: "支付成功!"
})
},
fail: (res) => {
uni.showModal({
content: "支付失败,原因为: " + res.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
}
因为用的是模拟的假数据,会报权限不足问题,如果真实开发中调用后端请求服务拿到商品信息,先登录微信小程序获取用户code,再请求服务端获取openid,通过openid
再获取订单预支付信息,直接在getOrderInfo
写死一个模拟预支付信息即可,通过订单预支付信息,去调用支付接口即可。
Apple应用内支付
苹果应用内置流程与其它三方支付平台存在差异,请单独参考iOS 平台使用Apple应用内支付文档,项目中参考支付文档最下面示例代码
流程:
在onLoad中先获取Apple支付渠道的实例。
onLoad: function(option) {
// 获取支付金额
if (option.params) {
const params = JSON.parse(option.params)
this.price = params.price
this.courseIds = params.courseIds
}
// 查询余额
this.loadData()
// 获取apple支付渠道实例
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()
});
},
requestOrder环境检测方法
requestOrder() {
uni.showLoading({
title: '检测支付环境...'
})
//必须调用此方法向Appstore请求有效的商品详情,才能进行 iap 支付,
iapChannel.requestOrder(this.moneyList, (orderList) => {
this.disabled = false;
console.log('requestOrder success666: ' + JSON.stringify(orderList));
uni.hideLoading();
}, (e) => {
console.log('requestOrder failed: ' + JSON.stringify(e));
uni.hideLoading();
this.errorMsg()
});
},
弹窗提示判断,如果环境不支持apple支付则弹窗提醒
errorMsg() {
uni.showModal({
content: "暂不支持苹果 iap 支付",
showCancel: false
})
},
如果当前环境可以支付,则使用uni.requestPayment
进行apple支
// Apple应用内支付
iosPayHandler() {
this.loading = true;
uni.requestPayment({
provider: 'appleiap',
orderInfo: {
productid: this.applePrice // 商品金额
},
success: (e) => {
console.log("success", e);
uni.showToast({
title: "支付成功!"
})
// 再进行app内部扣款
},
fail: (e) => {
console.log("fail", e);
uni.showModal({
content: "支付失败,原因为: " + e.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
},
总体代码:
<template>
<view>
<view class="money column center">
<text>余额:</text>
<text>{{parseFloat(balance).toFixed(2)}}币</text>
</view>
<view class="recharge">
<view>充值</view>
<view class="list">
<view v-for="(item, index) in 6" :key="index" :class="{active: activeIndex===index}"
@click="clickItem(index, item)">
<view>{{index+1}}00币</view>
<view>¥{{index+1}}00</view>
</view>
</view>
</view>
<view class="desc">
<view>充值说明:</view>
<view>
1.在IOS设备的APP要进行充值后,使用虚拟币消费。<br>
2.充值后不能在非IOS设备使用,与安卓版和网站余额不通用。<br>
3.充值后没有使用期限,但不可提现、退换、转让和申请发票。<br>
4.如遇无法充值、充值失败等问题,可关注[梦学谷]公众号,联系我们解决。<br>
</view>
</view>
<view class="bottom center">
<button class="btn" :loading="loading" :disabled="disabled" @click="iosPayHandler">立即充值</button>
</view>
</view>
</template>
<script>
import api from '@/api/order.js'
let iapChannel = null // 苹果内部支付渠道
export default {
data() {
return {
activeIndex: 0,
loading: false, // 是否充值中
disabled: true, //要先检查支付环境是否iap,不支付则点击立即支付无效
balance: 0, // 余额
moneyList: [], // 充值列表展示金额
price: 0, // 支付金额
courseIds: [], // 支付的课程ids
applePrice: 30, // ios充值金额
}
},
onLoad: function(option) {
// 获取支付金额
if (option.params) {
const params = JSON.parse(option.params)
this.price = params.price
this.courseIds = params.courseIds
}
// 查询余额
this.loadData()
// 获取apple支付渠道实例
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: '检测支付环境...'
})
//必须调用此方法向Appstore请求有效的商品详情,才能进行 iap 支付,
iapChannel.requestOrder(this.moneyList, (orderList) => {
this.disabled = false;
console.log('requestOrder success666: ' + JSON.stringify(orderList));
uni.hideLoading();
}, (e) => {
console.log('requestOrder failed: ' + JSON.stringify(e));
uni.hideLoading();
this.errorMsg()
});
},
iosPayHandler() {
this.loading = true;
uni.requestPayment({
provider: 'appleiap',
orderInfo: {
productid: this.applePrice // 商品id
},
success: (e) => {
console.log("success", e);
uni.showToast({
title: "支付成功!"
})
// 调用接口,立即扣款购买商品
},
fail: (e) => {
console.log("fail", e);
uni.showModal({
content: "支付失败,原因为: " + e.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false;
}
})
},
errorMsg() {
uni.showModal({
content: "暂不支持苹果 iap 支付",
showCancel: false
})
},
clickItem(index, item) {
this.activeIndex = index
this.applePrice = item
},
async loadData() {
// 查询余额
const {
data
} = await api.getUserBalance()
this.balance = data
// 要进行支付,则计算还差多少金额, 则充值多少,
if (this.price) {
// ios充值多少 = 余额-付款金额 < 0 : 余额不够:充足 const applePrice=this.balance - this.price // console.log('applePrice', applePrice)
// 取正数,向上取整 this.applePrice=Math.ceil(Math.abs(applePrice)) } // 充值列表展示金额 for(let i=0; i<6; i++) { // 6个元素,每个加30元
this.moneyList.push(this.applePrice + i * 30)
}
},
}
}
</script>
<style lang="scss">
.money {
height: 288rpx;
background-color: $mxg-color-primary;
color: #FFFFFF;
font-size: 88rpx;
text:first-child {
color: #e7e4e9;
font-size: 30rpx;
}
}
.recharge {
margin: 20rpx 0 0 20rpx;
color: #999;
font-size: 30rpx;
.list {
margin-top: 20rpx;
text-align: center;
>view {
float: left;
width: 225rpx;
margin-right: 10rpx;
margin-bottom: 15rpx;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx 0;
border: 1px solid $mxg-color-grey;
flex-wrap: wrap;
view:first-child {
color: $mxg-text-color-red;
font-size: 36rpx;
}
}
}
}
.active {
box-shadow: 0 0 0 .5px $mxg-text-color-red;
}
.desc {
// 清除浮动
clear: both;
margin: 0 20rpx;
font-size: 30rpx;
line-height: 45rpx;
color: #6e6d70;
view:first-child {
padding-top: 50rpx;
padding-bottom: 30rpx;
font-weight: bold;
}
view:last-child {
padding-bottom: 120rpx;
}
}
/* 底部 */
.bottom {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 100rpx;
background-color: #FFFFFF;
border-top: 1px solid #F1F1F1;
}
.btn {
width: 700rpx;
background-color: $mxg-color-primary;
color: #fff;
border-radius: 50rpx;
line-height: 80rpx;
font-size: 30rpx;
&::after {
// 加载中时,隐藏边框
border: none;
}
}
</style>
效果:由于我用的是mock
数据,说一检测环境就会失败判断,到了生产环境就会弹出apple
应用支付弹窗。
Appstore审核报PGPay SDK
不允许上架的问题
A:数字类产品(比如购买会员等不需要配送实物的商品),Apple
规定必须使用苹果IAP
应用内支付,给Apple
分成30%
。打包的时候不要勾选微信或支付宝等其他支付方式。如果你提交的包里包含了微信支付宝等支付的sdk
,即使没使用,Appstore
也会认为你有隐藏方式,以后会绕过IAP
,不给Apple
分成,因此拒绝你的App
上线。云打包时,manifest
里选上支付模块,但sdk
配置里去掉微信支付和支付宝支付。很多开发者的Android
版是包含微信和支付宝支付的,此时注意分开判断。详见
H5沙箱支付功能实现实现
配置沙箱
沙箱支持产品
沙箱测试账号
带着商品信息请求后端接口,获取paymentUrl
然后通过window.location.href = res.paymentUrl
进行跳转
通过location.href
跳转到如下页面即可使用沙箱测试账号进行登录。下图为支付宝登录页面,可能会违规。
注意: 沙箱测试支付功能一定要开启无痕浏览进行测试。
使用支付宝开放平台给的沙箱测试账号进行测试:如下找到
输入沙箱账号密码
支付成功
交易成功后,此页面会跳转到前端传递给后端的配置的跳转页面,支付成功后就会跳回到指定页面。
配置的支付成功后的跳转页面,在此页面调用后端接口,后端返回支付状态,根据支付状态再在此页面进行其他业务逻辑处理。
H5支付第二种方法
微信支付:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_6_0.shtml
支付宝:https://opendocs.alipay.com/open/204/105297
完结~,如有不足,后继补充。。。。