

English
pay
uni.requestPayment is a client-side payment API that unifies all platforms. Whether it is in a MiniApp or an App, the client uses this API to call payment.
When this API runs on each terminal, it will be automatically converted to the native payment calling API of each terminal.
Note that payment requires not only client-side development, but also server-side development. Although the client API is unified, the payment application opening and configuration backfill of each platform still need to look at the payment documents of each platform.
For example, WeChat has different application entrances and usage processes such as App payment, MiniApp payment, H5 payment, etc. Corresponding to uni-app, you need to apply for WeChat App Payment on the App side, while the MiniApp side applies for WeChat MiniApp Payment.
如果服务端使用uniCloud,那么官方提供了uniPay云端统一支付服务,把App、微信小程序、支付宝小程序里的服务端支付开发进行了统一的封装。
前端统一的uni.requestPayment
和云端统一的uniPay
搭配,可以极大提升支付业务的开发效率,强烈推荐给开发者使用。uniPay
的文档另见:https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html
Platform Difference Description
App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 抖音小程序 | 飞书小程序 | QQ小程序 | 快手小程序 | 京东小程序 |
---|---|---|---|---|---|---|---|---|---|
√ | Description | √ | √ | √ | √ | x | √ | √ | x |
OBJECT parameter description
Parameter Name | Type | Required | Description | Platform Difference Description |
---|---|---|---|---|
provider | String | 是 | 服务提供商,通过 uni.getProvider 获取。 | |
orderInfo | String/Object | 是 | 订单数据,注意事项 | App、支付宝小程序、百度小程序、抖音小程序 |
timeStamp | String | Required for WeChat MiniApp | Timestamp seconds from January 1, 1970 to the present, that is, the current time. | WeChat MiniApp |
nonceStr | String | Required for WeChat MiniApp | Random string with a length of 32 characters or less. | WeChat MiniApp |
package | String | Required for WeChat MiniApp | The value of the prepay_id parameter returned by the unified ordering interface. The submission format is: prepay_id=xx. | WeChat MiniApp |
signType | String | Required for WeChat MiniApp | Signature algorithm, which should be the same as the value when placing an order in the background | WeChat MiniApp |
paySign | String | Required for WeChat MiniApp | Signature, please refer to WeChat MiniApp Payment Document | WeChat MiniApp |
bannedChannels | Array<String> | 否 | 需要隐藏的支付方式,详见 百度小程序支付文档 | 百度小程序 |
service | Number | 抖音小程序必填 | 固定值:5(拉起小程序收银台)开发者如果不希望使用抖音小程序收银台,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 | No | Callback for successful interface call | |
fail | Function | No | Callback function for interface call failure | |
complete | Function | No | The callback function of the end of the interface call (the call will be executed if the call succeeds or fails) |
WeChat MiniAppsignType
description
legal value | description |
---|---|
MD5 | Only available in v2 version interface |
HMAC-SHA256 | Only available on v2 interface |
RSA | Only available in v3 interface |
uni-pay
插件,已封装了web支付,详见Description of payment conditions supported by each platform
Process: Payment platform function application -> configure payment parameters in manifest.json
-> call API in uni-app
for payment
manifest.json - App module permission selection
manifest.json - App SDK配置
中,勾选需要的支付平台,目前有微信支付、支付宝支付、苹果应用内支付(IAP),其中微信支付需要填写从微信开放平台获取的AppID
uni.getProvider
. Note that what is returned here is the manifest configuration, which has nothing to do with whether WeChat or Alipay is installed on the mobile phone.uni.requestPayment({
provider: 'alipay',
orderInfo: 'orderInfo', //微信、支付宝订单数据 【注意微信的订单信息,键值应该全部是小写,不能采用驼峰命名】
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
Log in to the Alipay account and create an application to access the Alipay App payment capability, including the following steps:
- Create app (get appid)
- Activate the App payment function
- Configure keys (get public key, private key)
For details, please refer to the official Alipay documentation: Quick access to App payment
If Alipay is not installed on the mobile phone, it will start Alipay's wap page login when it is called. If the corresponding client has been installed, its client login will be started.
For details, please refer to the official WeChat document: Mobile Application Development
Note that WeChat's App payment, MiniApp payment, and H5 payment are different systems. WeChat MiniApp Payment When applying for payment on the WeChat Merchant Platform, select the official account payment; ordinary browsers can also call up WeChat for payment, which is called H5 payment in WeChat , this function is not open to ordinary developers, you need to apply to WeChat separately, [see details]( https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1 )
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) {}
})
Log in to [App Store Connect](https://appstoreconnect.apple.com) with your Apple developer account, and add in-app purchases on the function tab page of the app. Notice:
- The information of the in-app purchase item needs to be filled in completely and then saved. At this time, the status of the in-app purchase item should be ready to submit. When the submitted application passes the review, the status will become approved
- When testing, it is recommended to use a test certificate to hit a custom iOS dock for testing
- Add an App Store Connect user in the app TestFight tab, you can use this user account for testing when testing payments
Get the payment channel (uni.getProvider)
Get the product list through the payment channel (iapChannel.requestProduct)
Check if there are open orders (iapChannel.restoreCompletedTransactions, optional check at the right time)
Request payment, pass product information (uni.requestPayment)
The client receives the payment receipt returned by Apple and sends it to the server, where the server requests the Apple server to verify whether the payment is valid
The server closes the order on the client side after verifying that the ticket is valid (iapChannel.finishTransaction)
Before HBuilder 3.5.1, the order was lost in some cases due to the automatic closing of the order
HBuilder 3.5.1 + added the parameter manualFinishTransaction
to manually close the order, call iapChannel.finishTransaction
at the right time to close the order
HBuilder 3.5.1+ starts to support the method of getting IAP payment channel through uni.getProvider
uni.getProvider({
service: 'payment',
success: (res) => {
const iapChannel = res.providers.find((channel) => {
return (channel.id === 'appleiap')
})
// If iapChannel is null, it means that the current package does not contain the iap payment module. Note: HBuilder base does not contain iap channel
}
});
iapChannel.requestProduct(<Function> success, <Function> fail)
success
callback value type Array<Product>
iapChannel.restoreCompletedTransactions(<Function> success, <Function> fail)
success
callback value type Array<Transaction>
iapChannel.finishTransaction(Transaction, <Function> success, <Function> fail)
All fail
callbacks have the format { errCode: xxx, errMsg: '' }
uni.requestPayment()
uni.requestPayment({
provider: 'appleiap',
orderInfo: {},
success: (e) => {
// e is of type Transaction, see the description below for details
}
})
property | type | default value | description |
---|---|---|---|
productid | String | Product id, configured in Apple Developer Center | |
username | String | Transparent parameter, generally used to mark the relationship between the order and the user, this field is returned when the ticket is verified to the Apple server twice | |
quantity | Number | 1 | The purchase quantity, at least 1 |
manualFinishTransaction | Boolean | false | 3.5.1+ 支持,手动关闭订单,值为 false 时支付完成后自动关闭订单,true 时不关闭订单,需要在合适的时机调用 finishTransaction 关闭订单。建议设置为 true , 默认值为 false 是为了向下兼容 |
paymentDiscount | Object | 否 | 促销优惠(HBuilderX 3.7.0+ 手机系统iOS12.2+支持) |
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
offerIdentifier | String | 是 | 促销id |
keyIdentifier | String | 是 | 密钥 |
nonce | String | 是 | 唯一id (必须小写 24小时有效) |
signature | String | 是 | 签名 |
timestamp | Number | 是 | 创建证书的时间戳(毫秒 24小时有效) |
property | type | description |
---|---|---|
title | String | Product title |
description | String | Product description |
productid | String | Product id, configured in Apple Developer Center |
price | Number | Price |
pricelocal | String | 币种,例如: zh_CN@currency=CNY |
discount | Array | 折扣信息(HBuilderX 3.7.0+ 手机系统iOS12.2+支持) |
属性 | 类型 | 说明 |
---|---|---|
price | Number | 促销价格 |
periodUnit | String | 周期单位(day: 日,week: 周,month: 月,year: 年) |
discountType | String | 优惠类型(introductory: 推介促销 subscription: 订阅促销) |
promotionType | String | 促销类型(payAsYouGo: 随用随付,payUpFront: 预先支付,freeTrial: 免费试用) |
code | String | 促销代码 |
units | Number | 促销期数 |
property | type | description |
---|---|---|
payment | Object | Payment information, see description below for details |
transactionDate | String | Transaction date, example 2022-01-01 08:00:00 |
transactionIdentifier | String | Transaction Unique Identifier |
transactionReceipt | String | The payment receipt is used to verify the validity of the transaction to Apple's server twice on the developer's server |
transactionState | String | Transaction Status Code |
property | type | description |
---|---|---|
productid | String | productid |
quantity | String | Purchase Quantity |
username | String | Transparent parameter |
Value type: String
value | description |
---|---|
1 | Successful transaction |
Precautions
transactionReceipt
will change after calling restoreCompletedTransactions
repeatedly, not a unique valuefinishTransaction
to close the order may not take effect immediately, depending on Apple's serversrestoreCompletedTransactions
has no response for a long time, check whether the sandbox account logged in by the device is normalSystem Settings -> App Store
AppStore
payment method, call uni.requestPayment()
to prepare for payment, trigger the failed fail
callback, errCode=2, the user has not bound the payment method, and the in-app payment process ends.
The system pop-up box guides the user to bind the payment method. This process will jump to the system application AppStore
to bind the payment method. If the binding is successful, the synchronization payment is successful, and the user successfully pays.<template>
<view class="content">
<view class="uni-list">
<radio-group @change="applePriceChange">
<label class="uni-list-cell" v-for="(item, index) in productList" :key="index">
<radio :value="item.productid" :checked="item.checked" />
<view class="price">{{item.title}} {{item.price}}</view>
</label>
</radio-group>
</view>
<view class="uni-padding-wrap">
<button class="btn-pay" @click="payment" :loading="loading" :disabled="disabled">确认支付</button>
</view>
</view>
</template>
<script>
import {
Iap,
IapTransactionState
} from "./iap.js"
export default {
data() {
return {
title: "iap",
loading: false,
disabled: true,
productId: "",
productList: []
}
},
onLoad: function() {
// create example
this._iap = new Iap({
products: [] // 苹果开发者中心创建
})
this.init();
},
onShow() {
if (this._iap.ready) {
this.restore();
}
},
onUnload() {},
methods: {
async init() {
uni.showLoading({
title: '检测支付环境...'
});
try {
// Initialize, get the iap payment channel
await this._iap.init();
// Get product list from apple server
this.productList = await this._iap.getProduct();
this.productList[0].checked = true;
this.productId = this.productList[0].productid;
// populate the product list, enable the interface
this.disabled = false;
} catch (e) {
uni.showModal({
title: "init",
content: e.message,
showCancel: false
});
} finally {
uni.hideLoading();
}
if (this._iap.ready) {
this.restore();
}
},
async restore() {
// Check the order that the user has paid and has not closed last time, the possible reasons: the first time the card is bound, the network is interrupted, etc.
// Check if the user is logged in here
uni.showLoading({
title: '正在检测已支付且未关闭的订单...'
});
try {
// Check unclosed orders from Apple server, optionally filter according to username, which is consistent with the value passed through when calling payment
const transactions = await this._iap.restoreCompletedTransactions({
username: ""
});
if (!transactions.length) {
return;
}
// Developer business logic, get the current user's unfinished order list from the server, and compare with the local
// omitted here
switch (transaction.transactionState) {
case IapTransactionState.purchased:
//let result = await this.validatePaymentResult();
// if (result) {
// await this._iap.finishTransaction(transaction);
// }
break;
case IapTransactionState.failed:
// close unpaid orders
await this._iap.finishTransaction(transaction);
break;
default:
break;
}
} catch (e) {
uni.showModal({
content: e.message,
showCancel: false
});
} finally {
uni.hideLoading();
}
},
async payment() {
if (this.loading == true) {
return;
}
this.loading = true;
uni.showLoading({
title: '支付处理中...'
});
try {
// const orderId = await this.createOrder({
// productId: this.productId
// });
// Request Apple Pay
const transaction = await this._iap.requestPayment({
productid: this.productId,
manualFinishTransaction: true,
// username: username + orderId //Transparent parameters according to business requirements, associating user and order relationship
});
// await this.validatePaymentResult({
// orderId: orderId,
// username: username,
// transactionIdentifier: transaction.transactionIdentifier
// });
//await this._iap.finishTransaction(transaction);
// payment successful
} catch (e) {
uni.showModal({
content: e.message,
showCancel: false
});
} finally {
this.loading = false;
uni.hideLoading();
}
},
createOrder({
productId
}) {
return new Promise((resolve, reject) => {})
},
validatePaymentResult(data) {
return new Promise((resolve, reject) => {});
},
applePriceChange(e) {
this.productId = e.detail.value;
}
}
}
</script>
<style>
.content {
padding: 15px;
}
button {
background-color: #007aff;
color: #ffffff;
}
.uni-list-cell {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
}
.price {
margin-left: 10px;
}
.btn-pay {
margin-top: 30px;
}
</style>
// uni iap
const ProviderType = {
IAP: 'iap'
}
const IapTransactionState = {
purchasing: "0", // A transaction that is being processed by the App Store.
purchased: "1", // A successfully processed transaction.
failed: "2", // A failed transaction.
restored: "3", // A transaction that restores content previously purchased by the user.
deferred: "4" // A transaction that is in the queue, but its final status is pending external action such as Ask to Buy.
};
class Iap {
_channel = null;
_channelError = null;
_productIds = [];
_ready = false;
constructor({
products
}) {
this._productIds = products;
}
init() {
return new Promise((resolve, reject) => {
this.getChannels((channel) => {
this._ready = true;
resolve(channel);
}, (err) => {
reject(err);
})
})
}
getProduct(productIds) {
return new Promise((resolve, reject) => {
this._channel.requestProduct(productIds || this._productIds, (res) => {
resolve(res);
}, (err) => {
reject(err);
})
});
}
requestPayment(orderInfo) {
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'appleiap',
orderInfo: orderInfo,
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
}
});
});
}
restoreCompletedTransactions(username) {
return new Promise((resolve, reject) => {
this._channel.restoreCompletedTransactions({
manualFinishTransaction: true,
username
}, (res) => {
resolve(res);
}, (err) => {
reject(err);
})
});
}
finishTransaction(transaction) {
return new Promise((resolve, reject) => {
this._channel.finishTransaction(transaction, (res) => {
resolve(res);
}, (err) => {
reject(err);
});
});
}
getChannels(success, fail) {
if (this._channel !== null) {
success(this._channel)
return
}
if (this._channelError !== null) {
fail(this._channelError)
return
}
uni.getProvider({
service: 'payment',
success: (res) => {
this._channel = res.providers.find((channel) => {
return (channel.id === 'appleiap')
})
if (this._channel) {
success(this._channel)
} else {
this._channelError = {
errMsg: 'paymentContext:fail iap service not found'
}
fail(this._channelError)
}
}
});
}
get channel() {
return this._channel;
}
}
export {
Iap,
IapTransactionState
}
// Just as an example, not real parameter information.
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));
}
});
uni-pay
组件发起支付。uniPay
可极快的完成支付业务开发。uni.request
to request the server interface, get the order data, use uni.requestPayment
to initiate a payment request to the payment platform, and pull up the client of the payment platform to pay. Detailed code in hello uni-app.Q: How to use aggregate payment such as ping++
A: The js API of uni-app has been unified across terminals, and the client does not need to use three-party aggregation payment. If the server chooses uniCloud
, there is no need for three-party aggregation payment. If the server is developed using traditional servers such as php and java, you can use three-party aggregation payment on the server.
Q: How to use other payments on the App, such as UnionPay and PayPal. A: App 3.4+ already supports PayPal, the previous version of App 3.4 uses the following scheme
Q: Appstore audit reports that PGPay SDK is not allowed to be listed A: For digital products (such as purchasing members and other products that do not require physical delivery), Apple stipulates that Apple IAP in-app payment must be used, and Apple will be divided into 30%. When packing, do not check other payment methods such as WeChat or Alipay. If the package you submit contains sdk for payment such as WeChat, Alipay, etc., even if you do not use it, the Appstore will think that you have a hidden way, and will bypass the IAP in the future and will not give Apple a share, so it will refuse your App to go online. When the cloud is packaged, the payment module is selected in the manifest, but WeChat payment and Alipay payment are removed from the sdk configuration. Many developers' Android versions include WeChat and Alipay payments, so pay attention to separate judgments at this time. For details, see https://ask.dcloud.net.cn/article/36447