JSBridge实现原理


JSBridge 是广为流行的Hybrid 开发中JS和Native一种通信方式,简单的说,JSBridge就是定义Native和JS的通信,Native只通过一个固定的桥对象调用JS,JS也只通过固定的桥对象调用native

JSBridge的基本原理

h5
➡️ 通过某种方式触发一个url
➡️ native捕获到url,进行分析
➡️ 原生做处理
➡️ native 调用h5的JSBridge对象传递回调

使用JSBridge的原因

传统的情况下:js可以和native之间通过api注入的方式实现相互通信,但JSBridge的出现还有下面原因:

  • android4.2 以下,addJavaScriptInterface方式有安全漏洞
  • ios7以下,js无法调用native
  • url scheme交互方式是一套现有的成熟方案,可以兼容各种版本

实现JSBridge

实现一个JSBridge的方法:

  1. 设计出一个native与js交互的全局桥对象
  2. js调用native
  3. native得知api被调用
  4. 分析 url 参数和回调的格式
  5. native调用js
  6. h5中api方法的注册以及格式

具体和JS侧相关的是前两个部分

一、设计native和js交互的全局对象

  // 名称: JSBridge 挂在 window上的一个属性
  var JSBridge = window.JSBridge || (window.JSBridge = {});
  /**
    该对象有如下方法:
    registerHandler(String, Function) 注册本地 js 方法,注册后 native可通过 JSBridge调用,注册后会将方法注册到本地变量 messageHandles中
    
    sendHandler(String, JSON, Function) h5 调用原生开放的api,调用后实际上还是本地通过 url scheme触发,调用时会将回调 id 存放到本地变量responseCallbacks 中
    
    _handleMessageFromNative h5 调用native之后的回调通知
    参数为 {reposeId: 回调id, responseData: 回调数据}
    
  */
  
  var JSBridge = {
    // 注册本地方法供原生调用
    registerHandler: function(method, cb) {
      // 会将cb 放入 messageHandlers里面,待原生调用
    },
    messageHandles: {}, // h5注册方法集合,供native通知后回调调用
    
    // h5 主动调用native,需生成唯一的callbackId
    sendHandler: function(mathod, data, succCb, errCb) {
      // 内部通过iframe src url scheme 向native发送请求
      // 并将对应的回调注册进 responseCallbacks
      // native 处理结束后将结果信息通知到h5 通过 _handleMessageFromNative
      // h5 拿到返回信息处理 responseCallbacks 里对应的回调
    },
    responseCallbacks: {}, // 回调集合
    
    // native 通知 h5
    _handleMessageFromNative: function(message) {
       // 解析 message,然后根据通知类型执行 messageHandles 或 responseCallbacks里的回调
    }
  }
  
  /**
      注意:
      1. native 调用_handleMessageFromNative通知h5,参数为 json 字符串
      
      2. native 主动调用h5方法时 {methodName: api名, data, callbackId}
          methodName: 开放api的名称
          data: 原生处理后传递给 h5 参数
        需要把回调函数的值 return 出去,供native拿到,
        
        或者再发一个 bridge 回去,方法名是 methodNameSuccess,或者严禁掉,方法名为native生产的callbackId
  */
  如:
  bridge.register("hupu.ui.datatabupdate", (name) => {
    if(name) {
      // 再发一个bridge通知原生tab更新成功,,,method 可以为native生成的 callbackId
      bridge.send('hupu.ui.datatabsuccess', {}) 
    }
  });

二、js调用native

方式:通过原生的setHandler方法调用原生

// sendHandler 执行步骤
1. 判断是否有回调函数,如果有,生成一个回调函数id,并将id,和对应的回调添加放入回调函数集合 responseCallbacks 中

2. 通过特定的参数转换方法,将传入的数据,方法名一起拼接成一个 url scheme,如下:
 var param = {
   method: 'methodName',
   data: {xx: 'xx'},
   success: 'successId',
   error: 'errorId'
 }
 // 变成字符串并编码
 var url = scheme://ecape(JSON.stringify(param))

3. 使用内部创建好的iframe来触发scheme(location.href = 可能会造成跳转问题)
 ...创建iframe
 var iframe = document.createElment('iframe');
 iframe.src = url;
 document.head.appendChild(iframe);
 setTimeout(() => document.head.removeChild('iframe'), 200)


Author: Casey Lu
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Casey Lu !
评论
 Previous
小程序原理及RN与Flutter的对比 小程序原理及RN与Flutter的对比
小程序 小程序的底层原理 小程序的呈现模式是 WebView + 原生组件,Hybrid 方式 双线程模式是小程序的最大特点 小程序的渲染层和逻辑层分别由 2 个线程管理:渲染层的界面使用了 WebView 进行渲染,逻辑层采用 JsCo
2020-08-27
Next 
轻量级开发的总结 轻量级开发的总结
随着日益增多的应用进入到我们的视野,追求轻量级开发逐渐成为了研发的趋势。 最常见的轻量级的代表便是小程序,可以在避开下载新应用的前提下,呈现在不同的端上。同样是无需下载,主打“一键直达”式的快应用也在去年便出现在人们视野之中。除了以上两者之
2020-08-25
  TOC