網頁程序遷移至微信小程序web-view詳解

小程序如今愈來愈流行,可是公司的不少項目都是用網頁寫的,小程序語法不兼容原生網頁,使得舊有項目遷移至小程序代價很高;
小程序以前開放了webview功能,能夠說是網頁應用的一大福音了,可是微信的webview有一些坑,這篇文章就是列舉一下我在開發過程當中遇到的一些問題以及我找到的一些解決方案。html

遇到的問題

  1. openid登陸問題
  2. webview動態src
  3. 支付功能
  4. 分享功能
  5. 掃描普通二維碼跳轉特定頁面
  6. 返回按鈕缺失問題

openid登陸問題

微信webview的使用方法很簡單,只要以下設置src就能夠展現具體的網站了。web

<!-- wxml -->
<!-- 指向微信公衆平臺首頁的web-view -->
<web-view src="https://mp.weixin.qq.com/"></web-view>

微信環境裏的不少網頁都是用頁面要實現網站的登陸功能,只要把登陸的信息,好比openid或者其餘信息拼接到src裏就行了。
這裏有個問題,公衆號的帳號體系通常是以openid來判斷惟一性的,小程序是能夠獲取openid的,可是小程序的openid和原公衆號之類的openid是不同的,須要將原先的openid帳號體系升級爲unionid帳號體系。小程序

如下是微信對unionid的介紹

獲取用戶基本信息(UnionID機制)api

在關注者與公衆號產生消息交互後,公衆號可得到關注者的OpenID(加密後的微信號,每一個用戶對每一個公衆號的OpenID是惟一的。對於不一樣公衆號,同一用戶的openid不一樣)。公衆號可經過本接口來根據OpenID獲取用戶基本信息,包括暱稱、頭像、性別、所在城市、語言和關注時間。
請注意,若是開發者有在多個公衆號,或在公衆號、移動應用之間統一用戶賬號的需求,須要前往微信開放平臺(open.weixin.qq.com)綁定公衆號後,纔可利用UnionID機制來知足上述需求。 服務器

UnionID機制說明:微信

開發者可經過OpenID來獲取用戶基本信息。特別須要注意的是,若是開發者擁有多個移動應用、網站應用和公衆賬號,可經過獲取用戶基本信息中的unionid來區分用戶的惟一性,由於只要是同一個微信開放平臺賬號下的移動應用、網站應用和公衆賬號,用戶的unionid是惟一的。換句話說,同一用戶,對同一個微信開放平臺下的不一樣應用,unionid是相同的。微信公衆平臺

作完以上步驟,就能夠調用小程序api wx.getUserInfo() 來獲取用戶信息了,此步驟須要進行後臺信息解密過程,在此就再也不贅述,結合小程序api文檔操做就好。函數

獲取到unioid以後,將unionid信息拼接到src就能夠進行網頁登陸操做了(前提是網頁能夠用跳轉連接的方式登陸,相似公衆號頁面獲取openid的形式)。工具

webview動態src

微信的webview有個坑的地方,不會動態的監聽src的變化,這就形成了一個問題,要經過改變src實現頁面跳轉就不能夠了。
我嘗試了一些方法以後,找到了一個解決方案:post

微信webview在頁面load的時候會加載一次webview,咱們就利用這個特性來實現動態src問題。

  1. 首先把要跳轉的連接信息設置成全局變量,要改變src的時候,先把要src以’?‘拆分爲連接和參數兩部分,存入全局函數,再調用onLoad就能夠實現webview刷新了。
  2. 頁面跳轉時,咱們也須要src的動態刷新,因此要把連接信息存入全局函數;頁面跳轉時,onShow函數會被調用,這時候再調用一次onLoad就能夠了。
data: {
    url: '',
    loaded: false
}
// 小程序js裏的onLoad函數能夠寫成這樣
onLoad: function () {
    this.setData({
      url: getApp().globalData.urlToken + '?' +  getApp().globalData.urlData
    })
},
changUrl: function () {
    getApp().globalData.urlToken = 'https://www.example.com'
    getApp().globalData.urlToken = 'a=1&b=2'
    // 直接調用onLoad,就會實現src的刷新
    this.onLoad()
},
onShow: function () {
    if (!this.data.loaded) {
      // 第一次不運行
      this.setData({
        loaded: true
      })
      return
    }
    // 直接調用onLoad,就會實現src的刷新
    this.onLoad()
  }

