微信小程序开发之webview组件内网页实现微信原生支付
前言、背景
本人目前的工作岗位是安卓工程师,在这之前对于前端和后台的知识基本是白纸,只是在日常的工作项目中有需要和小伙伴进行对接的时候接触了那么一丢丢,对于前端和后台的一些专业描述和理解有不当之处还请各位指正。
目前部门的主营项目是一个电商项目,在本人入职之前整个项目系统的主营业务流程已经完备,也已经在正式运营,不过因为各种原因平台主要是在PC端和微信公众号进行运营。小程序其实出来的挺早的,但是优先级对于我们目前的规划来说其实还是很低的。直到17年11月的时候小程序推出了web-view组件,在当时被誉为移动电商的福音&&&&$$$...此处省略五千字。
有了web-view那什么公众号内容、官网、网页有域名的那种直接就可以扔到小程序的webview组件了,极大的减少了开发成本,就是一把梭。。。。
关于小程序
小程序的解释什么的不巴拉巴拉,直接上干货开发文档就不做过多解释
微信小程序
关于小程序web-view组件
先奉上传送门小程序 webview相关说明和API使用
官方解释:web-view 组件是一个可以用来承载网页的容器,会自动铺满整个小程序页面。个人类型与海外类型的小程序暂不支持使用。
web-view组件开放时间并不久,所以目前的还是有很多局限性的。
关于webview配置指向的链接的去小程序后台进行配置就好(不配置webview是访问不了的)必须支持https 如图:
示例代码:
示例代码
做过微信公众号的童鞋应该都知道,在公众号里商家H5页面内调用JSSDK就可以实现微信支付功能。但是看过webview组件的API的文档的童鞋应该知道:webview 里面的网页(公众号迁移的网页)是调用不了外部的微信支付what....... 虽然微信支付也确实是提供了小程序的微信支付API,但是因为我们整个小程序的内容就是一个webview嵌入公众号内容的网页,在网页内下订单的过程中是无法通过webview的api接口通知小程序调起微信支付的。 查看微信支付小程序的支付文档,我们小程序如果要调用微信支付只需要得到以下参数就可以。
如图:小程序调用微信支付参数
以及示例代码
示例代码
看到这些一切就明朗了,在小程序端只要能通过某种方式得到webview内网页下单后的生成的相关参数就能调起微信支付从而实现webview组件内网页微信支付。
实现方式和主要流程
-
先说明一下整个小程序实现webview调用支付的代码结构如图:
项目代码结构
整个结构很清晰、简单,不做过多解释。微信小程序采用的MVVM的模式。
xxxx.wxml
类似于安卓activity的xml文件。
xxxx.js
类似于安卓中MVC模式的控制层。
xxxx.wxss
类似于前端的CSS样式。我们目前几乎没用到,因为只用到了小程序的webview组件。
- 原理分析
我们来看一下微信小程序支付的的业务流程:
上面已经提到如果需要小程序的webview组件调起微信支付,需要网页内部统一下单得到支付参数,然后通过小程序API调起微信支付,如下:
wx.requestPayment(
{
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){},
'fail':function(res){},
'complete':function(res){}
})
那么小程序如何得到支付参数呢,查看webview的API文档发现 webview的内部网页可以通过JSSDK的该API 实现webview网页内部控制小程序。
wx.miniProgram.navigateBack
进行小程序页面的跳转比如我们的项目在 index.wxml 的 webview 网页内部使用该API就可以控制小程序从index page 跳转到wxpay page。
具体实现步骤
- 在index.wxml文件添加webview组件,用来装载原公众号里面的网页内容
<web-view src="{{url}}"></web-view>
该url是index.js里面data定义的一个变量``,方便通过index.js的setData方法对webview的网页进行动态加载
- 新建wxpay目录,并新建wxpay的page页面用来处理支付逻辑。(该页面目前是空白的,功能上分析该页面只是为了收到webview网页的支付参数,从用户使用角度上来说该页面是一个支付页面应该需要添加一些用户交互的,比如转圈QAQ)
- webview网页用户在生成订单后,选择微信支付即走微信的统一下单流程,生成微信支付的参数和sgin。在webview网页内部通过path携带参数跳转到wxpay页面,具体伪代码实现如下(注释很清楚): 重点: 这部分是后端代码 即小程序内部网页的代码(在java工程中为 .ftl文件)。我的这个方案是需要后端进行逻辑更改的。看懂的朋友应该知道只有当后端微信支付下单流程完成后才能得到调起微信支付需要的参数。这部分都是后端实现的。 只有后端下单流程完成,然后判断是不是小程序是小程序就是下面的代码。不是就继续走公众号的微信支付
//判断是否是在wx小程序环境
if(small_wx && data.resultCode=='success'){
//点击微信支付后,调取统一下单接口生成微信小程序支付需要的支付参数
var params = '?timestamp='+data.jsparams.timeStamp+'&nonceStr='+data.jsparams.nonceStr
+'&'+data.jsparams.pkg+'&signType='+data.jsparams.signType
+'&paySign='+data.jsparams.paySign+'&orderId='+data.orderid+'&pType=0';
//定义path 与小程序的支付页面的路径相对应
var path = '/pages/wxpay/wxpay'+params;
//通过JSSDK的api使小程序跳转到指定的小程序页面
wx.miniProgram.navigateTo({url: path});
}
- 小程序端wxpay页面逻辑实现(wxpay.js),webview内的网页通过
wx.miniProgram.navigateTo({url: path})
携带参数使小程序跳转到wxpay页面。wxpay.js 对url中携带的参数进行处理,然后通过wx.requestPayment
调起微信支付并对支付的回调通知进行处理,具体代码实现如下(注释很详细不做过多赘述):
onLoad: function (options) {
var that = this;
//页面加载调取微信支付(原则上应该对options的携带的参数进行校验)
that.requestPayment(options);
},
//根据 obj 的参数请求wx 支付
requestPayment: function (obj) {
//获取options的订单Id
var orderId = obj.orderId;
//调起微信支付
wx.requestPayment({
//相关支付参数
'timeStamp': obj.timestamp,
'nonceStr': obj.nonceStr,
'package': 'prepay_id=' + obj.prepay_id,
'signType': obj.signType,
'paySign': obj.paySign,
//小程序微信支付成功的回调通知
'success': function (res) {
//定义小程序页面集合
var pages = getCurrentPages();
//当前页面 (wxpay page)
var currPage = pages[pages.length - 1];
//上一个页面 (index page)
var prevPage = pages[pages.length - 2];
//通过page.setData方法使index的webview 重新加载url 有点类似于后台刷新页面
//此处有点类似小程序通过加载URL的方式回调通知后端 该订单支付成功。后端逻辑不做赘述。
prevPage.setData({
url: "https://xxxxxxxxxx.com/wx_isPayment.jhtml?orderId=" + orderId + '&ispay=0',
}),
//小程序主动返回到上一个页面。即从wxpay page到index page。此时index page的webview已经重新加载了url 了
//微信小程序的page 也有栈的概念navigateBack 相当于页面出栈的操作
wx.navigateBack();
},
//小程序支付失败的回调通知
'fail': function (res) {
console.log("支付失败"),
console.log(res)
var pages=getCurrentPages();
var currPage = pages[pages.length - 1];
var prevPage = pages[pages.length - 2];
console.log("准备修改数据")
prevPage.setData({
url: "https://xxxxxxxxxx/wx_isPayment.jhtml?orderId=" + orderId + '&ispay=0' ,
}),
console.log("准备结束页面")
wx.navigateBack();
}
})
},
- 微信支付后的回调通知,当wxpay页面调用
navigateBack
的时候回到index页面的时候webview 已经加载https://xxxxxxxxxx/wx_isPayment.jhtml?orderId=" + orderId + '&ispay=0'
这个网页,后台实现相关逻辑。通过orderId查询该订单是否支付成功。如果支付成功就网页重定向到支付成功的页面,如果支付失败还是待支付页面。用户依旧可以点击微信支付按钮进行微信支付。 - 至此小程序的webview组件内网页就可以实现微信支付了。
see you agin
如果用原生小程序组件实现商城支付就没这么麻烦,但是工作量会非常巨大。直接把公众号的网页移植到小程序的webview里面,极大的节省了开发时间,对于小商户来说还是非常方便的。我们现在也算是偷懒把,毕竟投入不大、优先级不够、先弄个东西出来可以用,小程序没有一个向服务端的wx.request
请求。但是我内心其实拒绝的。。。。。因为用户体验和产品角度都很low.........
补上两张支付效果图嗯哼。。。(有小伙伴问到我就统一说明一下)
1 webview内的网页下单成功
熟悉开发的小伙伴应该知道出现这个页面的时候。其实只是后端生成了一个订单而已,这个时候和支付还没有一毛钱关系(微信支付时序图中的生成商户订单)。 此时用户点击微信支付按钮即为时序图中的 5 调用统一下单API()---》生成预付单----》返回预付单信息(prepay_id). 6 生成JSAPI页面调用的支付参数并签名() 返回支付参数(prepay_id, paySgin等) 以上其实都还是微信公众号的下单,生成支付逻辑
只有当得到支付参数后,判断是小程序环境才通过
var path = '/pages/wxpay/wxpay'+params;
//通过JSSDK的api使小程序跳转到指定的小程序页面
wx.miniProgram.navigateTo({url: path});
这个API 将支付参数传到wxpay page页面。 至此通信流程完成
附上微信公众号支付的 时序图 微信公众号支付时序图参考
2 当index的微信支付下单流程完成后,通过jssdk的 wx.miniProgram.navigateTo API 将数据传递到wxpay page页面。 当wxpay得到参数后,验证参数无误就调用 wx.requestPayment 调起微信支付
微信支付如何联系我:https://wyysz.github.io/
划重点、很重要 很重要 2018/2/24更新。针对不少朋友咨询我不成功,调用不了微信支付、小程序提示我appid与商户号不一致的问题解释说明。。。。
首先上面的博客主要是说的实现流程、对于微信支付的逻辑我几乎没提。因为潜意识我理解为要做着功能的小伙伴是知道微信支付如何实现的。因为很多人问了 所以就补充一下吧。
一个订单要能支付那么 openid 微信用户的标识,appid 小程序标识或者公众号标识 ,商户号,mchid,证书啥的。。
按照我博客的内容来走到现在 应该是小程序能正常使用,但是就是调起不了微信支付。 。。。 很正常呀,因为你没参考小程序支付的微信支付流程来呀,你用公众号的支付逻辑在小程序的里面怎么能走的通。 一定要修改后端支付逻辑并且按照微信支付 小程序支付的文档说明来
第一步:openid的获取,通过wx.login的到的code换取session_key
参考链接: https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject
截图如下:
这是第一步通过这种方式得到用户的唯一标识 openid。。。。
第二步就是参考微信支付 小程序支付了(即修改的逻辑)
首先让小程序有微信支付的能力,即开通微信支付可以选择截图的方式,前提是有微信商户号。
参考链接:
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_11&index=2
然后就是参考小程序支付api 实现支付生成支付参数。。。。即开始说的timeStamp、noncestr、package、signtype、paysgin等。
微信支付 小程序支付文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=4
截图:
最后附上我们自己的后端生成支付参数的代码,这里用到了openid 对应了微信支付 小程序支付 提到的统一下单------》都需要先获取到Openid,调用相同的API。
代码参考:
后端生成支付订单.png
代码中的result就包含了 唤醒微信支付sdk 所需要的参数。至此后端逻辑应该就讲完了。 按照我的博客来做 不能实现支付的九成九是没改后端逻辑的小伙伴,没有仔细理解微信支付 小程序支付该怎么做。 和我开始没说要该支付逻辑也有一定关系。。。补上。有问题可以留言或者联系我。 码字不易,如果对你有帮助请多支持。