一篇文章了解 JsBridge

开发
近些年,移动端普及化越来越高,开发过程中选用 Native 还是 H5 一直是热门话题。Native 和 H5 都有着各自的优缺点,为了满足业务的需要,公司实际项目的开发过程中往往会融合两者进行 Hybrid 开发。Native 和 H5 分处两地,看起来无法联系,那么如何才能让双方协同实现功能呢?

                   [[345068]]

、jsbridge 定义

JSBridge 是一种 JS 实现的 Bridge,连接着桥两端的 Native 和 H5。它在 APP 内方便地让 Native 调用 JS,JS 调用 Native ,是双向通信的通道。JSBridge 主要提供了 JS 调用 Native 代码的能力,实现原生功能如查看本地相册、打开摄像头、指纹支付等。


二、JSBridge 用途

JSBridge 就像其名称中的『Bridge』的意义一样,是 Native 和非 Native 之间的桥梁,它的核心是 构建 Native 和非 Native 间消息通信的通道,而且是 双向通信的通道。

双向通信的通道:

1) JS 向 Native 发送消息: 调用相关功能、通知 Native 当前 JS 的相关状态等。

2) Native 向 JS 发送消息: 回溯调用结果、消息推送、通知 JS 当前 Native 的状态等。

H5与Native交互如下图: 

三、JSBridge 的实现原理

JavaScript 是运行在一个单独的 JS Context 中(例如,WebView 的 Webkit 引擎、JSCore)。由于这些 Context 与原生运行环境的天然隔离,我们可以将这种情况与 RPC(Remote Procedure Call,远程过程调用)通信进行类比,将 Native 与 JavaScript 的每次互相调用看做一次 RPC 调用。

 

在 JSBridge 的设计中,可以把前端看做 RPC 的客户端,把 Native 端看做 RPC 的服务器端,从而 JSBridge 要实现的主要逻辑就出现了:通信调用(Native 与 JS 通信) 和句柄解析调用。


四、JSBridge 的通信原理

一、JavaScript 调用 Native的方式

JavaScript 调用 Native 的方式,主要有两种:注入 API 和 拦截 URL SCHEME。

1、注入API

注入 API 方式的主要原理是,通过 WebView 提供的接口,向JavaScript 的 Context(window)中注入对象或者方法,让 JavaScript 调用时,直接执行相应的 Native 代码逻辑,达到 JavaScript 调用 Native 的目的。

对于 iOS 的 UIWebView,实例如下:

  1. JSContext *context = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; 
  2. context[@"postBridgeMessage"] = ^(NSArray<NSArray *> *calls) { 
  3. // Native 逻辑 
  4. }; 
  5. 前端调用方式: 
  6. window.postBridgeMessage(message); 

2、拦截 URL SCHEME

先解释一下 URL SCHEME:URL SCHEME是一种类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的 url 近似,主要区别是 protocol 和 host 一般是自定义的,

例如: qunarhy://hy/url?url=ymfe.tech,protocol 是 qunarhy,host 则是 hy。


拦截 URL SCHEME 的主要流程是:Web 端通过某种方式(例如 iframe.src)发送 URL Scheme 请求,之后 Native 拦截到请求并根据 URL SCHEME(包括所带的参数)进行相关操作。

在时间过程中,这种方式有一定的缺陷:

1) 使用 iframe.src 发送 URL SCHEME 会有 url 长度的隐患。

2) 创建请求,需要一定的耗时,比注入 API 的方式调用同样的功能,耗时会较长。

因此:JavaScript 调用 Native 推荐使用注入 API 的方式


二、Native 调用 JavaScript 的方式

相比于 JavaScript 调用 Native, Native 调用 JavaScript 较为简单,直接执行拼接好的 JavaScript 代码即可。

从外部调用 JavaScript 中的方法,因此 JavaScript 的方法必须在全局的 window 上。

对于 iOS 的 UIWebView,示例如下:

  1. result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString]; 
  2. * javaScriptString为JavaScript 代码串 

对于 iOS 的 WKWebView,示例如下:

  1. [wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler]; 

三、通信原理总结

通信原理是 JSBridge 实现的核心

1)JavaScript 调用 Native 推荐使用 注入 API 的方式(iOS6 忽略,Android 4.2以下使用 WebViewClient 的 onJsPrompt 方式)。

2)Native 调用 JavaScript 则直接执行拼接好的 JavaScript 代码即可。


四、JSBridge 接口实现

