JSBridge的实现原理

3,615 阅读3分钟

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&param2=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<String>() {
    @Override
    publicvoidonReceiveValue(String value){

    }
});

参考:

jsbridge的原理

Hybrid 开发:JsBridge - Web 和客户端的桥

H5与Native交互之JSBridge技术