IOS微信上Vue單頁面應用JSSDK簽名失敗解決方案

背景

手機型號:javascript

型號:iphone 7 / iphone xs max
版本:ios 10.3.1 / ios 12.1
微信版本:WeChat 6.7.3

問題還原:vue

Vue應用(vue-router)上使用history模式,在某個頁面內調用微信JSSDK相關API,如掃碼、分享等,使用當前頁面URL總會出現簽名錯誤(invalid signature),致使API調用失敗。

問題根源

Vue-Router進行路由切換的時候,老是會操做瀏覽器的歷史記錄,從而響應頁面URL變化。java

在JSSDK文檔頁面有這麼一句話:ios

同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復

但根據屢次測試狀況來看,狀況剛好相反,在Android下直接使用 window.location.href 得出的URL進行簽名是徹底沒問題(可能已升級至Android6.2以上版本),在IOS上就不行了。web

這是由於在IOS上,不管路由切換到哪一個頁面,實際真正有效的的簽名URL是【第一次進入應用時的URL】vue-router

好比進入應用首頁是: https://m.app.com,須要使用JSSDK的頁面A是:https://m.app.com/product1/123,不管從首頁進入到A頁面以前,中間跳轉過多少次路由,最終簽名有效的URL仍是首頁URL。vuex

解決方案

方案一

直接粗暴處理方式:瀏覽器

在進入須要使用JSSDK頁面(B)的前一個頁面(A),即 A > B,直接使用 window.location.hrefwindow.open 打開B頁面,此時由於B頁面是直接刷新方式進入,因此當前B頁面URL不管IOS或Android都是能夠直接拿來簽名的。緩存

這種方式處理缺點也很明顯,如頁面刷新抖動太厲害不夠平滑過渡,再好比B頁面須要從vuex中取出緩存信息,若是這些緩存信息不是經過vuex保存在localstorage的話,取出來的確定都是空的。微信

方案二

思路:既然IOS僅可以使用第一次進入應用的URL來簽名,那麼在vuex上緩存一個微信簽名URL,IOS保存第一次進入應用的URL,Android則緩存爲每一個頁面的URL。簽名時,直接從緩存拿出簽名URL來處理。

// 全局判斷是否IOS方法
function isIos(){
  const u = navigator.userAgent;
  return u.indexOf("iPhone") > -1 || u.indexOf("Mac OS") > -1;
}

1. 定義vuex緩存

...

{
  state: {
    wechatSignUrl: ""
  },
  
  mutations: {
    setWechatSignUrl(state, wxSignUrl) {
      // 關鍵點
      // IOS僅記錄第一次進入頁面時的URL
      // IOS微信切換路由實際URL不變,只能使用第一進入頁面的URL進行簽名
      if (isIos() && state.wxSignUrl !== '') {
        return;
      }
      state.wxSignUrl = wxSignUrl;
    }
  },
  
  getters: {
    getWechatSignUrl: (state) => state.wxSignUrl
  }
}

...

關鍵點在於設置更新微信簽名URL判斷的地方:首次進入應用頁面的時候確定會觸發更新,如果IOS且簽名URL已經設置過了,那麼就不須要更新設置了,只要不退出或刷新應用,緩存永遠都會是首次進入頁面URL。

2. 路由守衛內觸發更新簽名URL

import store form "@/stores"

// 獲取真實有效微信簽名URL
function getWechatSignUrl(to){
    if(isIos()) {
      return window.location.href;
    } else {
      // 此處$appHost須要自行處理
      return $appHost + to.fullPath
    }
}

...
$router.beforeEach((to, from, next) => {
    store.commit("setWechatSignUrl", getWechatSignUrl(to));    
})
...

在路由守衛內更新簽名URL,保證IOS是使用當前頁面URL,Android是使用目標路由完整地址再加上域名

3. 使用簽名URL調用JSSDK API

在使用JSSDK API的頁面經過vuex取出緩存的微信簽名URL,而後進行簽名。

好比:

import store form "@/stores"

...
{
  methods: {
   initWechatShareConfig() {
     const that = this;
     const wxSignUrl = store.getters['getWechatSignUrl'];
     const wxShareConfigs = {
        // 微信分享配置
     }

     // 初始化微信分享
     $wechat.share(wxSignUrl, wxShareConfigs);
   }
  }
}
...
$wechat.share 是根據JSSDK文檔二次封裝的分享方法,內部是根據wxSignUrl先進行簽名,而後再調用分享API
相關文章
相關標籤/搜索