Posts JSBridge
Post
Cancel

JSBridge

JSBridge 其实在职业生涯中已经多次用过了,例如微信的 WeiXinJSBridge(JSSDK)、RN 的 window.postMessage,但让我自己描述这一过程所用的语句还非常“外行”,现在系统整理一下。

原文地址:https://juejin.im/post/5abca877f265da238155b6bc

原理

  • JSBridge 调用可以看作一次 RPC(remote procedure call,远程过程调用)。前端是 RPC 的客户端,Native 是 RPC 的服务端
  • 简单来说就是各种 Web 页面可以通过 Bridge 来调用应用的一些原生功能。主要就是给 JS 提供能调用 Native 功能的接口,让前端部分可以使用地理位置、摄像头或者支付等 Native 功能

双向通信

  • JS 向 Native 发送调用指令,通知 Native 当前 JS 状态
  • Native 向 JS 回溯调用结果(callback),消息推送,通知 JS 当前 Native 状态

JSBridge 调用

JS 调用 Native

注入 API

安卓和 iOS 编写各自的代码,将 api 注入到 webview 的 window 下面,前端进行调用。

1
window.webkit.messageHandlers.nativeBridge.postMessage(message);

拦截 URL SCHEME

前端直接 iframe.srclocation.href,需要提前跟 Native 进行协商。但存在两个问题:

  • url 长度缺陷
  • location.href 连续调用 Native 会导致一些调用丢失

Native 调用 JS

Native 直接执行 JS 代码,因此方法必须挂在 window 下面,否则 Native 没办法拿到方法

JSBridge 实现

JSBridge 接口主要功能有两个

  • 给 Native 发消息
  • 被 Native 调用

同时要实现给 Native 发消息后的【回调】,大概的 window.JSBridge 长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(function () {
  var id = 0,
    callbacks = {},
    registerFuncs = {};

  window.JSBridge = {
    // 调用 Native
    invoke: function (bridgeName, callback, data) {
      // 判断环境,获取不同的 nativeBridge
      var thisId = id++; // 获取唯一 id
      callbacks[thisId] = callback; // 存储 Callback
      nativeBridge.postMessage({
        bridgeName: bridgeName,
        data: data || {},
        callbackId: thisId, // 传到 Native 端
      });
    },
    receiveMessage: function (msg) {
      var bridgeName = msg.bridgeName,
        data = msg.data || {},
        callbackId = msg.callbackId, // Native 将 callbackId 原封不动传回
        responstId = msg.responstId;
      // 具体逻辑
      // bridgeName 和 callbackId 不会同时存在
      if (callbackId) {
        if (callbacks[callbackId]) {
          // 找到相应句柄
          callbacks[callbackId](msg.data); // 执行调用
        }
      } else if (bridgeName) {
        if (registerFuncs[bridgeName]) {
          // 通过 bridgeName 找到句柄
          var ret = {},
            flag = false;
          registerFuncs[bridgeName].forEach((callback) => {
            callback(data, function (r) {
              flag = true;
              ret = Object.assign(ret, r);
            });
          });
          if (flag) {
            nativeBridge.postMessage({
              // 回调 Native
              responstId: responstId,
              ret: ret,
            });
          }
        }
      }
    },
    register: function (bridgeName, callback) {
      if (!registerFuncs[bridgeName]) {
        registerFuncs[bridgeName] = [];
      }
      registerFuncs[bridgeName].push(callback); // 存储回调
    },
  };
})();
This post is licensed under CC BY 4.0 by the author.
Trending Tags
Contents

Trending Tags