cordova之支付宝APP支付实践

it2026-01-04  7

当前方式

目前仅在测试andrid环境下通过,IOS暂无测试

targetSdkVersion: 28 vue: 2.6.11 cordova-android: 8.1.0 "cordova-plugin-alipay-v2": "^2.0.0"

APP支付支付情景

用户已安装支付宝支付流程 1.用户在商家 App 中选择商品下单、确认购买,进入支付环节,选择支付宝,用户点击确认支付,如图 1;

2.进入到支付宝页面,调起支付宝支付,出现确认支付界面,如图 2;

3.用户确认收款方和金额,点击立即支付后出现输入密码界面,如图 3;

4.输入正确密码后,支付宝端显示支付结果,如图 4; 5.自动回跳到商家 App 中,商家根据付款结果个性化展示订单处理结果,如图 5。

用户未安装支付宝支付流程 1.用户在商家 App 中选择商品下单、确认购买,进入支付环节,选择支付宝,用户点击确认支付,如图 6; 2.用户未安装支付宝客户端,则调起支付宝网页支付收银台,用户登录支付宝账户,如图 7; 3.登录成功后,进入确认付款页面,如图 8;

4.用户点击确认付款,进入支付密码页面,如下图 9; 5.用户输入密码,完成支付,展示支付结果,如图 10。

准备

申请前必须拥有经过实名认证的支付宝账户;

企业或个体工商户可申请;

需提供真实有效的营业执照,且支付宝账户名称需与营业执照主体一致;

网站能正常访问且页面显示完整,网站需要明确经营内容且有完整的商品信息;

网站必须通过 ICP 备案。如为个体工商户,网站备案主体需要与支付宝账户主体名称一致;

如为个体工商户,则团购不开放,且古玩、珠宝等奢侈品、投资类行业无法申请本产品。

支付宝APP支付流程

步骤3:返回带有签名信息的订单信息示例格式如下:

'alipay_sdk=alipay-sdk-java-dynamicVersionNo' + '&app_id=2016101600701716&biz_content=%7B%22body%22%3A%22null%' + '3Anull%22%2C%22out_trade_no%22%3A%22313507361383776256%22%2C%22' + 'product_code%22%3A%22ET+order%22%2C%22subject%22%3A%2239+%E5%AE' + '%B9%E8%A5%BF%E5%A4%A7%E6%B0%B4%E8%A1%97%E5%8A%9E%E5%85%AC%E5%8C%BA%' + '3A18+%E6%B3%8A%E5%AF%93%EF%BC%88%E8%B1%AA%E4%B8%B9%E5%BA%97%EF%BC%89%' + '22%2C%22timeout_express%22%3A%2230m%22%2C%22total_amount%22%3A%220.01%22%' + '7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&notify_url=https%3A%' + '2F%2Fipts.zpmc.com%2Fpss%2Fet-service%2Falipay%2Fcallback&sign=aeCeGuaUI9kDYwz0L' + '3UIR99knqh%2F1rrxjp8gXDQY3q6wxMQoSDn5NCS3RTUwGYT5%2FlgLu9NRq8ywUkrp6zWvy%2Filj5%2F4' + 'ZGkFhiDfEnNjKimeUq9Ne1tpNEYRHrv19dalaOEO7vXbrJjpzg5w9fqo1m0MDISVj3PlFwMcOF6ZDc%2Br' + '4GDbkvbrX%2BSjsBCX7CPWDR5eijFN199VtvrFHOOrfdIRkYCDRoLjdsXwTKxnrWagutcGdPjMLdIM%2FXyO' + 'f77fLmSrfEKrUNGfMHBlOY6%2FxDqVVCAqDQgQutVF5La%2BKzUtgij8T6fC9IGRncjFpn%2F9vfXFWyZE%2F' + '3zEZqMFTZCSYg%3D%3D&sign_type=RSA2&timestamp=2020-09-02+17%3A00%3A28&version=1.0';

步骤4:调用支付接口 这一步就需要安装插件:cordova-plugin-alipay-v2

npm安装

cordova plugin add cordova-plugin-alipay-v2 --variable APP_ID=your AppId(支付宝注册app产生的AppId)

代码实例

