隔了一个月的时间,我又来了给大家踩坑了,这次是基于我们的H5微信支付在APP的webview中的实现,废话不多说,进入正题了。
背景介绍
公司新接了一个需求,要求把现有的小程序代码转化为H5,这能难的倒我嘛,在上个版本已经把原生小程序改造成Taro框架的我,五分钟就把dist包打出来甩给了产品,任务完成。"不错不错,客户还要求使用微信H5支付",我还是丝毫不慌,之前也是做过H5支付的,这个流程熟悉的很,"客户是需要在APP的webview中嵌入微信H5支付",what?好吧,那还是来老老实实踩坑吧!
那我们还是按照步骤来进行一步步的处理分析吧
微信H5支付申请
微信的H5支付需要在支付开放平台进行申请,如下图所示,点击进入H5支付,,只有支付开通成功才能进行微信H5支付的开发;
这里就不展开说了,就说几个注意点:
- 域名使用一级域名即可,需要有ICP备案截图;
- 在描述场景文本框中粘贴一下你的网站地址,下方只要求粘贴网站的页面即可,但是我第一次审核没过就是因为我没有提供网站地址;
- 要是你的支付商户主体跟域名主体是一致的,没问题,但要是不一致,需要一份授权书(授权书需要双方公司公章),以及双方之间的合作协议(合作协议只要是双方的合同文档即可,没有硬性要求)
接口调用
其实接口调用主要是服务端同学的任务了,下载微信支付的证书,对数据加密解密等等,前端只需要调用一个下单接口即可。因为之前已经存在小程序支付了,就在现有的接口上进行优化部分参数,实际调用微信接口还需要部分参数(这个是我们的接口的入参,实际参数还是需要根据你们的服务实际情况定义)
js
// 业务封装微信下单接口入参
let myData = {
token: userToken,
body: "充电订单消费",
total_fee: Math.round(Number(rechargePrice.value) * 100), // 支付金额,单位分
spbill_create_ip: "",
trade_type: isH5 ? 'MWEB' : "JSAPI", // 支付类型
clientType: isH5 ? 2 : 1 // 区分支付类型
}
// 判断是否是h5, 不是则写入
if (!isH5) {
myData.openid = openId // 小程序支付需要用户openId
} else {
myData.scene_info = JSON.stringify({
h5_info: {
type:"Wap",
wap_url: store.state.globalData.baseUrl,
wap_name: "充电订单消费"
}
}) // scene_info参数
}
js
// 微信下单接口 https://api.mch.weixin.qq.com/v3/pay/transactions/h5
// 微信下单接口入参
{
"appid": "{{appid}}", ///请求基础下单接口时请注意APPID的应用属性,例如公众号场景下,需使用应用属性为公众号的服务号APPID
"mchid": "{{mchid}}", ///商户号,要与请求头保持一致
"description": "描述测试", ///商品描述
"out_trade_no": "charger0001011", ///户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
"time_expire": "2023-11-11T23:59:59+08:00",
/*订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。 */
"attach": "附加数据", ///附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
"notify_url": "https://dev.suncharger.cn",
/* 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http */
"amount": {
"total": 5, ///订单总金额,单位为"分"
"currency": "CNY" /// CNY:人民币,境内商户号仅支持人民币。
},
"scene_info": {
// "payer_client_ip": "39.144.38.160", ///用户的客户端IP,支持IPv4和IPv6两种格式的IP地址
"payer_client_ip":"220.205.232.233",
"h5_info": {
"type": "Wap" ///场景类型,示例值:iOS, Android, Wap
}
},
"settle_info": {
// 是否开启分账,启用分账账单
// 对分账功能感兴趣的同学可以试一试,我试了一下,还是可行的
// 但是分账金额有最大30%的限制,有很多业务场景不满足,要是想提高分配额度还需要发邮件进行申请
"profit_sharing": true
}
}
这里粘贴一个微信H5支付的官方文档:pay.weixin.qq.com/docs/mercha... ,注意要区分版本,有V2跟V3两个版本,我们因为是老项目了,用的是接入的是V2版本的微信支付。
在这里推荐一个官方的调试工具 ,因为在前期需要调研微信H5支付在APP的webview中是否能够使用,但又不能耽误服务端同事的工作,因此前期调研就是使用这个官方调试工具生成H5的回调链接测试支付的。
嵌入webview
以上地址已经生成了,那么剩下的就是看这个地址能不能唤起支付了,首先地址直接粘贴到浏览器访问,测试安卓以及IOS,都能够唤起微信支付,莫得问题;
然后让我们的APP同事帮忙打一个包,可以动态配置输入webview的访问地址,打开APP,输入支付地址,进入webview,信心满满,晴天霹雳,进入页面之后直接报错了,不过在一阵搜索之后,找到了解决方案。
因为没有原图了,直接从微信官方扒了一张图过来了,错误提示就是左边的内容,"商家参数格式有误,请联系商家解决",解决方法微信官方也提供了,对APP同事百般请求,终于帮我加上了这段代码,成功在webview中唤起微信支付。
其实最开始一样是唤不起微信支付的,APP在webview中添加了一段weixin://的拦截,然后还是不行,最后才加的referer字段。
Loading
你们以为这样就结束了嘛?哈哈,要是就这样那就不叫踩坑了。就当我以为这个Demo完成,那嵌入到三方APP不也是分分钟的事情。
等客户把他们的APP打包给到我之后,出现了Demo上相同的问题,然后我就把APP解决的这段代码给到客户,美滋滋等着客户打一个新包的时候,"我们这边APP不能添加对接的服务商业务性代码,需要你们H5自己解决这个问题",微信上收到这个消息的时候,心又凉了半截,能怎么办,乙方没有话语权,那就找找其他解决方案吧。
问题分析&解决
导致异常的问题微信其实已经给出了,就是当我们跳转微信的支付回调地址的时候referer会丢失,那么我们有什么办法能够不丢失呢?结合网上的方案,列一下:
- 使用window.open(url)打开地址
- 使用动态新增form表单打开地址;
- 使用a标签跳转地址;
- ......
在这里就不一一列举了,以上的方案都试过了,起码在我这里是不可行的,最终在一个大佬的文章里找到了方案:
js
// 需要添加redirect_url,ios会返回中转页面
const redirect_url = encodeURIComponent(location.origin + location.pathname + '#/pages/rechargeSuccess/index?scheme=seariChargingPro')
const mwebUrl = result.data.mwebUrl + "&redirect_url=" + redirect_url
console.log(mwebUrl)
// 使用iframe打开微信支付地址
let iframe = document.createElement('iframe')
iframe.src = mwebUrl //你调用接口返回的微信h5支付的链接
// 允许脚本执行,即允许iframe运行脚本
// 允许 iframe 内容从包含文档导航(加载)内容。
// 允许 iframe 内容被视为与包含文档有相同的来源
iframe.sandbox = "allow-scripts allow-top-navigation allow-same-origin"
document.body.appendChild(iframe)
document.body.click()
// window.focus() 也可以写这个
setTimeout(() => {
document.body.removeChild(iframe);
}, 3000)
总结一下,就是动态新增一个iframe节点,配置sandbox,挂载到body上,然后模拟点击元素,延时3秒时间,移除iframe节点,实现H5微信支付。
IOS回调页面
在IOS中还遇到一个问题,支付完成后不会返回到APP页面,在网上找了一圈,也是有解决方案的,但是也需要APP那边配合处理(只是看到有文章解决了,但是没有测试是否可行),那只能PASS了。最终只能使用redirect_url做一个回调页面了
js
// 需要添加redirect_url,ios会返回中转页面
const redirect_url = encodeURIComponent(location.origin + location.pathname + '#/pages/rechargeSuccess/index?scheme=schemeUrl')
const mwebUrl = result.data.mwebUrl + "&redirect_url=" + redirect_url
- redirect_url地址需要使用encodeURIComponent处理,不然会存在内容丢失;
- 添加scheme参数,在浏览器中可使用schemeUrl://的方式直接唤起APP,会有一个弹窗提示是否打开此APP。
总结
这一次的记录也是为了我自己,在找了很多的文章之后都没有解决问题,将心比心也希望这篇文章能够帮助到跟我类似问题的朋友。
最后粘贴一下大佬的文章链接:blog.csdn.net/weixin_4783...