天天看點

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

衆所周知,app的一些功能可能會使用到H5開發,這就難免會遇到java與js的互相調用,像android利用WebViewJavascriptBridge實作js和java的互動,這裡主要介紹下JsBridge的原理和使用。

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

一、什麼是JSBridge

JSBridge主要是給JavaScript提供調用Native功能的接口,讓混合開發中的前端部分可以友善地使用Native的功能(例如:位址位置、攝像頭)。而且JSBridge的功能不止調用Native功能這麼簡單寬泛。

JSBridge是一座用JavaScript搭建起來的橋,一端是Web,一端是Native,是Native和Web之間的橋梁。我們搭建這座橋的目的也很簡單,讓Native可以調用Web的js代碼,讓Web可以“調用”原生的代碼。它的核心是建構Native和Web間消息通信的通道,而且這個通信的通道是雙向的。

雙向通信的通道:JS向Native發送消息:調用相關功能、通知Native目前JS的相關狀态等。Native向JS發送消息:回溯調用結果、消息推送、通知JS目前Native的狀态等。
           

H5與Native互動如下圖:

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

二、JSBridge的實作原理

JavaScript是運作在一個單獨的JS Context中(例如WebView的Webkit引擎、JSCore)。由于這些Context與原生運作環境的天然隔離,我們可以将這種情況與RPC(Remote Procedure Call,遠端過程調用)通信進行類比,将Native與JavaScript的每次互相調用看做一次RPC調用。

在JSBridge的設計中,可以把前端看做RPC的用戶端,把Native端看做RPC的伺服器端,進而JSBridge要實作的主要邏輯就出現了:通信調用(Native與JS通信)和句柄解析調用。

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

三、JSBridge的通信原理

1.JavaScript調用Native的方式

主要有兩種:注入API和攔截URL SCHEME

1.1 注入API

注入API方式的主要原理是,通過WebView提供的接口,向JavaScript的Context(window)中注入對象或者方法,讓JavaScript調用時,直接執行相應的Native代碼邏輯,達到JavaScript調用Native的目的。

iOS

UIWebVIew(iOS2+)和WKWebView(iOS8+)的調用方式有所差別

//假設ios用戶端約定方法名為nativeBridge//UIWebViewwindow.nativeBridge(message);//WKWebViewwindow.webkit.messageHandlers.nativeBridge.postMessage(message);
           

Android

原理:通過WebView提供的addJavascriptInterface方法給浏覽器window注入一個命名空間,然後給Web增加一些可以操作Java的反射。

//addJavascriptInterfacemWebView.addJavascriptInterface(new Class(), 'android');  //@JavascriptInterfacepublic class Class(){  @JavascriptInterface  public void method(){  }}//js 代碼window.android.method();
           

備注:在4.2之前,Android注入JavaScript對象的接口是addJavascriptInterface,但是這個接口有漏洞,可以被不法分子利用,危害使用者的安全,是以在4.2中引入新的接口@JavascriptInterface(上面代碼中使用的)來替代這個接口,解決安全問題。

1.2 攔截URL SCHEME

解釋一下URL SCHEME:URL SCHEME是一種類似于url的連結,是為了友善app直接互相調用設計的,形式和普通的url近似,主要差別是protocol和host一般是自定義的。

例如:esign://home/url?url=www.baidu.com,protocol是esign,host則是home。
           

攔截URL SCHEME 的主要流程是:Web端通過某種方式(例如iframe.src)發送URLScheme請求,之後Native攔截到請求并根據URL SCHEME(包括所帶的參數)進行相關操作。

在時間過程中,這種方式有一定的缺陷:

  • 使用iframe.src發送URLSCHEME會有url長度的隐患。
為什麼選擇iframe.src不選擇locaiton.href?因為如果通過location.href連續調用Native,很容易丢失一些調用。
           

建立請求,需要一定的耗時,比注入API的方式調用同樣的功能,耗時會較長。

