HybridAPP 通過JSBridge提供調用Native功能的接口,讓混合開發中的『前端部分』可以友善地使用位址位置、攝像頭甚至支付等 Native 功能。它的核心是 建構 Native 和非 Native 間消息通信的通道,而且是 雙向通信的通道。
JSBridge的實作原理
js調用Native
注入api/對象
原理:通過WebView提供的接口向js的context(window)注入一個對象或者方法,js調用時,直接執行對應的Native代碼邏輯
iOS
UIWebVIew(iOS2+)和WKWebView(iOS8+)的調用方式有所差別
//假設ios用戶端約定方法名為nativeBridge
//UIWebView
window.nativeBridge(message);
//WKWebView
window.webkit.messageHandlers.nativeBridge.postMessage(message);
複制代碼
Android
原理:通過WebView提供的addJavascriptInterface方法給浏覽器window注入一個命名空間,然後給Web增加一些可以操作Java的反射。
// addJavascriptInterface
mWebView.addJavascriptInterface(new Class(), 'android');
//@JavascriptInterface
public class Class(){
@JavascriptInterface
public void method(){
}
}
// js 代碼
window.android.method();
複制代碼
在 4.2 之前,Android 注入 JavaScript 對象的接口是 addJavascriptInterface,但是這個接口有漏洞,可以被不法分子利用,危害使用者的安全,是以在 4.2 中引入新的接口 @JavascriptInterface(上面代碼中使用的)來替代這個接口,解決安全問題。
攔截URL scheme
iOS
在UIWebView内發起的所有網絡請求,都可以通過delegate函數在Native層得到通知。這樣,我們就可以在UIWebView内發起一個自定義的網絡請求,通常是這樣的格式:jsbridge://methodName?param1=value1¶m2=value2
于是Native 攔截的請求中,我們隻要發現是jsbridge://開頭的位址,就不進行内容的加載,轉而執行相應的調用邏輯。
缺點:
使用 iframe.src 發送 URL SCHEME 會有 url 長度的隐患。
建立請求,需要一定的耗時,比注入 API 的方式調用同樣的功能,耗時會較長。
即使URL scheme連結有以上缺點,但因為它 支援 iOS6,是以為了實作相容很多方案會使用這種方式
Android邏輯與iOS相似
改寫浏覽器原有對象
使用prompt,console.log,alert方式,在android webview這一層可以重寫這些方法。
一般常使用prompt,因為這個在js裡使用的不多,用來和native通訊副作用比較少。
prompt簡單舉例說明,Web頁面通過調用prompt()方法,安卓用戶端通過監聽onJsPrompt事件,攔截傳入的參數,如果參數符合一定協定規範,那麼就解析參數,扔給後續的Java去處理。這種協定規範,最好是跟iOS的協定規範一樣,這樣跨端調起協定是一緻的,但具體實作不一樣而已。比如:hybrid://action?arg1=1這樣的協定,而其他格式的prompt參數,是不會監聽的,即除了hybrid://action?arg1=1這樣的規範協定,prompt還是原來的prompt。
Native調用JS
Native調用js實際就是執行拼接js字元串,從外部調用對應方法,傳回js執行結果。是以js方法必須放在全局的Window上
iOS
是通過UIWebView元件的stringByEvaluatingJavaScriptFromString方法來實作的,該方法傳回js腳本的執行結果。
//UIWebView
result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
//WKWebView
[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
複制代碼
Android
在 Kitkat(4.4)之前是使用webview的loadUrl進行調用的:
webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");
複制代碼
而 Kitkat 之後的版本,也可以用 evaluateJavascript 方法實作:
webView.evaluateJavascript(javaScriptString, new ValueCallback() {
@Override
publicvoidonReceiveValue(String value){
}
});
複制代碼
參考: