Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSBridge 原理以及各种方式的优缺点 #17

Open
Yuanfang-fe opened this issue Apr 21, 2021 · 0 comments
Open

JSBridge 原理以及各种方式的优缺点 #17

Yuanfang-fe opened this issue Apr 21, 2021 · 0 comments

Comments

@Yuanfang-fe
Copy link
Owner

Yuanfang-fe commented Apr 21, 2021

在开发 web App 的时候,我们会用 JSBridge 来调用 Native 的一些功能,作为一名前端开发,JSBridge 实现这块不一定是我们开发的,但也要对 JSBridge 实现原理做到了解。

JS 调用 Native

1. 拦截 Url Schema(假请求)

2. 拦截 prompt alert confirm

3. 注入 JS 上下文

  • 拦截 Url Schema(假请求)

h5 和 native 约定一个通信协议,例如 jsbridge, 同时约定调用 native 的方法名作为域名,以及带上参数 和 接收方法执行结果的 js 方法名 cbName,例如

"jsbridge://openScan?{"data": {"scanType": "qrCode"}, "cbName": "handleScanResult"}"

优点:

因为它 支持 iOS6,所以为了实现兼容很多方案会使用这种方式。

缺点:

  1. 连续发送时消息丢失
window.location.href = "jsbridge://callNativeNslog?{"data": "111", "cbName": ""}";
window.location.href = "jsbridge://callNativeNslog?{"data": "222", "cbName": ""}";

js 此时的诉求是在同一个运行逻辑内,快速的连续发送出 2 个通信请求,用客户端本身 IDE 的 log,按顺序打印 111,222,那么实际结果是 222 的通信消息根本收不到,直接会被系统抛弃丢掉。

原因:因为 h5 的请求归根结底是一种模拟跳转,跳转这件事情上 webview 会有限制,当 h5 连续发送多条跳转的时候,webview 会直接过滤掉后发的跳转请求,因此第二个消息根本收不到。
2. URL 长度限制
如果需要传输的数据较长,例如方法参数很多时,由于 URL 长度限制,会丢失部分数据。
3. 耗时长
创建请求,需要一定的耗时,比注入 API 的方式调用同样的功能,耗时会较长。
4. web 环境报错
在浏览器环境下,会跳转到不存在的页面

  • 拦截 prompt alert confirm

因为 alert confirm 比较常用,所以一般通过 prompt 进行通信。

约定的传输数据的组合方式以及 js 端封装方法的可以类似上面的 拦截 URL Schema 提到的方式。

function callNative(methodName, arg, cb) {
    ...

    const url = 'jsbridge://' + method + '?' + JSON.stringify(args);

    prompt(url);
}

native 会拦截 h5 发出的 prompt,当检测到协议为 jsbridge 而非普通的 http/https/file 等协议时,会拦截该请求,解析出 URL 中的 methodName、arg、 cbName,执行该方法并调用 js 回调函数。

优点:

没发现

缺点:

  1. iOS 的 UIWebView 不支持该方式(WKWebView 支持)
  2. 浏览器中,如果有地方需要用到 prompt 就会有副作用
  • 注入 JS 上下文

即由 native 将实例对象通过 webview 提供的方法注入到 js 全局上下文,js 可以通过调用 native 的实例方法来进行通信。

具体有安卓 webview 的 addJavascriptInterface,iOS UIWebview(iOS2+) 的 JSContext,iOS WKWebview(iOS8+)的 scriptMessageHandler。

h5 端可以在 js 调用 window._jsbridge 实例下面的 call 方法,传入的数据组合方式可以类似上面两种方式。具体代码如下:

window.callbackId = 0;

function callNative(method, arg, cb) {
  let args = {
    data: arg === undefined ? null : JSON.stringify(arg)
  };

  if (typeof cb === 'function') {
    const cbName = 'CALLBACK' + window.callbackId++;
    window[cbName] = cb;
    args['cbName'] = cbName;
  }

  if (window._jsbridge) {
    window._jsbridge.call(method, JSON.stringify(args));
  }
}

优点:

官方提供,方便简捷

缺点:

  1. Native 注入的方法和时机都受限,JS 调用 Native 之前需要先判断 JSBridge 是否注入成功

  2. 在安卓 4.2 以下有安全漏洞,在 4.2 之前,Android 注入 JavaScript 对象的接口是 addJavascriptInterface,但是这个接口有漏洞,可以被不法分子利用,危害用户的安全,因此在 4.2 中引入新的接口 @JavascriptInterface(上面代码中使用的)来替代这个接口,解决安全问题。

Native 调用 JS

1. loadUrl

2. evaluateJavascript

  • loadUrl

Native 调用 JS 比较简单,只要 H5 将 JS 方法暴露在 Window 上给 Native 调用即可。

mWebview.loadUrl("javascript: func()");
  • evaluateJavascript

mWebview.evaluateJavascript("javascript: func()", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
        return;
    }
});
方式 优点 缺点
loadUrl 兼容性好 1. 会刷新页面 2. 无法获取 js 方法执行结果
evaluateJavascript 1. 性能好 2. 可获取 js 执行后的返回值 仅在安卓 4.4 以上可用

参考:
https://segmentfault.com/a/1190000025182935
https://segmentfault.com/a/1190000021818496
https://juejin.cn/post/6844903936248250375#heading-2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant