什么是JSBridge
在 JavaScript 代码中提供调用 Native 功能的接口,让混合开发中的前端部分可以方便地使用 Native 的功能(例如:地址位置、摄像头)。
它的核心是构建 Native 和非 Native 间消息通信的通道,而且这个通信的通道是双向的。
JSBridge 的实现原理
JavaScript 是运行在一个单独的 JS Context 中(例如,WebView 的 Webkit 引擎、JSCore)。由于这些 Context 与 Native 原生运行环境的天然隔离,我们必须通过一定的方法来实现 Native 和 JS Context 的双向通信。主要包括:
- Native 调用 js 方法
- js 调用 Native 方法
Native调用js方法
Native => JS
iOS
1 | webview.stringByEvaluatingJavaScriptFromString("Math.random()") |
1 | [webView stringByEvaluatingJavaScriptFromString:@"Math.random();"]; |
Android1
2
3
4
5
6mWebView.evaluateJavascript("javascript: Math.random();", new ValueCallback() {
public void onReceiveValue(String value) {
//这里的value即为对应JS方法的返回值
}
});
JS => Native
对于 Webview 中发起的网络请求,Native 都有能力去捕获/截取/干预。所以 JSBridge 的核心就是设计一套uri方案,让 Native 可以识别,从而做出响应,执行对应的操作。
js调用Native方法
JavaScript 调用 Native 的方式主要有两种,可以通过 注入API 和 拦截URL SCHEME 的方式来实现。
注入API
注入 API 方式的主要原理是,通过 WebView 提供的接口,向 JavaScript 的 Context(window)中注入对象或者方法,让 JavaScript 调用时,直接执行相应的 Native 代码逻辑,达到 JavaScript 调用 Native 的目的。
对于 iOS 的 UIWebView,实例如下:
1 | JSContext *context = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; |
对于 iOS 的 WKWebView 可以用以下方式:
1 | @interface WKWebVIewVC ()<WKScriptMessageHandler> |
Android 可以通过 addJavascriptInterface
方法 将 Native 的一个对象注入到页面中,供JS调用。
1 | /** |
拦截 URI SCHEME
URI SCHEME 是一种 uri 的链接,是为了方便app直接互相调用设计的,形式和普通的 uri 近似,主要区别是 protocol 和 host 是自定义的。
拦截 URI SCHEME 的主要流程是:Web 端通过某种方式(例如 iframe.src)发送 URI Scheme 请求,之后 Native 拦截到请求并根据 URI SCHEME(包括所带的参数)进行相关操作。
在时间过程中,这种方式有一定的缺陷:
- 使用 iframe.src 发送 URL SCHEME 会有 url 长度的隐患。
- 创建请求,需要一定的耗时,比注入 API 的方式调用同样的功能,耗时会较长。
JSBridge 接口实现
从上面的剖析中,可以得知,JSBridge 的接口主要功能有两个:调用 Native(给 Native 发消息) 和 接被 Native 调用(接收 Native 消息)。因此,JSBridge 可以设计如下:
1 | window.JSBridge = { |
对于JSBridge的回调,和jsonp类似,url 参数里会有 callback 参数,其值是 当前页面唯一 的,而同时以此参数值为 key 将回调函数存到 window 上,随后,服务器返回 script 中,也会以此参数值作为句柄,调用相应的回调函数。