场景:小程序页面有一个web-view组件,组件嵌套的H5页面,要唤起微信支付。
先讲一下我的项目,首先我是自己开发的一个H5触屏版的商城系统,里面含有购物车,订单支付等功能。然后刚开始,我们公众号里面点击官网导航,其实就是访问的 https://m.xxxx.com
然后支付的时候,我判定了如果是微信浏览器则只展示微信公众号支付,如果是外部浏览器则展示支付宝、微信H5支付 2个选项。
小提示:(微信支付分了 微信公众号支付和微信H5支付,微信H5支付是后期才出的,早期没有。微信公众号支付是在微信浏览器内访问H5页面发起支付,微信H5支付是外部手机浏览器唤起微信客户端发起支付。)
然后后来,公司觉得,公众号的直达性不够好,也就是用户扫一扫出现公众号后,还需要点一下官网才能访问官网,而我们希望用户在海报上扫一下二维码就打开官网,而不要和公众号产生关系。所以就去申请了一个小程序,并且与我们公众号绑定。然后人手不足,我们不打算重新开发一个小程序,所以直接拿小程序的web-view嵌套我们的官网地址 https://m.xxxx.com 这个域名。
嵌套好了以后,一切没问题,但是在支付这块有问题,调用微信公众号支付没法用,一片空白,调用微信H5支付,提示我需要在外部浏览器打开。
然后我在此不得不吐槽一下微信支付,自家的产品,自家的小程序,为什么不能让我们开发者用得省心点?明明是web-view组件,嵌套H5页面,也满足了微信内部浏览器访问才对,愣是不给我调用微信公众号支付,还得自己去实现新的支付。醉了。按道理来说,开发者调用你的jssdk,最省心的就是,我不需要管我当前的环境,只负责调用你的jssdk的某个方法,你自己管好当前是微信浏览器,还是外部浏览器,选择合适的方式弹出微信支付确认框即可。但是,特么的为了集成你一个微信支付,我愣是对接了一个微信公众号支付,微信H5支付,现在又要多一个小程序支付,明明明明他们都是一个H5支付而已。吐槽完毕,步入正题。他们这样做毕竟有他们的道理,我等开发者只有老老实实按别人说的做就可以了。
现在明确知道的小程序嵌套H5页面,引用微信的jssdk后,支持的接口如下链接展示 https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html
可以知道是支持不了微信公众号支付的。其实,微信公众号支付,也就是统一下单后,再调用 WeixinJSBridge.invoke('getBrandWCPayRequest 这个方法唤起支付确认框,可以明确知道这个方法并没有被小程序web-view支持。
同时,如果调用微信H5支付,会被提示在微信外浏览器打开,我估计是因为微信H5支付的那个支付地址(H5支付会让用户去访问一个mweb_url 这个 mweb_url地址我估计是判定了useragent,小程序web-view的useragent带了 MicroMessenger)
综上,各位开发者们,就不要再想歪门邪道的方法在小程序web-view页面嵌套的H5页面上唤起 微信公众号支付或者微信H5支付了,不可能的!就目前(20180930)而言肯定不可能。如果你还想想办法让它兼容你的网页,你就慢慢想吧,有办法了告诉我。所以,我的结论是:唯一的办法就是,想办法让H5页面,唤起小程序支付。
根据上面说的,唯一的路子就是你的H5页面唤起小程序支付,其实也简单,我是按下面这么干的。
首先,小程序放一个页面,叫做 orderPay.js ,这个是发起小程序支付用的页面,然后我们在H5页面发起支付的时候,把页面导到这个小程序页面即可,这点是可以做到的,接口是 wx.miniProgram.navigateTo ,大家可以看下这个接口的描述,是允许你带参数的。所以,一切就很明了了。
我的流程是:判定当前环境是否小程序-->跳转到 miniProgramPaySend.aspx ,这个页面将程序导向小程序原生页面 orderPay ,并且带着一个参数 orderId(我商城系统的订单id)
miniProgramPaySend.aspx 页面代码
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
<script type="text/javascript">
wx.miniProgram.getEnv(function (res) {
if (res.miniprogram) { //只有在小程序环境下,才跳转到小程序支付页面去支付,否则的话都是跳转到订单详情去让它重新选支付方式。
wx.miniProgram.navigateTo({ //这将唤起小程序的原生页面
url: '/pages/pay/orderpay?orderId=<%=Request.QueryString["orderId"]%>&username=<%=new Cookies().Username%>&token=<%=new Cookies().Token%>'
})
}
else {
var ok = confirm("非微信小程序环境,请选择在公众号处支付。");
if(true){ //不管用户点哪个按钮都是去订单详情
location.href = "/muserCenter/myWebsiteOrder/detail/?orderId="+<%=Request.QueryString["orderId"]%>;
}
}
})
然后,小程序 orderPay 页面 onload 的时候,获取这个单号,然后用 wx.request 方法请求我自己的接口,这个接口去请求微信 统一下单接口,返回小程序支付需要的相关参数 ,比如 package timeStamp 等 然后再用 wx.requestPayment
来发起请求支付即可正常弹出支付请求页面了。
代码片段我贴一点吧。 以下是我小程序 orderPay 页面的 onLoad 方法
onLoad: function (option) {
//console.log("orderId:" + option.orderId);
var openid = wx.getStorageSync("openid"); //我在app.js里面登录然后换好了openId保存在了本地缓存中了
var orderId=option.orderId; //这是我商城系统的orderId
var username=option.username; //这是我商城系统鉴权的username
var token=option.token; //这是我商城系统鉴权用的 token
console.log("orderId:" + orderId + "|username:" + username + "|token:" + token);
//这个请求是去拿小程序支付需要的相关参数用的,具体怎么获取这些参数,看文档吧兄台。
wx.request({
url: config.api_baseDomain +'/musercenter/wxMiniProgram/ApiRequest.aspx?action=getPayInfo&orderId='+orderId+'&openid='+openid+'&username='+username+'&token='+token,
dataType: 'json',
success(res) {
console.log("支付信息:" + JSON.stringify(res.data)); if (typeof (res.data.package) == "undefined") { //说明统一下单失败了,由小程序页面唤起 web-view 页面,并指定web-view 访问的地址,其实吧,也就是打开一个H5页面
console.log("发起支付异常,原因:"+res.data);
var urlTemp = config.api_baseDomain + '/muserCenter/myWebsiteOrder/detail/?orderId=' + orderId + '&msg=' + res.data.errorMsg; webviewUtils.GoToWebViewWithUrl(urlTemp); }
else{ //如果相关参数请求正确的话,就开始发起小程序支付
wx.requestPayment(
{
'timeStamp': '' + res.data.timeStamp + '',
'nonceStr': '' + res.data.nonceStr + '',
'package': '' + res.data.package + '',
'signType': '' + res.data.signType + '',
'paySign': '' + res.data.paySign + '',
'success': function (res) //支付成功的话,打开一个H5地址
{
var urlTemp = config.api_baseDomain + '/muserCenter/myWebsiteOrder/detail/?orderId=' + orderId + '&msg=支付成功!'
console.log(JSON.stringify(res))
webviewUtils.GoToWebViewWithUrl(urlTemp); },
'fail': function (res) //同上
{
var msg="支付失败";
if (res.errMsg.indexOf("fail cancel"))
{
msg="支付取消";
}
var urlTemp = config.api_baseDomain + '/muserCenter/myWebsiteOrder/detail/?orderId=' + orderId + '&msg='+msg
console.log(JSON.stringify(res))
webviewUtils.GoToWebViewWithUrl(urlTemp);
},
'complete': function (res) { }
})
} }
}) },
整个支付撸明白了就不算难了。当时花了好长的时间再那里求证web-view到底能不能唤起微信公众号支付,当时一脸蒙蔽的认为都是微信的东西,应该 不用做任何修改就能直接唤起微信公众号支付。。。。其实本来应该要可以才对的。。。。
哦,对了,还有关于统一下单的,用户openId的问题,这个openId,你不能拿公众号的那套方法去获取,获取出来的虽然能用来统一下单,但是不能用小程序来支付,会提示你appid不正确,因为你统一下单拿公众号的appid,然后支付的时候用的是小程序的appid,铁定不行,应该要按小程序的办法获取openId来做统一下单才行,我是在小程序启动,即 app.js 的