了解React Native与小程序的底层框架

本文是学习React Native与小程序官方开发指南的笔记与总结,以了解React Native和小程序的底层框架。

Hybrid App

在了解React Native与小程序前,我们先来了解一下Hybrid App。

优势

Hybrid App(混合模式移动应用)是指介于web-app、native-app这两者之间的app,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”。

Native App是一种基于智能手机本地操作系统如iOS、Android、WP并使用原生程式编写运行的第三方应用程序,也叫本地app。一般使用的开发语言为JAVA、C++、Objective-C。
Web App就是运行于网络和标准浏览器上,基于网页技术开发实现特定功能的应用。

以下是与Web App和Native App的对比:

Web App Hybrid App Native App
开发成本
维护更新 简单 简单 复杂
体验
安装 不需要 需要 需要
跨平台

技术原理

Hybrid App的本质,其实是在原生的 App 中,使用 WebView 作为容器直接承载 Web页面,也有人说成是“套壳”。
其中,最核心的点就是 Native端 与 H5端 之间的双向通讯层,也可以理解为我们需要一套跨语言通讯方案,来完成 Native(Java/Objective-c/…) 与 JavaScript 的通讯。这个方案就是 JSBridge,而实现的关键便是作为容器的 WebView,一切的原理都是基于 WebView 的机制。
Hybrid App

WebView是一个基于webkit引擎、展现web页面的控件。

现有方案

现在比较流行的混合方案主要有三种,主要是在UI渲染机制上的不同:

  1. 基于 WebView UI 的基础方案,市面上大部分主流 App 都有采用,例如微信JS-SDK,通过 JSBridge 完成 H5 与 Native 的双向通讯,从而赋予H5一定程度的原生能力。
  2. 基于 Native UI 的方案,例如 React-Native、Weex。在赋予 H5 原生API能力的基础上,进一步通过 JSBridge 将js解析成的虚拟节点树(Virtual DOM)传递到 Native 并使用 原生渲染
  3. 另外还有近期比较流行的小程序方案,也是通过更加定制化的 JSBridge,并使用 双线程 的模式隔离了JS逻辑与UI渲染,形成了特殊的开发模式,提高了页面性能及开发体验。

以上的三种方案,其实同样都是基于 JSBridge 完成的通讯层,第二三种方案,其实可以看做是在方案一的基础上,继续通过不同的新技术进一步提高了应用的混合程度。

接下来,我们先看一下React Native的方案。

React Native的底层框架

总体框架

React Native

  • js层
    该层提供了各种供开发者使用的组件以及一些工具库(事件分发等)。
  • C++层
    主要处理java/OC与js的通信(JSBridge)以及执行JavaScript(JS脚本引擎)。
  • Native层(Object C/Java层)
    主要包括UI渲染器、网络通信等工具库。根据不同操作系统有不同的实现。

UI渲染

因为React Native的底层为React框架,同样地也体现了虚拟DOM的思想

  1. 首先Js层通过jsx编写的Virtual Dom来构建Component
  2. Native层将其转成真实DOM插入到原生 App 的页面中。
  3. 当有变更,通过diff算法生成差异对象
  4. 最终由 Native层将差异对象应用到原生App的页面元素上。

虚拟DOM具体实现思路:

  1. 用JS对象模拟DOM(虚拟DOM)
  2. 把此虚拟DOM转成真实DOM并插入页面中(render)
  3. 如果有事件发生修改了虚拟DOM,比较两棵虚拟DOM树的差异,得到差异对象(补丁数组)(diff)
  4. 把差异对象(补丁数组)应用到真正的DOM树上(patch)
    优点是能高效的改动DOM,避免了重新绘制DOM。

通信机制

主要是使用JSCore实现JS和Object C/Java交互。
大致步骤如下:

  • 把JSX代码解析成javaScript代码
  • 读取JS文件,并利用利用JS脚本引擎执行
  • 返回一个数组,数组中会描述OC/Java对象,描述对象属性和所需要执行的方法,这样就能让这个对象设置属性,并且调用方法。

JSCore,即JavaScriptCore,JS引擎的核心部分。
iOS使用的是内置的JavaScriptCore,Android使用的是 https://webkit.org 家的jsc.so。

小结

