移动端与网页通信之JSI篇

857 阅读3分钟

通信的必要性

因为移动端的个性使然,网页在移动端中成为一种不过或缺的组成部分,以解决效率低、发版周期长、跨平台等问题。

而网页对移动端原生的调用能力有限,或是不足以满足特定业务的需要,这就需要将【业务指令】发送给原生侧,由原生完成后返回结果。

那两者之间的通信问题就变得十分必要。

名词解释

业务指令:这里指原生侧或网页侧为达到某一业务目的,向对方发送的信息,这些信息能被解析成一个意图供自身完成特定逻辑。

原生侧:指与网页相对的端侧。如在安卓应用中开启一个网页,那么其原生侧指的是安卓,iOS亦如是。

Bridge桥接:由官方提供的原生网页通信接口,详细信息另开一篇。

JSI是什么

JSI是由React Native团队提出的概念,全称为JavaScript Interface

A lightweight API to embed a JavaScript engine in a C++ application. Fabric uses it to communicate between Fabric’s C++ core and React.

  1. React Native 新架构 [1]
  2. [ReactNative翻译]深入了解React Native JSI [2]
  3. 从 react-native 的 js 和 native 通讯看看 JSI 是什么 [3]

以上是网上关于JSI介绍的文章,我摘取一些关键的信息如下

  • JSI概念来源自React Native团队,用于解决通信慢的问题
  • JSI可以应用在做任意的JS引擎上,如JSC(JavaScript Core)v8Hermes
  • JSI允许原生侧(C++)直接与引擎中的JavaScript通信,如函数调用,变量获取等

JSI的使用

在这里举最简单的例子说明

// JS引擎的获取有很多方式,我这里选择直接构造,简单点
let jsc = JSContext()!
let fun: @convention(block) (String) -> Void = { msg in
    print("JSContext Message (msg)")
}
jsc.setObject(fun, forKeyedSubscript: "jscLog" as NSString)
jscLog("Hello!")

// Native print "Hello!"

与Bridge桥接对比的优势

React Native中打开相机时的调用链如图

使用Bridge桥接时需要

  1. 点击原生的UI按钮
  2. 将上下文信息收集
  3. 序列化信息,并发送到Bridge中
  4. Bridge将信息发送到JavaScript中的handleClick
  5. handleClick调用打开相机函数
  6. 将“打开相机”这一个动作序列化后发送给Bridge
  7. Bridge将这一指令发送到原生
  8. 原生执行指令,更新UI

而使用JSI时,这一过程就仅需要1-->4-->5-->8,省下一半的时间!

结果很诱人,但事实却是残酷的。

不足之处

  1. JSI需要原生侧与JS引擎直接对话,而引擎实例无法获取

实际上在网页场景下,原生侧没有办法获取到JS引擎,这里与React Native有非常大的区别。

React Native中的JS引擎是由原生创建的,而相对的,端的网页调用系统的网页容器,该容器在内部创建了JS引擎

  1. 端中的网页容器是多进程架构

在WebKit内核流行后,移动端的网页容器基本都变成了多进程架构,这也成为了无法使用JSI的原因之一。原生侧的函数与引擎不在一个内存空间,无法调用。

  1. JS中对原生方法的调用也会占用引擎资源

尽管在网页的通信上无法使用,但直接使用JS引擎也能完成很多意想不到的工作,下期再谈。