是以:JavaScript調用Native推薦使用注入API的方式

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

2.Native調用JavaScript的方式

相比于JavaScript調用Native,Native調用JavaScript較為簡單,直接執行拼接好的JavaScript代碼即可。

從外部調用JavaScript中的方法,是以JavaScript的方法必須在全局的window上。

iOS

對于iOS的UIWebView,示例如下:

//UIWebViewresult = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
           

對于iOS的WKWebView,示例如下:

//WKWebView[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
           

Android

Android

在Kitkat(4.4)之前是使用webview的loadUrl進行調用的:

webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");
           

而Kitkat之後的版本,也可以用evaluateJavascript方法實作:

webView.evaluateJavascript(javaScriptString,new ValueCallback() {    @Override    publicvoidonReceiveValue(String value){    }});
           
jsbridge原理_前端和App開發者都要懂的JSBridge的原理

四、JSBridge 接口實作

從上面的剖析中,可以得知,JSBridge的接口主要功能有兩個:調用Native(給Native發消息)和接被Native調用(接收Native消息)。是以,JSBridge可以設計如下:

window.JSBridge = {    // 調用 Native    invoke: function(msg) {        // 判斷環境,擷取不同的 nativeBridge        nativeBridge.postMessage(msg);    },    receiveMessage: function(msg) {        // 處理 msg    }};
           

在上面部分中,提到過RPC中有一個非常重要的環節是句柄解析調用,這點在JSBridge中展現為句柄與功能對應關系。同時,我們将句柄抽象為橋名(BridgeName),最終演化為一個BridgeName對應一個Native功能或者一類Native消息。基于此點,JSBridge的實作可以優化為如下:

window.JSBridge = {    // 調用 Native    invoke: function(bridgeName, data) {        // 判斷環境,擷取不同的 nativeBridge        nativeBridge.postMessage({            bridgeName: bridgeName,            data: data || {}        });    },    receiveMessage: function(msg) {        var bridgeName = msg.bridgeName,            data = msg.data || {};        //具體邏輯    }};
           

終極提問:消息都是單向的,那麼調用Native功能時Callback怎麼實作的?

對于JSBridge的Callback,其實就是RPC架構的回調機制。當然也可以用更簡單的JSONP機制解釋:

當發送JSONP請求時,url參數裡會有callback參數,其值是目前頁面唯一的,而同時以此參數值為key将回調函數存到window上,随後,伺服器傳回script中,也會以此參數值作為句柄,調用相應的回調函數。
           

整體流程:

在Native端配合實作JSBridge的JavaScript調用Native邏輯也很簡單,主要的代碼邏輯是:接收到JavaScript消息=>解析參數,拿到bridgeName、data和callbackId=>根據bridgeName找到功能方法,以data為參數執行=>執行傳回值和callbackId一起回傳前端。

Native調用JavaScript也同樣簡單,直接自動生成一個唯一的ResponseId,并存儲句柄,然後和data一起發送給前端即可。

jsbridge原理_前端和App開發者都要懂的JSBridge的原理

五、JSBridge的總結

對于JSBridge的引用,常用有如下兩種方式,但各有利弊。

1.由Native端進行注入

注入方式和Native調用JavaScript類似,直接執行橋的全部代碼。

它的優點是:

橋的版本很容易與Native保持一緻,Native端不用對不同版本的JSBridge進行相容。

它的缺點是:

注入時機不确定,需要實作注入失敗後重試的機制,保證注入的成功率,同時JavaScript端在調用接口時,需要優先判斷JSBridge是否已經注入成功。

2.由JavaScript端引用

直接與JavaScript一起執行。

它的優點是:

JavaScript端可以确定JSBridge的存在,直接調用即可。

它的缺點是:

如果橋的實作方式有更改,JSBridge需要相容多版本的Native Bridge或者Native Bridge相容多版本的JSBridge。

至此,JSBridge的原理介紹完畢,歡迎大家轉發留言進行交流。