乐趣区

关于webview:小程序webview嵌入公众号网页并实现微信支付下载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{//...}
 
    },

->> 赞赞赞~

退出移动版