天天看點

jsbridge實作及原理_初探JSBridge

jsbridge實作及原理_初探JSBridge

有段時間沒寫文章了,最近在寫rax的時候,需要實作一個分享功能,對于前端而言隻需要調一下native(IOS和Android)提供的API就好了。雖然實作這個功能很簡單,但有沒有想過native是如何提供API給前端調用的呢,答案就是我們今天要聊的JSBridge,如果你寫過hybrid、react native、weex或rax,相信你或多或少聽過這個東西。即使沒有聽過也沒關系,下面會初步的介紹一下它。

JSBridge

現在開發移動端應用,供我們選擇的方案有很多, 比如native(IOS和Android)、 hybrid和react native等。其中hybrid、react native等方案對前端很友好,畢竟是用我們熟悉的JavaScript開發,但JavaScript無法直接調用native本身提供的能力,比如擷取相冊資訊。是以就需要通過一種方式将native能力提供給JavaScript,同時native也可能需要調用JavaScript的一些功能,而JSBridge就是JavaScript和native之間的橋梁,提供兩者互相調用的能力。

jsbridge實作及原理_初探JSBridge

實作原理

JSBridge的實作方式有很多,有通過C++實作的,也有通過native提供的webview實作的。這裡我們重點了解原理,通過native提供的webview實作比較簡單,另外相較于IOS,我對Android更熟悉一點,是以接下來将通過一個Android端的JSBridge來講解,這個代碼是我在GitHub上面找的,具體見:

lzyzsd/JsBridge​github.com

jsbridge實作及原理_初探JSBridge

native端注冊函數供JavaScript調用:

// 下面webview是一個自定義的WebView,繼承Android原生的WebView對象
webView.registerHandler("submitFromWeb", new BridgeHandler() {
     @Override
     public void handler(String data, CallBackFunction function) {
         Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
         function.onCallBack("submitFromWeb exe, response data from Java");
     }
 });
           

上面代碼是Android端注冊了一個名為submitFromWeb的函數供JavaScript端調用,其中handler函數是具體執行的内容,String類型的data是JavaScript端調用時傳過來的參數,CallBackFunction類型的function是用來将執行的結果回傳給JavaScript。

JavaScript調用native端提供的函數:

// WebViewJavascriptBridge是提前注入的一個全局變量用于javascript調用native提供的函數
WebViewJavascriptBridge.callHandler(
    'submitFromWeb',
    {'param': str},
    // 調用native函數成功後的回調函數
    function callback(responseData) {
        document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
    }
);
           

上面代碼是JavaScript通過提前注入的WebViewJavascriptBridge對象調用native端提供的submitFromWeb函數,傳遞的參數為{'param': str},調用結束後會回調callback函數。

jsbridge實作及原理_初探JSBridge

整個調用流程如上圖所示,Android端調用registerHandler,将submitForWeb函數儲存在函數池中。JavaScript調用callHandler函數,首先将回調函數callback儲存在回調函數池中,同時會生成“調用Message”,然後通過一定的方式将該Message傳遞給Android端;Android端根據傳過來的Message判斷調用什麼函數,并在函數池中尋找,找到了就執行,執行完之後會生成一個“響應Message”,該Message中包含回調函數的辨別和函數執行的結果;之後通過一定的方式将該Message傳遞給Javascript端,JavaScript端收到Message後,從回調函數池中找到回調函數并執行。

這裡需要了解2個點,JavaScript是如何将Message傳遞給Android端的,Android端是如何将Message傳遞給JavaScript的。

JavaScript将Message傳遞給Android端是通過WebviewClient中shouldOverrideUrlLoading來實作的,webview中iframe的src如果發生變化,就會調用該函數。首先将Message json化,将其放到iframe src屬性的url上(類似http中get請求),WebviewClient感受到iframe src發生變化,就會調用shouldOverrideUrlLoading函數,拿到url解析擷取Message。WebviewClient的shouldOverrideUrlLoading具體用法請見:https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)。

Android端将Message傳遞給JavaScript是通過webview.loadUrl('javascript:XXXX(args)')來實作的,其中XXX是JavaScript環境中的提前設定的一個方法,args表示需要傳遞的參數。這裡是不是很眼熟呀,沒錯,這裡的實作和jsonp是不是很像。

上面隻是簡單的介紹了JavaScript調用Android注冊的函數,相反Android也可以調用JavaScript注冊的函數,原理和上面類似,是以這裡就不再贅述。

總結

本文在沒有涉及代碼的情況化,粗略介紹了一下JSBridge的原理,忽略了很多技術細節,比如自定義的Webview是如何實作的;JavaScript端将Message傳遞給Android端詳細的url格式;Android端将Message傳遞給JavaScript端時調用的函數(提前注入的);JavaScript端是如何提前注入資訊的,比如WebViewJavascriptBridge這個對象。如果你想了解這些技術細節的話,可以去看一下源碼。

lzyzsd/JsBridge​github.com

jsbridge實作及原理_初探JSBridge

另外非常感謝您能夠看到最後,接下來我會寫幾篇關于React Fiber相關的文章,如果你對此有興趣的話,歡迎關注我;另外如果您發現文章中哪裡有不對的地方,也歡迎指出來,我好改正。