// wxml能夠寫成這樣
<web-view src="{{url}}"></web-view>

支付功能

webview裏面能夠經過jssdk來實現一些小程序功能,但不能直接調用小程序的支付功能,這時候咱們就須要轉變一下策略了:

  1. 在網頁裏引入微信jssdk
  2. 在網頁須要發起支付的地方,調用跳轉頁面的接口,控制小程序跳轉到小程序的支付頁面(這個要在小程序裏單獨寫的),跳轉的時候,須要把訂單的一些信息都拼接到連接裏,訂單信息由後臺返回,須要經過微信支付系統的統一下單接口,具體參看支付文檔。
  3. 跳轉到小程序支付頁面後,由小程序頁面發起支付,支付完成後跳轉回webview頁面,經過以前設置的動態src,控制webview跳轉到特定的頁面。
// 網頁引入jssdk

// 網頁發起支付
wx.miniProgram.navigateTo({
    // payData由後臺返回,主要是須要統一下單平臺的prepay_id
    url: '../pay/index?data=' + encodeURIComponent(JSON.stringify(payData))
})
// 微信支付頁面
onLoad: function (option) {
    let page = this
    try {
      let data = JSON.parse(option.data)
      if (!data || !data.prepay_id) {
        console.error('支付參數錯誤,請稍後重試', data)
      }
      wx.requestPayment({
        timeStamp: '' + data.timestamp,
        nonceStr: data.nonceStr,
        package: 'prepay_id=' + data.prepay_id,
        paySign: data.paySign,
        signType: data.signType,
        success: function (res) {
          getApp().globalData.urlToken = `paySuccess.html`
          // 支付成功
          getApp().globalData.urlData = 'data=paySuccessData'
          wx.navigateTo({
            url: '/page/home/index',
          })
        },
        fail: function (res) {
          getApp().globalData.urlToken = `payError.html`
          // 支付失敗
          getApp().globalData.urlData = 'data=payErrorData'
          wx.navigateTo({
            url: '/page/home/index',
          })
        },
        complete: function (res) {
        }
      })
    } catch (e) {
      console.error('支付錯誤', e)
    }
  }

分享功能

小程序直接分享的webview所在的頁面,若是須要加上頁面參數,那咱們就須要處理一下了。

  1. webview內是不能直接發起分享的,須要先用wx.miniProgram.postMessage接口,把須要分享的信息,推送給小程序;推送給小程序的信息不是實時處理的,而是用戶點擊了分享按鈕以後,小程序纔回去讀取的,這就要求每一個須要分享的頁面再進入的時候就發起wx.miniProgram.postMessage推送分享信息給小程序。
  2. 小程序頁面經過bindmessage綁定的函數讀取post信息,分享的信息會是一個列表,咱們取最後一個分享就好,把分享信息處理好,存到data裏面以便下一步onShareAppMessage調用。
  3. 用戶點擊分享時,會觸發onShareAppMessage函數,在裏面設置好對應的分享信息就行了。
  4. onload函數有一個option參數的,能夠讀取頁面加載時url裏帶的參數,這時要對原先的onload函數進行改造,實現從option裏讀取連接信息。
// 網頁wx.miniProgram.postMessage
wx.miniProgram.postMessage({
  data: {
    link: shareInfo.link,
    title: shareInfo.title,
    imgUrl: shareInfo.imgUrl,
    desc: shareInfo.desc
  }
})
// 小程序index wxml設置
<web-view src="{{url}}" bindmessage="bindGetMsg"></web-view>
// 小程序index js
bindGetMsg: function (e) {
    if (!e.detail) {
      return
    }
    let list = e.detail.data
    if (!list || list.length === 0) {
      return
    }
    let info = list[list.length - 1]
    if (!info.link) {
      console.error('分享信息錯誤', list)
      return
    }
    let tokens = info.link.split('?')
    this.setData({
      shareInfo: {
        title: info.title,
        imageUrl: info.imgUrl,
        path: `/page/index/index?urlData=${encodeURIComponent(tokens[1])}&urlToken=${tokens[0]}`
      }
    })
},
onShareAppMessage: function (res) {
    if (res.from === 'button') {
      // 來自頁面內轉發按鈕
      console.log(res.target)
    }
    let that = this
    return {
      title: that.data.shareInfo.title,
      path: that.data.shareInfo.path,
      imageUrl: that.data.shareInfo.imageUrl,
      success: function (res) {
        // 轉發成功
      },
      fail: function (res) {
        // 轉發失敗
      }
    }
},
onLoad: function (option) {
    if (option.urlToken) {
      getApp().globalData.urlToken = option.urlToken
    }
    if (option.urlData) {
      getApp().globalData.urlData = option.urlData
    }
    this.setData({
      url: getApp().globalData.urlToken + '?' +  getApp().globalData.urlData
    })
},