RN既有Native的体验,又能使用前端开发者熟悉的React框架,并具有hybrid技术的优点,能跨平台开发,能远程更新代码,提高迭代频率和效率。
但还有以下不足:

  • RN 所支持的样式是 CSS 的子集,会满足不了 Web 开发者日渐增长的需求;
  • RN 现有能力下还存在的一些不稳定问题,比如性能、Bug等。
  • RN 是把渲染工作全都交由客户端原生渲染,会有更接近原生的体验,但实际上一些简单的界面元素使用 Web 技术渲染完全能胜任。

接下来,我们来看一下小程序的双线程的模式。

小程序的底层框架

双线程模型

如下图,小程序的运行环境分成渲染层和逻辑层,WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。
一个小程序存在多个界面,所以渲染层存在多个WebView线程。这使得小程序更贴近原生体验,也避免了单个WebView的任务过于繁重。
这两个线程的通信会经由微信客户端(Native)做中转,逻辑层发送网络请求也经由Native转发。
小程序双线程模型

原因

小程序的渲染层和逻辑层分离主要有两个原因:

  1. UI渲染跟 JavaScript 的脚本执行分别在两个线程,从而避免一些逻辑任务抢占UI渲染的资源。
  2. 为了解决管控与安全问题,提供一个沙箱环境来运行开发者的JavaScript 代码(逻辑层),从而阻止开发者使用一些浏览器提供的,诸如跳转页面、操作DOM、动态执行脚本的开放性接口。详情可以看官网的管控与安全
  3. 渲染层和逻辑层的分离也给在不同的环境下(小程序与小程序开发者工具)运行提供了可能性。

UI渲染

与RN一样,小程序在页面渲染上也体现了虚拟DOM的思想。
小程序页面渲染

  1. 首先,在渲染层,宿主环境会把WXML可以先转成JS对象,然后再渲染出真正的Dom树。
  2. 在逻辑层发生数据变更的时候,我们需要通过宿主环境提供的setData方法把数据从逻辑层传递到渲染层,
  3. 再经过对比前后差异,把差异应用在原来的Dom树上,渲染出正确的UI界面。

在组件系统方面,小程序的大部分组件由Exparser组件框架实现,小部分原生组件由客户端参与组件的渲染,以提供更好的性能。
比如原生组件map<map latitude="39.92" longtitude="116.46"></map>
在实际运行时,

  1. 渲染层webview创建组件,插入到DOM树中后计算布局(位置与宽高)。
  2. 通过通信机制通知Native,Native会根据布局插入一块原生区域并渲染。
  3. 当webview得知位置或宽高发生变化时,通知Native做相应的调整。

详细看原生组件

通信原理

那么,渲染层与逻辑层是怎么与Native通信的呢?
在视图层与客户端的交互通信(基本上只是原生组件会用到)方面,

  • iOS 利用WKWebView 的提供 messageHandlers 特性;
  • 安卓则是往 WebView 的 window 对象注入一个原生方法,最终会封装成 WeiXinJSBridge 这样一个兼容层。

在逻辑层与客户端原生通信机制方面,

  • iOS平台可以往JavaScripCore框架注入一个全局的原生方法;
  • 安卓方面则是跟渲染层一致的。

开发者工具

上面有提到渲染层和逻辑层的分离也给在不同的环境下运行提供了可能性。在开发者工具中,逻辑层实际上是使用一个隐藏着的标签来模拟JSCore的。并通过将JSCore中不支持的BOM对象局部变量化,使得开发者无法在小程序代码中正常使用BOM,从而避免不必要的错误。
在通讯机制方面,开发者工具底层维护着一个WebSocket服务器,用于在WebView与开发者工具之间建立可靠的消息通讯链路,使得接口调用,事件通知,数据交换能够正常进行,从而使小程序模拟器成为一个统一的整体。
详细可看官网上的微信开发者工具

小结

小程序双线程模型中,渲染层和逻辑层分离,具有渲染快、加载快的优点;
但任何数据传递都是线程间的通信,也就是都会有一定的延时。这会使得各部分的运行时序变得复杂一些。详细可以看官网上的天生的延时

总结

共同点

RN与小程序都具有hybrid技术的优点,兼具“Native App良好用户交互体验的优势”和“Web App跨平台开发的优势”。
从框架来说,都使用Web 相关技术来编写业务代码;都实现了一套跨语言通讯方案,来完成 Native(Java/Objective-c/…)端 与 JavaScript (小程序中分为渲染层和逻辑层)的通讯。

不同点

从渲染底层来看,小程序使用浏览器内核来渲染界面(小部分原生组件由客户端参与渲染),即界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力;而 RN 则是用客户端原生渲染的。

参考