JSBridge 的接口主要功能有两个:调用 Native(给 Native 发消息) 和 被 Native 调用(接收 Native 消息)。因此,JSBridge 可以设计如下:

  1. window.JSBridge = { 
  2.   // 调用 Native 
  3.   invoke: function(msg) { 
  4.     // 判断环境,获取不同的 nativeBridge 
  5.     nativeBridge.postMessage(msg); 
  6.   }, 
  7.   receiveMessage: function(msg) { 
  8.     // 处理 msg 
  9.   } 
  10. }; 

在上面的文章中,提到过 RPC 中有一个非常重要的环节是 句柄解析调用 ,这点在 JSBridge 中体现为 句柄与功能对应关系。同时,我们将句柄抽象为 桥名(BridgeName),最终演化为 一个 BridgeName 对应一个 Native 功能或者一类 Native 消息。基于此点,JSBridge 的实现可以优化为如下:

  1. window.JSBridge = { 
  2.   // 调用 Native 
  3.   invoke: function(bridgeName, data) { 
  4.   // 判断环境,获取不同的 nativeBridge 
  5.     nativeBridge.postMessage({ 
  6.       bridgeName: bridgeName, 
  7.       data: data || {} 
  8.     }); 
  9.   }, 
  10.   receiveMessage: function(msg) { 
  11.     var bridgeName = msg.bridgeName, 
  12.     data = msg.data || {}; 
  13.   // 具体逻辑 
  14.   } 
  15. }; 

对于 JSBridge 的 Callback ,其实就是 RPC 框架的回调机制。当然也可以用更简单的 JSONP 机制解释:

当发送 JSONP 请求时,url 参数里会有 callback 参数,其值是 当前页面唯一 的,而同时以此参数值为 key 将回调函数存到 window 上,随后,服务器返回 script 中,也会以此参数值作为句柄,调用相应的回调函数。

整体流程:

在 Native 端配合实现 JSBridge 的 JavaScript 调用 Native 逻辑也很简单,主要的代码逻辑是:接收到 JavaScript 消息 => 解析参数,拿到 bridgeName、data 和 callbackId => 根据 bridgeName 找到功能方法,以 data 为参数执行 => 执行返回值和 callbackId 一起回传前端。

Native调用 JavaScript 也同样简单,直接自动生成一个唯一的 ResponseId,并存储句柄,然后和 data 一起发送给前端即可。

 

五、JSBridge 如何引用

对于 JSBridge 的引用,常用有两种方式,各有利弊。

 

1) 由 Native 端进行注入

注入方式和 Native 调用 JavaScript 类似,直接执行桥的全部代码。

优点:桥的版本很容易与 Native 保持一致,Native 端不用对不同版本的 JSBridge 进行兼容;与此同时,

缺点:注入时机不确定,需要实现注入失败后重试的机制,保证注入的成功率,同时 JavaScript 端在调用接口时,需要优先判断 JSBridge 是否已经注入成功。


2) 由 JavaScript 端引用

直接与 JavaScript 一起执行。与由 Native 端注入正好相反。

优点:JavaScript 端可以确定 JSBridge 的存在,直接调用即可;

缺点:如果桥的实现方式有更改,JSBridge 需要兼容多版本的 Native Bridge 或者 Native Bridge 兼容多版本的 JSBridge。

 

 

责任编辑:姜华 来源: 前端学苑
相关推荐

2021-06-30 00:20:12

Hangfire.NET平台

2023-05-12 08:19:12

Netty程序框架

2021-01-29 18:41:16

JavaScript函数语法

2020-11-10 10:48:10

JavaScript属性对象

2021-02-02 18:39:05

JavaScript

2019-01-09 10:04:16

2021-06-04 09:56:01

JavaScript 前端switch

2024-01-30 13:47:45

2023-09-06 14:57:46

JavaScript编程语言

2021-01-26 23:46:32

JavaScript数据结构前端

2021-05-18 08:30:42

JavaScript 前端JavaScript时

2021-06-24 09:05:08

JavaScript日期前端

2023-07-28 07:14:13

2024-04-19 14:23:52

SwitchJavaScript开发

2023-07-30 15:18:54

JavaScript属性

2021-03-09 14:04:01

JavaScriptCookie数据

2021-03-05 18:04:15

JavaScript循环代码

2023-05-08 08:21:15

JavaNIO编程

2021-09-27 09:18:30

ListIterato接口方法

2021-02-26 20:01:57

SVG滤镜元素
点赞
收藏

51CTO技术栈公众号