1. 程式人生 > >android jsbridge實現原理簡述

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簡單介紹就到這裡。