WebView與APP互動實戰記錄

fengxianqi發表於2019-01-29

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的互動其實就完成了,就是這麼簡單。

注意事項

  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)複製程式碼

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

  1. js呼叫安卓後callback回撥不成功,js收不到app返回的訊息

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

來源:https://juejin.im/post/5c4fc0726fb9a049dd80b046#comment

相關文章