小程序web-view嵌入公众号网页并实现微信支付、下载pdf

场景

在微信小程序开发中,使用小程序web-view组件可以在小程序中嵌入一个H5应用。如果在公众号已经开发完成了一个网页,之后又想在小程序中也开发一个相同的应用,就可以直接使用webview组件直接套用一个已发布的公众号页面节省很多开发成本。当有差异化功能时就可以通过微信sdk的接口进行当前是否小程序/公众号的判断,然后进行webview新页面的开发。

我的公众号网页是Vue+iView写的,小程序比较简单因为核心逻辑只是与webview进行通讯,所以是原生编写。本篇主要讲解使用webview遇到的一些问题解决方法以及调起支付、下载功能。简单建立一个原生小程序项目结构:

加入webview

首先建立一个homepage.wxml,内容主要是一个webview组件嵌入公众号页面https://test.xxxx.com/wxgzh,传入openid和appid用于内部传递给生成订单的后端接口,ver参数可以保证页面不缓存(最新的页面):

<!--index.wxml-->
<view class="container">
 <web-view src="https://test.xxxx.com/wxgzh/?someid=38127&openid={{openid}}&appid={{appid}}&ver={{ver}}#/index"></web-view>
</view>

在首页加载时调用官方wx.login接口请求用户登录小程序,登录后调取后端的登录接口去获取openid最终传递到webview中。
homepage.js

//homepage.js
const app = getApp()
Page({
 data: {
 ver:'timesp',
 openid:'',
 appid:''
 },
 onLoad: function() {
 const accountInfo = wx.getAccountInfoSync();
 console.log(accountInfo.miniProgram.appId, '小程序 appId') 
 this.setData({
 ver:new Date().getTime(),
 appid:accountInfo.miniProgram.appId,
 })
 this.doLogin();
 },
 getLoginData(code){
 let that = this;
 wx.request({
 method:'post',
 url: app.globalData.baseUrl+'wx/wx/user/login',
 data: {
 data:{
 appId:this.data.appid,
 code: code
 },
 token:''
 },
 success (res) {
 console.log('获取openid成功',res)
 that.setData({openid:res.data.data.openid});
 },
 fail(res){
 console.log('获取openid失败')
 }
 })
 },
 doLogin:function(){
 let that = this;
 wx.login({
 success (res) {
 if (res.code) {
 //发起网络请求
 that.getLoginData(res.code)
 } else {
 wx.showToast({
 title: '登录失败!',
 })
 console.log('登录失败!' + res.errMsg)
 }
 }
 })
 }
})

给小程序加返回按钮

到这里其实是已经实现可以在小程序中打开公众号页面了,但是有个问题,当webview页面在内部进行多层跳转时,想返回上一层发现微信是没有明确的返回按钮的,影响体验。解决方法是在公众号网页内部自己实现一个公共有返回按钮的TopBar组件,但是我们公众号页面是不需要这个TopBar的。
有一个解决方法是创建一个中间者空页面作为小程序的初始页面index.js,当页面加载时立即跳转到真实的首页homepage,这样做就可以强制让小程序显示出返回按钮了:
index.js

 onShow: function () {
 wx.navigateTo({
 url: '/pages/homepage/homepage' //页面一显示就跳转至主webview页 用于返回按钮的显示
 })
 },

小程序缓存隔离

如果你的公众号有使用本地缓存,用户在使用完公众号网页后又切换回小程序,也就是当用户先后打开了这两个平台,因为微信内置浏览器的问题,同域的两个网站共享了同一个状态,这样会导致内部的网站本地存储的登录状态数据混乱,显然是不行的。

那就要在访问小程序之前就要对当前状态及时进行清除,我这里简单对当前状态判断进行重置状态。

function clearCache(){ 
 if (
 navigator.userAgent.indexOf("miniProgram") >-1 
) { 
 if (this.getBrowserData("isWxmini") === 'false') { 
 //小程序检查到公众网页缓存,清除之前的缓存,包括首次进入小程序情况
 // 给token一个默认值
 localStorage.setItem("token", "xxx");
 document.cookie = "token=xxx";
 sessionStorage.setItem("token", "xxx");
 this.setBrowserData("isWxmini", true);
 console.log("已清除微信来的缓存");
 } 
 } else if (this.getBrowserData("isWxmini") === 'true') {
 //公众网页检查到小程序缓存,清除之前的缓存
 localStorage.setItem("token", "xxx");
 document.cookie = "token=xxx";
 sessionStorage.setItem("token", "xxx");
 this.setBrowserData("isWxmini", false);
 console.log("已清除小程序来的缓存");
 }
}
fetch(myConfig) {
 clearCache.call(this);
 数据请求...
}

因为webview和真实公众号中的页面使用的是同一个前端资源,所以就可以在页面的全局网络请求函数fetch调用之前执行clearCache.call(this)。通过userAgent是否出现miniProgram标识来判断当前是否在小程序当中,使用isWxmini标识来区分环境进行不同环境数据的清除。

小程序支付