cordova.plugins.alipay.payment(payInfo,function success(e){ // 支付成功 },function error(e){ //TODO 支付失败 console.log("支付失败" + e.resultStatus); });

步骤8 接口返回支付结果 结果参数对应状态和字段解释如下:

// e.resultStatus 状态代码 e.result 本次操作返回的结果数据 e.memo 提示信息 // // e.resultStatus:9000 订单支付成功;8000 正在处理中;调用function success // // error.resultStatus:4000 订单支付失败;6001 用户中途取消;6002 网络连接出错 ;调用function error // // 当e.resultStatus为9000时,请去服务端验证支付结果,建议商户依赖异步通知 同步返回的结果必须放置到服务端进行验证,具体请查看验证的规则 。 /** * e.result参数返回结果: * out_trade_no String 是 64 商户网站唯一订单号 70501111111S001111119 trade_no String 是 64 该交易在支付宝系统中的交易流水号。最长64位。 2014112400001000340011111118 app_id String 是 32 支付宝分配给开发者的应用Id。 2014072300007148 total_amount Price 是 9 该笔订单的资金总额,单位为RMB-Yuan。取值范围为[0.01,100000000.00],精确到小数点后两位。 9.00 seller_id String 是 16 收款支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字 20886894 msg String 是 16 处理结果的描述,信息来自于code返回结果的描述 success charset String 是 16 编码格式 utf-8 timestamp String 是 32 时间 2016-10-11 17:43:36 code String 是 16 结果码 */

步骤9 将同步支付结果返回后端,后端解析支付结果 此时在e.resultStatus === 9000时 将e.result中返回的json字符串,转换成对象,传入后端接口

此时在e.resultStatus === 8000时表示支付中,还未获取支付状态,我们可以在一段时间再次轮询订单的支付状态避免支付结果不准确,此时不需要进入步骤10 步骤10. 获取接口返回最终支付状态结果(与后端协商支付状态字段)

关于cordova中沙箱环境设置

在本项目(app-xiongan)\platforms\android\app\src\main\java\cn\hhjjj\alipay\alipay.java中在支付方法调用之前添加设置沙箱环境的代码 com.alipay.sdk.app.EnvUtils.setEnv(com.alipay.sdk.app.EnvUtils.EnvEnum.SANDBOX); 如下:

@Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { if (action.equals("payment")) { String orderInfo = args.getString(0); + com.alipay.sdk.app.EnvUtils.setEnv(com.alipay.sdk.app.EnvUtils.EnvEnum.SANDBOX); this.payment(orderInfo, callbackContext); return true; } return false; }

有点:在没有注册支付宝app账户时,可以先使用沙箱环境开发,节省时间。 如何设置沙箱环境:请看沙箱指南

前端代码:(代码仅为部分思路代码,不能单独运行,仅供思路参考)

bridge部分

/** * 支付宝支付 */ aliPayMent(payInfo) { // let timer = null; return ready((resolve, reject) => { if (isApp) { if (window.cordova && window.cordova.plugins && window.cordova.plugins.alipay) { // 支付宝支付流程: // 1.如果已经安装支付宝 // 进入到支付宝页面,调起支付宝支付,出现确认支付界面; // 用户确认收款方和金额,点击立即支付后出现输入密码界面; // 输入正确密码后,支付宝端显示支付结果; // 自动回跳到商家 App 中,商家根据付款结果个性化展示订单处理结果 // 2.如果未安装支付宝 // 用户未安装支付宝客户端,则调起支付宝网页支付收银台,用户登录支付宝账户; // 登录成功后,进入确认付款页面; // 用户点击确认付款,进入支付密码页面, // 用户输入密码,完成支付,展示支付结果,不会自动跳转到商家App // 支付宝状态 // e.resultStatus 状态代码 e.result 本次操作返回的结果数据 e.memo 提示信息 // // e.resultStatus:9000 订单支付成功;8000 正在处理中;调用function success // // error.resultStatus:4000 订单支付失败;6001 用户中途取消;6002 网络连接出错 ;调用function error // // 当e.resultStatus为9000时,请去服务端验证支付结果,建议商户依赖异步通知 同步返回的结果必须放置到服务端进行验证,具体请查看验证的规则 。 /** * e.result参数返回结果: * out_trade_no String 是 64 商户网站唯一订单号 70501111111S001111119 trade_no String 是 64 该交易在支付宝系统中的交易流水号。最长64位。 2014112400001000340011111118 app_id String 是 32 支付宝分配给开发者的应用Id。 2014072300007148 total_amount Price 是 9 该笔订单的资金总额,单位为RMB-Yuan。取值范围为[0.01,100000000.00],精确到小数点后两位。 9.00 seller_id String 是 16 收款支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字 20886894 msg String 是 16 处理结果的描述,信息来自于code返回结果的描述 success charset String 是 16 编码格式 utf-8 timestamp String 是 32 时间 2016-10-11 17:43:36 code String 是 16 结果码 */ window.cordova.plugins.alipay.payment(payInfo, e => { console.log(e, 'e===pay'); switch (e.resultStatus) { case '9000': resolve(e); break; case '8000': resolve(e); // clearTimeout(timer); // timer = setTimeout(() => { // this.aliPayMent(payInfo).then(data => { // resolve(data); // }); // }, 1000); break; case '4000': reject(e || '订单支付失败'); break; case '6001': reject(e || '用户中途取消'); break; case '6002': reject(e || '网络连接出错'); break; default: reject(e); break; } }, e => { //TODO 支付失败 console.log('支付失败' + e.resultStatus); reject(e); }); } else { reject('是否安装支付包插件,请检查插件'); } } }); }

使用支付宝支付代码

// 统一转换promise结果 function awaitWraper(promise) { return promise .then(res => [null, res]) .catch(err => [err, null]); } // 将同步支付结果返回后端,后端解析支付结果 function checkSign(resultObj) { const _this = this; const alipayResponse = resultObj.alipay_trade_app_pay_response || {}; if (!Object.keys(resultObj).length || !Object.keys(alipayResponse).length) { this.$toast.error('支付失败,校验参数缺失!'); return; } const param = { sign: resultObj.sign || '', sign_type: resultObj.sign_type || '', ...alipayResponse, }; const [callbackError, callbackData] = await this.awaitWraper(api.et.alipayCallback(param)); const data = callbackData.data || {}; console.log(callbackError, callbackData, data, '获取cheksign'); // 获取支付状态 if (data && data.success) { try { _this.$et.cancelOrderSuccess(); } catch (e) { window.console.debug(e); } // _this.$toast.success('支付成功,即将跳转!'); _this.visible = false; console.log('success===='); } else { this.$toast.error('支付失败,支付校验没有通过!'); } } // 获取支付状态 function checkOrderPaymentStatus(orderId) { if (!orderId) return; api.et.alipayCallback(orderId).then(res => { console.log(res, 'checkOrderPaymentStatus==='); const data = res.data || {}; if (data && data.success) { this.$toast.success('支付成功,即将跳转!'); this.visible = false; if (this.timer) { clearInterval(this.timer); } } }).catch(error => { console.log(error, '查询订单支付状态失败!'); }); } // 多次轮询支付状态 function setIntervalPaymentStatus() { // 轮询支付状态 let count = 0; const _this = this; const orderId = (this.orderInfo && this.orderInfo.id) || ''; if (this.timer) { clearInterval(this.timer); this.timer = null; } this.timer = setInterval(function () { if (count > 5) { clearInterval(_this.timer); _this.timer = null; _this.$toast.error('支付处理中!'); _this.visible = false; } else { count++; _this.checkOrderPaymentStatus(orderId); } }, 10); } // 调用支付接口,获取支付结果 function aliPayment(payInfo) { if (!payInfo) { this.$toast.error('订单信息参数不存在!'); return; } // 调用bridge const [paymentError, paymentData] = await this.awaitWraper(this.$bridge.aliPayMent(payInfo)); console.log(paymentError, paymentData, 'aliPayment支付'); if (paymentError) { this.$toast.error('支付失败!'); return; } if (paymentData && paymentData.resultStatus === '9000' && paymentData.result) { // 支付状态为9000,将返回的同步结果再次传给后端进行异步校验 const result = paymentData.result || ''; const resultObj = JSON.parse(result) || {}; if (Object.keys(resultObj).length) { await this.checkSign(resultObj); } else { this.$toast.error('支付失败,无法获取支付交易返回信息!'); console.log(paymentData, 'error===='); } } else if (paymentData && paymentData.resultStatus === '8000') { // 支付状态为8000,表示支付中,多刷新几次获取支付状态 this.setIntervalPaymentStatus(); } else { this.$toast.error('支付失败!'); console.log(paymentData, 'error===='); } } // 提交支付 function onSubmit() { if (!this.orderInfo || !this.orderInfo.id) { this.$toast.error('订单不存在!'); return; } // 获取订单信息 const params = { orderId: this.orderInfo.id || '', paymentMethod: 'ALIPAY' }; // 支付宝App方式,api.et.alipay从后端返回订单信息 const [payError, payData] = await awaitWraper(api.et.alipay(params)); if (payError) { console.log(payError, '获取订单支付信息失败!'); this.$toast.error('获取订单支付信息失败!'); return; } const payInfo = (payData && payData.data && payData.data.body) || ''; // 将获取的订单信息 await aliPayment(payInfo); }

遇到过的问题

支付宝相关:

支付返回4000:后端沙箱环境调用的是前端实际支付宝app,应该调用支付宝App沙箱包系统繁忙清稍后再试的错误:支付宝插件使用的是实际支付环境,设置支付宝插件为沙箱环境系统繁忙,稍后再试,ALIN10070:所有存在错误的链接 本次实践有问题的原因:没有商家授权应用

参考文档

支付宝APP支付文档

最新回复(0)