android jsbridge實現原理簡述
假如生活欺騙了你,假如工作到處不順,請放鬆心態,提升自己,終有一天你會適應,然後。。。。。。。。。。。。。。。
本篇是面試小問題專欄的開篇文章,由於是面試小問題的解答,所以所有的文章都會力求把問題說明白的同時精簡字數,可能有理解不到位的地方後續會慢慢完善。
h5可以作為移動端跨平臺的一種方式,其他方式還有rnjs,flutter,weekx等,android或者ios為了實現和js的互動都提供了原生方法,但都存在一定的問題,這時jsbridge就誕生了。
android原生和js互動方式,呼叫js,loadurl通用,evaluateJavascript支援回撥但都涉及版本問題,js呼叫原生不同版本又設定到安全問題,雖然新版利用@JavascriptInterface 解決了安全問題但現實中依然有很多低版本。
jsbridge 優點說明:
1 統一android ,ios兩邊的呼叫方式,使繫結和呼叫函式介面統一,
2 完美解決安全性問題和回撥函式問題。
原理說明:
互動通道:
要實現原生和js互動首先需要一條雙方互動的通道,一般的jsbridge都是利用攔截prompt函式,webView端攔截了js端傳送的prompt函式,可以獲取上面的文字。原生執行js還是利用原來的loadurl。
重寫webView和 WebChromeClient,攔截prompt。
public static class WebChromeClientEx extends WebChromeClient { public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); } public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { Logger.d("JsBridge","onJsPrompt: " + message); try { //根據協議進行解析 JSONObject jsonObject = new JSONObject(message); if (JavascriptBridge.matchBridgeProtocol(jsonObject)) { result.confirm("prompt ok"); JavascriptBridge.onGetDataFromJs(view, jsonObject); } else { result.confirm("data does not match bridge protocol"); } } catch (Exception e) { e.printStackTrace(); result.confirm("exception"); } return true; } public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { if (view instanceof BaseWebView) { SimpleToastHelper.showShortToast(view.getContext(), message); } result.confirm(); return true; } public boolean onJsAlert(WebView view, String url, String message, JsResult result) { if (view instanceof BaseWebView) { SimpleToastHelper.showShortToast(view.getContext(), message); } result.confirm(); return true; } }
定義協議:
js呼叫原生,會通過呼叫prompt函式,webView獲取到prompt傳遞的文字(協議),根據自定義協議解析文字,執行特定原生函式。
js端如何呼叫原生的函式和回撥如何處理:
native(原生)的函式A會被js呼叫,首先A和實現會被儲存到本地的map中,然後native端回撥用js端寫好的註冊函式,在對應的js端生成一個代表原生函式A的js函式B(其實兩者之間沒有必然聯絡,不想系統提供的js呼叫native的方式,沒有註冊物件,這樣就保證了安全性),然後js呼叫想呼叫原生A函式時,就呼叫js函式B,利用prompt把呼叫原生A的協議傳過去,onjsprompt攔截協議,呼叫本地A函式。
所以jsbridge都會提供H5端註冊程式碼用於生成js的javascriptBridge物件,類似
(function () { if (window.bridge) { return; }
window.bridge = {}; var messages = {}; var call_id = 0;
native函式需要呼叫register函式,在h5端生成對應的函式
bridge.register = function (name) { if (this[name]) { return; } this[name] = function (params, callback) { invokeNative(name, params, callback); }; };
bridge.obtain = function (id) { return JSON.stringify(messages[id].params); };
bridge.callback = function (id, data) { var message = messages[id]; if (!message) { return; }
if (message.callback) { message.callback(JSON.parse(data)); } delete messages[id]; };
最終實現呼叫原生的方法 prompt
function invokeNative (name, params, callback) { call_id ++; messages[call_id] = {'params' : params, 'callback' : callback};
if (navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1) { prompt(JSON.stringify({'cmd':name, 'id':call_id, 'params':params}), ''); } else { var iframe = document.createElement('iframe'); iframe.src = 'bridge://invoke.native.method?handler=' + name + '&id=' + call_id; iframe.style.display = 'none'; document.documentElement.appendChild(iframe); setTimeout(function () { document.documentElement.removeChild(iframe); }, 0); } } })();
原生呼叫js如何實現回撥:
可以Native根據協議生成js物件,webView載入網頁時將本地js注入到網頁中,原生呼叫注入js中的函式,js端接收呼叫首先呼叫js函式,然後根據協議呼叫原生端的對調函式。
jsbridge簡單介紹就到這裡。