在小程序中建立一个wxPay页面,当这个页面加载时就直接调用官方支付的API wx.requestPayment,然后传入从webview中传递出来的支付参数,这么做是因为要从webview中点击支付后跳转过来,后面会介绍:
wxPay.wxml

const app = getApp()
Page({
 data: {
 },
 onLoad: function(options) {
 this.getPayinfo(JSON.parse(unescape(options.payData)));
 },
 getPayinfo:function(data){
 console.log(data);
 // 调起支付
 wx.requestPayment({
 'timeStamp': String(data.timeStamp),//为字符串,否则报错
 'nonceStr': data.nonceStr,
 'package': data._package,
 'signType':data.signType,
 'paySign': data.paySign,
 'success': function (res) {
 console.log('=======支付成功==========');
 wx.showToast({
 title: '支付成功!',
 })
 wx.navigateBack({
 })
 },
 'fail': function (res) {
 console.log('=======支付失败==========')
 wx.showToast({
 icon:'error',
 title: '支付失败!',
 })
 wx.navigateBack({
 })
 }
 })
 
 },
})

接下来是公众号网页的部分:
首先需要在公众号网页中加入以下公共方法,用于在公众号网页中判断当前是否在小程序webview环境中,然后就可以通过isWxMiniEnv标识来编写相应的逻辑

import wx from "weixin-js-sdk";// 引入微信js-sdk
//当前是否在小程序webview环境
common.isWxMiniEnv = () => {
 let env = false;
 wx.miniProgram.getEnv((res)=> {
 env = res.miniprogram;
 });
 return env
}
//进行小程序支付功能调用
common.wxMiniPay = (data,cb) => {
 if(!common.isWxMiniEnv()) return;
 let payData = escape(JSON.stringify(data)) ;
 const url=`../wxPay/index?payData=${payData}`;
 //跳转到小程序支付界面wxPay
 wx.miniProgram.navigateTo({
 url
 });
 cb&&cb(); 
}

wxMiniPay就是一个简单的跳转函数使用sdk中的navigateTo可以直接跳转到小程序中的相应页面并可以在url上传递一些参数进行通讯。

然后准备工作做好之后就可以直接使用wxMiniPay调起支付了,支付时会调用后端支付接口,返回一些订单的参数,给wxMiniPay传入参数用于小程序页面那边接收。

 _this.common.wxMiniPay({order:_this.order,timeStamp, nonceStr, _package, signType, paySign},()=>{
 _this.getOrder(_this.order) //通过接口查询订单是否已支付完成
 });

当跳转完成时这边会执行getOrder方法,这个方法逻辑就是一直轮询当前订单的支付状态,如果返回订单支付完成了就会弹出支付成功的提示,这里我就不贴轮询代码了。

文件下载

因为是在小程序中进行下载,所以也需要在小程序创建一个下载页,当页面加载完成就直接通过传递过来的options下载参数进行下载。
这边调用了微信官方的api wx.downloadFile,传入下载接口和存储的位置,为了防止url参数因为一些特殊字符导致参数错误或者被错误截断,就事先已经编码一遍,所以这里需要进行一遍解码decodeURIComponent。下载完成后调用wx.openDocument直接把文件打开:
download.js

 /**
 * 生命周期函数--监听页面加载
 */
 onLoad: function (options) {
 this.download(options)
 },
 download(options){
 console.log(options.url)
 wx.downloadFile({
 url:decodeURIComponent(options.url), //解码url'
 filePath: wx.env.USER_DATA_PATH + '/'+ decodeURIComponent(options.filename),
 success: function (res) {
 var filePath = res.filePath;
 console.log(res.filePath);
 wx.openDocument({
 showMenu:true,
 filePath: filePath,
 success: function (res) {
 console.log('打开文档成功')
 wx.navigateBack({ //为了不显示空页面 ,及时回退一下
 delta: 1,
 })
 },
 error: function (msg) {
 console.log(msg)
 }
 })
 },
 fail:function(e){
 console.log(e)
 }
 }
 )
 },

设置showMenu:true可以让下载后的文件右上角出现三个点的菜单,就可以对文件进行转发/存储。最后因为download页面是个只有下载逻辑的空页面,需要调用wx.navigateBack来关掉这个空页面。

在公众号下载界面中加入逻辑,主要是当前为小程序时就拼接一个下载url和下载接口的入参,最后通过wxsdk跳转到小程序中的对应download页面,url注意使用encodeURIComponent可以支持更多url符号的编码:

 downLoad() {//下载
 let item = {
 url: '',
 }
 item.url = "?someid=test&someNo='
 + this.$route.query.someNo;
 if(this.common.isWxMiniEnv()){
 let durl = window.location.protocol + "//" + window.location.host + '/wx/pdfDownload' + item.url
 const url=`../download/download?url=${encodeURIComponent(durl)}&filename=文件名.pdf`;
 //跳转到小程序下载界面
 this.wx.miniProgram.navigateTo({
 url
 });
 }else{
 //...
 }
 
 },

->>赞赞赞~

作者:洛阳醉长安行原文地址:https://segmentfault.com/a/1190000042353050

%s 个评论

要回复文章请先登录注册