通信的必要性
因为移动端的个性使然,网页在移动端中成为一种不过或缺的组成部分,以解决效率低、发版周期长、跨平台等问题。
而网页对移动端原生的调用能力有限,或是不足以满足特定业务的需要,这就需要将【业务指令】发送给原生侧,由原生完成后返回结果。
那两者之间的通信问题就变得十分必要。
名词解释
业务指令:这里指原生侧或网页侧为达到某一业务目的,向对方发送的信息,这些信息能被解析成一个意图供自身完成特定逻辑。
原生侧:指与网页相对的端侧。如在安卓应用中开启一个网页,那么其原生侧指的是安卓,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.
- React Native 新架构 [1]
- [ReactNative翻译]深入了解React Native JSI [2]
- 从 react-native 的 js 和 native 通讯看看 JSI 是什么 [3]
以上是网上关于JSI介绍的文章,我摘取一些关键的信息如下
- JSI概念来源自React Native团队,用于解决通信慢的问题
- JSI可以应用在做任意的JS引擎上,如
JSC(JavaScript Core)
,v8
,Hermes
- 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桥接时需要
- 点击原生的UI按钮
- 将上下文信息收集
- 序列化信息,并发送到Bridge中
- Bridge将信息发送到JavaScript中的handleClick
- handleClick调用打开相机函数
- 将“打开相机”这一个动作序列化后发送给Bridge
- Bridge将这一指令发送到原生
- 原生执行指令,更新UI
而使用JSI时,这一过程就仅需要1-->4-->5-->8,省下一半的时间!
结果很诱人,但事实却是残酷的。
不足之处
- JSI需要原生侧与JS引擎直接对话,而引擎实例无法获取
实际上在网页场景下,原生侧没有办法获取到JS引擎,这里与React Native有非常大的区别。
React Native中的JS引擎是由原生创建的,而相对的,端的网页调用系统的网页容器,该容器在内部创建了JS引擎
- 端中的网页容器是多进程架构
在WebKit内核流行后,移动端的网页容器基本都变成了多进程架构,这也成为了无法使用JSI的原因之一。原生侧的函数与引擎不在一个内存空间,无法调用。
- JS中对原生方法的调用也会占用引擎资源
尽管在网页的通信上无法使用,但直接使用JS引擎也能完成很多意想不到的工作,下期再谈。