请求支付
| Web | 微信小程序 | Android | iOS | HarmonyOS |
|---|---|---|---|---|
| x | 4.41 | 4.02 | 4.18 | 4.61 |
uni.requestPayment是一个统一各平台的客户端支付API,客户端均使用本API调用支付。
本API运行在各端时,会自动转换为各端的原生支付调用API。
注意支付不仅仅需要客户端的开发,还需要服务端开发。虽然客户端API统一了,但各平台的支付申请开通、配置回填仍然需要看各个平台本身的支付文档。
比如微信有App支付的申请入口和使用流程,对应到uni-app,在App端要申请微信的App支付。
如果服务端使用uniCloud,那么官方提供了uniPay云端统一支付服务,把App、微信小程序、支付宝小程序里的服务端支付开发进行了统一的封装。
前端统一的uni.requestPayment和云端统一的uniPay搭配,可以极大提升支付业务的开发效率,强烈推荐给开发者使用。uniPay的文档另见:https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| options | RequestPaymentOptions | 是 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| data | any | 否 | 返回数据 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| errCode | number | 是 | 错误码 | ||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||
| errSubject | string | 是 | 统一错误主题(模块)名称 | ||||||||||||||||||||||||||||||||||||||||||||
| data | any | 否 | 错误信息中包含的数据 | ||||||||||||||||||||||||||||||||||||||||||||
| cause | Error | 否 | 源错误信息,可以包含多个错误,详见SourceError | ||||||||||||||||||||||||||||||||||||||||||||
| errMsg | string | 是 | |||||||||||||||||||||||||||||||||||||||||||||
app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%
22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.02%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%
91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22
%2C%22out_trade_no%22%3A%22314VYGIAGG7ZOYY%22%7D&charset=utf-8&method=alipay.trade.app.pay&sign_type=R
SA2×tamp=2016-08-15%2012%3A12%3A15&version=1.0&sign=MsbylYkCzlfYLy9PeRwUUIg9nZPeN9SfXPNavUCroGKR5Kqvx0nEnd3eRmKxJuthNUx4ERCXe552
EV9PfwexqW%2B1wbKOdYtDIb4%2B7PL3Pc94RZL0zKaWcaY3tSL89%2FuAVUsQuFqEJd
hIukuKygrXucvejOUgTCfoUdwTi7z%2BZzQ%3D<br>
[更多详情参考支付宝官方文档]
{
"appid":"wxd569c7238830733b",
"noncestr":"6N47VnR42bqIm4xq",
"package":"Sign=WXPay",
"partnerid":"1230636401",
"prepayid":"wx26174750316675ac54b89c224eb3250000",
"timestamp":1711446470,
"sign":"EE987459B9CFF6462462147130110D31"
}
[更多详情参考微信官方文档]
UniPaymentAlipayProvider(支付宝支付)继承自 UniProvider
UniPaymentWxpayProvider(微信支付)继承自 UniProvider,特有字段说明:
| 名称 | 类型 | 必备 | 默认值 | 描述 |
|---|---|---|---|---|
| isWeChatInstalled | boolean | 是 | - | 判断微信是否安装 |
支付失败时可通过错误回调参数IRequestPaymentFail中的cause属性获取支付SDK的源错误信息,类型为SourceError,其包含 code 属性存储了支付SDK的原始错误码。
| 支付宝错误码 | 错误信息 |
|---|---|
| 9000 | 订单支付成功 |
| 8000 | 正在处理中,支付结果未知(有可能已经支付成功),请查询商家订单列表中订单的支付状态 |
| 4000 | 订单支付失败 |
| 5000 | 重复请求 |
| 6001 | 用户中途取消 |
| 6002 | 网络连接出错 |
| 6004 | 支付结果未知(有可能已经支付成功),请查询商家订单列表中订单的支付状态 |
| 其它 | 其它支付错误 |
| 微信支付错误码 | 错误信息 |
|---|---|
| 0 | 成功 |
| -1 | 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常原因等 |
| -2 | 无需处理。发生场景:用户不支付了,点击取消,返回APP |
| -3 | 发送失败 |
| -4 | 授权被拒绝 |
| -5 | 不支持 |
| -6 | 禁止 |
| 其它 | 其它支付错误 |
uni.getProvider的方式,详见uni.getProvider uni.getProvider({
service: "payment",
success: (e) => {
const provider = e.providers.find((item): boolean => {
return item.id == 'wxpay'
})
// #ifdef APP-ANDROID
if (provider != null && provider instanceof UniPaymentWxpayProvider && !((provider as UniPaymentWxpayProvider).isWeChatInstalled)) {
console.log('WeChat 没有安装')
} else {
console.log('WeChat 已安装')
}
// #endif
// #ifdef APP-IOS
if (provider != null && ((provider as UniPaymentWxpayProvider).isWeChatInstalled == undefined || ((provider as UniPaymentWxpayProvider).isWeChatInstalled != null && (provider as UniPaymentWxpayProvider).isWeChatInstalled == false))) {
console.log('WeChat 没有安装')
} else {
console.log('WeChat 已安装')
}
// #endif
},
fail: (e) => {
console.log("获取支付通道失败:", e);
}
})
uni-payment节点,详见 https://doc.dcloud.net.cn/uni-app-x/collocation/manifest-modules.html#uni-payment模块配置HBuilderX 4.71+支持可视化界面配置,各平台配置请参考:
app-ios平台、
app-android平台、
app-harmony平台示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见
该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验
<template>
<page-head title="发起支付"></page-head>
<view class="uni-common-mt payment-content">
<text>如对当前页面的支付示例功能有任何疑问,通过电子邮件:service@dcloud.io 联系我们</text>
</view>
<view class="payment-content">
<template v-if="providerList.length > 0">
<button class="payment-button" type="primary" v-for="(item, index) in providerList" :key="index" @click="requestPayment(item)">{{ item.name }}</button>
</template>
<template v-else>
<button class="payment-button" type="primary">请先在 manifest.json 配置勾选微信支付、支付宝</button>
</template>
</view>
</template>
<script setup lang="uts">
export type PayItem = { id: string; name: string; provider?: UniProvider };
type DataType = {
btnText: string;
btnType: string;
orderInfo: string;
errorCode: number;
errorMsg: string;
complete: boolean;
fail: boolean;
outTradeNo: string;
openid: string;
};
type PaymentOptions = {
provider: string;
orderInfo: string;
errorTitle?: string;
duration?: number;
};
// 支付订单请求地址
const ALIPAY_ORDER_URL = 'https://demo.dcloud.net.cn/payment/alipay/?total=0.01';
const WXPAY_ORDER_URL = 'https://demo.dcloud.net.cn/payment/wxpayv3.__UNI__uniappx/?total=0.01';
const WXPAY_HELLO_UNI_APP_X_ORDER_URL = 'https://demo.dcloud.net.cn/payment/wxpayv3.__UNI__HelloUniAppX/?total=0.01';
const UNI_PAY_API_URL = 'https://env-00jxt67zj8kj.dev-hz.cloudbasefunction.cn/uni-pay-api';
const providerList = ref([] as PayItem[]);
const data = reactive({
btnText: '支付宝支付',
btnType: 'primary',
orderInfo: '',
errorCode: 0,
errorMsg: '',
complete: false,
fail: false,
outTradeNo: '',
openid: '',
} as DataType);
const getPaymentBundleId = (): string => {
let bundleId: string | null = '';
// #ifdef APP-ANDROID
bundleId = uni.getAppBaseInfo().packageName;
// #endif
// #ifdef APP-IOS
bundleId = uni.getAppBaseInfo().bundleId;
// #endif
// #ifdef APP-HARMONY
bundleId = uni.getAppBaseInfo().bundleName;
// #endif
// #ifdef MP-WEIXIN
bundleId = uni.getAccountInfoSync().miniProgram.appId;
// #endif
return bundleId ?? '';
};
const getWxpayOrderUrl = (): string => {
if (getPaymentBundleId() == 'io.dcloud.hellouniappx') {
return WXPAY_HELLO_UNI_APP_X_ORDER_URL;
}
return WXPAY_ORDER_URL;
};
const requestPaymentByOrderInfo = (options: PaymentOptions) => {
let duration = 3000;
if (options.duration != null) {
duration = options.duration as number;
}
uni.requestPayment({
provider: options.provider,
orderInfo: options.orderInfo,
// #ifdef MP-WEIXIN
// 微信小程序支持...结构语法
...JSON.parse(options.orderInfo),
// #endif
// #ifdef APP-HARMONY
dataType: 'text',
// #endif
success: (res: RequestPaymentSuccess) => {
console.log(JSON.stringify(res));
uni.showToast({ duration, icon: 'success', title: '支付成功' });
},
fail: (res: RequestPaymentFail) => {
console.log(JSON.stringify(res));
data.errorCode = res.errCode;
const title = options.errorTitle == null ? 'errorCode:' + data.errorCode : options.errorTitle;
uni.showToast({ duration, icon: 'error', title });
},
} as RequestPaymentOptions);
};
// #ifdef APP
const appPay = (provider: string) => {
uni.showLoading({ title: '请求中...' });
const isWxpay = provider == 'wxpay';
uni.request({
url: isWxpay ? getWxpayOrderUrl() : ALIPAY_ORDER_URL,
method: 'GET',
timeout: 6000,
success: (res) => {
console.log(res.data);
const orderInfo = isWxpay ? JSON.stringify(res.data) : (res.data as string);
data.orderInfo = JSON.stringify(res.data);
uni.hideLoading();
requestPaymentByOrderInfo({
provider,
orderInfo,
duration: isWxpay ? 5000 : 3000,
});
},
fail: (res) => {
uni.hideLoading();
console.log(res);
},
});
};
// #endif
// #ifdef MP-WEIXIN
// 发起微信小程序支付
const mpWeixinPay = async (): Promise<void> => {
uni.showLoading({ title: '请求中...', mask: true });
try {
if (data.openid == '') {
await getOpenId();
}
} catch (err) {
uni.hideLoading();
console.error('get-openid-err', err);
return;
}
let bundleId = getPaymentBundleId();
let random = Math.floor(Math.random() * 9000) + 1000;
data.outTradeNo = `test${Date.now()}${random}`;
console.log('outTradeNo: ', data.outTradeNo);
uni.request({
url: `${UNI_PAY_API_URL}/getOrderInfo`,
method: 'GET',
data: {
outTradeNo: data.outTradeNo,
bundleId,
openid: data.openid,
totalFee: 1,
},
success: (res) => {
uni.hideLoading();
let responseData = res.data as UTSJSONObject;
let errCode = responseData['errCode'] as number;
if (errCode != 0) {
uni.showModal({
title: '提示',
content: responseData['errMsg'] as string,
showCancel: false,
});
return;
}
let orderInfo = responseData['orderInfo'] as string;
console.log('orderInfo: ', orderInfo);
requestPaymentByOrderInfo({
provider: 'wxpay',
orderInfo,
errorTitle: '支付失败',
});
},
fail: (err) => {
uni.hideLoading();
console.error('request-err', err);
},
});
};
// #endif
const requestPayment = (e: PayItem) => {
// #ifdef APP
const provider = e.id;
if (provider == 'wxpay') {
const wxProvider = e.provider as UniPaymentWxpayProvider;
if (wxProvider != null && wxProvider.isWeChatInstalled != null && wxProvider.isWeChatInstalled == false) {
uni.showToast({
title: '微信没有安装',
icon: 'error',
});
return;
}
}
appPay(provider);
// #endif
// #ifdef MP-WEIXIN
mpWeixinPay();
// #endif
};
// #ifdef MP-WEIXIN
// 获取微信小程序openid,用于发起支付
const getOpenId = async (): Promise<void> => {
let bundleId = getPaymentBundleId();
let code = '';
await new Promise<void>((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (res) => {
code = res.code;
resolve();
},
fail: (err) => {
reject(err);
},
});
});
await new Promise<void>((resolve, reject) => {
uni.request({
url: `${UNI_PAY_API_URL}/getOpenId`,
method: 'GET',
data: {
code,
bundleId,
},
success: (res) => {
data.openid = res.data.openid;
console.log('openid: ', data.openid);
resolve();
},
fail: (err) => {
console.error('request-err', err);
reject(err);
},
});
});
};
// #endif
onLoad(() => {
// #ifdef APP
let provider = uni.getProviderSync({
service: 'payment',
} as GetProviderSyncOptions);
console.log(provider);
provider.providerObjects.forEach((value: UniProvider) => {
if (value.id == 'alipay' || value.id == 'wxpay') {
console.log(value.id, value);
providerList.value.push({
name: value.description,
id: value.id,
provider: value,
} as PayItem);
}
});
// #endif
// #ifdef MP-WEIXIN
providerList.value.push({
name: '微信支付',
id: 'wxpay',
} as PayItem);
// #endif
});
// 自动化测试使用
const jest_pay = () => {
uni.requestPayment({
provider: 'alipay',
orderInfo: data.orderInfo,
fail: (res: RequestPaymentFail) => {
data.errorCode = res.errCode;
data.complete = true;
data.fail = true;
},
success: (res: RequestPaymentSuccess) => {
console.log(JSON.stringify(res));
data.complete = true;
data.fail = false;
},
} as RequestPaymentOptions);
};
defineExpose({
data,
jest_pay,
});
</script>
<style>
.payment-content {
padding: 0 10px;
}
.payment-button {
margin-top: 20px;
}
</style>
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errMsg | string | 是 | 错误信息 |
App平台,微信和支付宝的SDK,除了requestPayment API封装的功能,还有一些其他功能。如开发者需要调用这些SDK的其他API,可以使用uts直接调用(注意打包时勾选相应的模块)
可以参考uni.requestPayment的源码,也是通过uts调用这2个原生SDK:
背景:目前uni-app x引擎已经内置了支付宝支付、微信支付。但支付SDK还有很多,比如银联SDK。
以往这些SDK可以通过独立插件的方式集成到uni-app x中,但需要提供单独的API给开发者使用。
uni-app x从4.25起,开放了provider自接入机制,让三方SDK可以以provider方式被开发者集成。
开发一个UTS插件,对接uni规范化的API、错误信息描述等实现自己的支付插件,这样插件使用者就可以通过uni的标准API使用三方SDK。
举个例子,开发者想使用uni.requestPayment()的方式调用XX支付,但是内置支付api不支持,
那只需要按照下面四个步骤实现即可:
第一步,新建一个UTS插件,在interface.uts 中定义接口,继承UniPaymentProvider,代码如下
export interface UniPaymentAlipayProvider extends UniPaymentProvider{}
第二步,在app-android或者app-ios的index.uts中实现接口,代码如下
import { UniPaymentAlipayProvider } from '../interface.uts'
export class UniPaymentAlipayProviderImpl implements UniPaymentAlipayProvider{
override id : String = "XX" // id必须有插件作者前缀,避免冲突,避免不同插件作者的插件id重名
override description : String = "XX的描述"
override isAppExist : boolean | null = null
constructor(){}
override requestPayment(options : RequestPaymentOptions) {
//todo 具体逻辑,接收uni规范的入参,进行业务处理,返回uni规范的返回值。如遇到错误,按uni的规范返回错误码
}
}
第三步,在manifest.json中配置
"app": {
"distribute": {
/* android打包配置 */
"modules": {
"uni-payment":{
"XX":{}
}
}
}
}
第四步,打包自定义基座然后运行
由于uni-app x内置的支付API也是基于这套规范实现的,所以推荐参考 uni-app x支付宝支付插件的实现源码