WebView與APP交互實戰記錄

WebView與APP交互

WebView與APP交互,即網頁經過JSBrige調用APP的功能,APP也能夠經過JSBrige調用網頁提供的方法。最近恰好接觸到這一塊,記錄一下前端側的實際操做過程,這篇文章適合還沒接觸過這一塊的同窗們,這裏不講原理,直接開始實戰的過程。javascript

準備工做

與客戶端同窗溝通好使用的JSBrige庫,我這裏使用的是下面這兩個庫:前端

iOS(1.1w+ Star): https://github.com/marcuswestin/WebViewJavascriptBridgejava

Android(6k+ Star): https://github.com/lzyzsd/JsBridgeandroid

Star數量比較高,使用的企業也比較多,因此仍是比較可靠的,能夠在它們的文檔中示例代碼。ios

注意: github上有不少這樣的庫,但最好配套使用,即iOS和Android注入的jsBrige名稱一致,咱們前端使用時比較方便統一。

開發步驟

1. 統一封裝APP注入的JSBrige

ios和android注入的jsbrige可能會有些差別,因此在使用前咱們須要抹平不一樣客戶端的差別。
若是app的同窗使用了上面說的庫,安卓和iOS會在WebView中的window下注入一個WebViewJavascriptBridge的對象,iOS有多是注入WVJBCallbacks的數組,也有可能須要經過iframe來注入。iOS的文檔中給出了一個兼容的示例代碼:git

function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}

咱們能夠直接使用上面的代碼,爲了使用方便,在頁面onload後,咱們將這個函數掛在window下:github

window.onload = function () {
  function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
  }
  window.setupWebViewJavascriptBridge = setupWebViewJavascriptBridge
}

window.setupWebViewJavascriptBridge這個函數,就是咱們所說的JSBridge,即WebView與APP交互的橋樑。數組

2. JS調用APP的方法

APP端的同窗須要先用庫提供的方法在APP端實現一個方法,方法名好比:playMusic(musicId),能夠傳遞參數musicId,表示讓APP開始播放某一首音樂。js調用時如:app

window.setupWebViewJavascriptBridge(function (bridge) {
        bridge.callHandler('playMusic', { musicId: 1 }, function (data) {
          console.log('app觸發成功了,音樂正在播放。。。APP回調返回的數據:', data)
        })
      })

上面至關於向app發起了一個playMusic請求,app收到請求後,執行相關的動做,而後能夠callback,網頁能夠拿到回調並繼續作相關動做(須要的話)。函數

3. APP調JS提供的方法

一樣的道理,若想APP能調用JS提供的方法,JS中要先註冊這個方法,方法名好比stateChange(state),JS註冊方法:

window.setupWebViewJavascriptBridge(function (bridge) {
  bridge.registerHandler('stateChange', function (data, responseCallback) {
    console.log('收到APP請求stateChange事件,請求的數據是:', data)
    // 能夠返回給app一個回調
    responseCallback('朕已經收到APP愛卿的請求了,且退下!')
  })
})

到這裏,WebView與app的交互其實就完成了,就是這麼簡單。

注意事項

1. window.onload時就callHandler可能不成功

通常在Android中會出現這個問題,這是由於APP注入的WebViewJavascriptBridge還不存在,JS就調用其中的方法了,因此就會沒有效果。而Android的庫也給出了這個注意事項,因此得這樣寫:

window.onload = function () {
  function registerAppEvent () {
    window.setupWebViewJavascriptBridge(function (bridge) {
      bridge.registerHandler('stateChange', function (data, responseCallback) {
        console.log('收到APP請求,請求的數據是:', data)
        // 能夠返回給app一個回調
        responseCallback('朕已經收到APP愛卿的請求了,且退下!')
      })
    })
  }

  // 兼容寫法 
  if (window.WebViewJavascriptBridge) {
    registerAppEvent()
  } else {
    document.addEventListener(
        'WebViewJavascriptBridgeReady'
        , function() {
            registerAppEvent()
        },
        false
    )
  }
}

但這裏沒有考慮到iOS的狀況,在最新的iOS中WebViewJavascriptBridge多是不存在的,因此上面寫法registerAppEvent()在iOS可能沒法執行。爲了不屢次注入事件,我這裏用了setTimeout,兼容兩端的流程:

let isInitBridgeEvent = false // 做爲是否已註冊過事件的標記
  if (window.WebViewJavascriptBridge) {
    registerAppEvent()
    isInitBridgeEvent = true
  } else {
    document.addEventListener(
      'WebViewJavascriptBridgeReady',
      function () {
        registerAppEvent()
        isInitBridgeEvent = true
      },
      false
    )
    // 若是還沒註冊則再註冊一次
    setTimeout(() => {
      if (!isInitBridgeEvent) {
        registerAppEvent()
        isInitBridgeEvent = true
      }
    }, 100)

這坨代碼寫的很挫,讓我尷尬癌都犯了,有沒有熱心的小夥伴幫我優化下寫法[送花花]。

2. js調用安卓後callback回調不成功,js收不到app返回的消息

這個問題其實github上有issue,這是安卓1.0.4版本沒有解決的問題,最新的代碼已經解決了。解決辦法是:安卓須要引入最新的master的代碼,而不要使用1.0.4版本的代碼。

相關文章
相關標籤/搜索