WebView與APP互動實戰
WebView與APP互動,即網頁通過JSBrige
呼叫APP的功能,APP也可以通過JSBrige
呼叫網頁提供的方法。最近剛好接觸到這一塊,記錄一下前端側的實際操作過程,這篇文章適合還沒接觸過這一塊的同學們,這裡不講原理,直接開始實戰的過程。
準備工作
與客戶端同學溝通好使用的JSBrige庫,我這裡使用的是下面這兩個庫:
iOS(1.1w+ Star):github.com/marcuswesti…
Android(6k+ Star):github.com/lzyzsd/JsBr…
Star數量比較高,使用的企業也比較多,所以還是比較可靠的,可以在它們的文件中示例程式碼。
注意: github上有很多這樣的庫,但最好配套使用,即iOS和Android注入的jsBrige名稱一致,我們前端使用時比較方便統一。
開發步驟
1. 統一封裝APP注入的JSBrige
ios和android注入的jsbrige可能會有些差異,所以在使用前我們需要抹平不同客戶端的差異。
如果app的同學使用了上面說的庫,安卓和iOS會在WebView中的window下注入一個WebViewJavascriptBridge
的物件,iOS有可能是注入WVJBCallbacks
的陣列,也有可能需要通過iframe
來注入。iOS的文件
中給出了一個相容的示例程式碼:
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下:
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呼叫時如:
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的互動其實就完成了,就是這麼簡單。
注意事項
-
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) 複製程式碼
這坨程式碼寫的很挫,讓我尷尬癌都犯了,有沒有熱心的小夥伴幫我優化下寫法[送花花]。
-
js呼叫安卓後
callback
回撥不成功,js收不到app返回的訊息
這個問題其實github上有issue ,這是安卓1.0.4版本沒有解決的問題,最新的程式碼已經解決了。 解決辦法是:安卓需要引入最新的master的程式碼,而不要使用1.0.4版本的程式碼。