APP原生webview实现H5微信支付

隔了一个月的时间,我又来了给大家踩坑了,这次是基于我们的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...

相关推荐
陈思杰系统思考Jason6 天前
系统思考—持续修炼
百度·微信·微信公众平台·新浪微博·微信开放平台
JSON_L6 天前
小程序 - 头像上传
微信·小程序
陈思杰系统思考Jason7 天前
系统思考—沟通成本
百度·微信·微信公众平台·新浪微博·微信开放平台
杰克逊的日记9 天前
linux部署安装wordpress
android·java·linux·webview
陈思杰系统思考Jason10 天前
系统思考沙盘模拟
微信·微信公众平台·oneapi·新浪微博·微信开放平台
编织幻境的妖10 天前
使用html 和javascript 实现微信界面功能2
javascript·微信·html
impossible199472710 天前
获取微信用户openid
微信·微信授权·openid
程序员入门进阶12 天前
基于微信的追星小程序+ssm
微信·小程序
编织幻境的妖12 天前
使用html 和javascript 实现微信界面功能1
javascript·微信·html
小曲曲13 天前
监听H5页面在微信浏览器异常退出
微信