掃描普通二維碼跳轉特定頁面

除了分享功能以外,小程序還能夠經過配置,實現掃描普通二維碼跳轉特定頁面的功能。

如下是微信對此功能的介紹

爲了方便小程序開發者更便捷地推廣小程序,兼容線下已有的二維碼,微信公衆平臺開放掃描普通連接二維碼跳轉小程序能力。
功能介紹
普通連接二維碼,是指開發者使用工具對網頁連接進行編碼後生成的二維碼。
線下商戶可不需更換線下二維碼,在小程序後臺完成配置後,便可在用戶掃描普通連接二維碼時打開小程序,使用小程序的功能。
對於普通連接二維碼,目前支持使用微信「掃一掃」或微信內長按識別二維碼跳轉小程序.

二維碼規則
根據二維碼跳轉規則,開發者須要填寫須要跳轉小程序的二維碼規則。要求以下:

  1. 二維碼規則的域名須經過ICP備案的驗證。
  2. 支持http、https、ftp開頭的連接(如:http://wx.qq.com、https://wx.qq.com/mp/、https://wx.qq.com/mp?id=123)。
  3. 一個小程序賬號可配置很少於10個二維碼前綴規則。

前綴佔用規則

開發者可選擇是否佔用符合二維碼匹配規則的全部子規則。如選擇佔用,則其餘賬號不可申請使用知足該前綴匹配規則的其餘子規則。

如:若開發者A配置二維碼規則:https://wx.qq.com/mp?id=123,並選擇「佔用全部子規則「,其餘開發者將不能夠配置知足前綴匹配的子規則如https://wx.qq.com/mp?id=1234

我推薦的方式
webview實現方式

  1. 設置跳轉功能小程序後臺就能夠設置,連接是分爲四部分,路https://www.example.com/wxmin...

    https://www.example.com 域名
    /wxmini/ 小程序前置規則,須要在服務器上建一個文件夾,而且把驗證文件放在文件夾線
    home.html 須要跳轉的網頁頁面
    a=1 跳轉頁面的參數
  2. 對onload函數再進行處理,實現普通二維碼跳轉。
// 對index onLoad在進行處理
onLoad: function (option) {
    this.resetOption(option)
    if (option.urlToken) {
      getApp().globalData.urlToken = option.urlToken
    }
    if (option.urlData) {
      getApp().globalData.urlData = option.urlData
    }
    this.setData({
      url: getApp().globalData.urlToken + '?' +  getApp().globalData.urlData
    })
},
resetOption: function (option) {
    if (!option) {
      return
    }
    if (option.q) {
      option.q = decodeURIComponent(option.q)
      if (option.q.indexOf('https://www.example.com/wxmini/') == -1) {
        return
      }
      let tmp = option.q.replace('/wxmini', '')
      let tmps = tmp.split('?')
      option.urlToken = tmps[0]
      option.urlData = tmps[1]
    } else {
      option.urlData = decodeURIComponent(option.urlData)
    }
}

返回按鈕缺失問題

若是web頁面是在第一個頁面的話,這時候會有一個問題,小程序的返回按鈕就沒有了,webview沒法使用微信的返回按鈕了,這時候只要在webview頁面前多加一個跳轉頁面就行了(第一個頁面也能夠設置成獲取用戶權限的頁面,不過我感受這樣體驗很差,也不是全部頁面都要用戶獲取了權限纔可使用)

最終的頁面層級
"pages": [
    "page/index/index", // 首頁,處理onload裏的option內容,爲了返回按鈕設置的
    "page/home/index", // webview所在的頁面
    "page/auth/index", // 獲取用戶權限的頁面
    "page/pay/index", // 支付頁面
    "page/error/index" // 錯誤信息頁面
  ],

參考連接

  1. webview文檔
  2. 小程序unionid介紹
  3. unionid獲取方式
相關文章
相關標籤/搜索