背景
随着移动端从诞生到遍地开发再到平台化的收敛,为了不断满足企业对于开发效率及跨平台的一致性的追求,各种跨平台方案层出不穷。对于我们做产品设计和开发,开发效率和使用体验可以说是至关重要的两个因素。如果你身处大前端,你就不得不拥抱跨端,这是一个不以人意志为转移的趋势。从本质上来讲,跨平台开发是为了增加业务代码的复用率,减少因为要满足多个平台的适配开发而带来的开发和维护成本,从而有效降低开发成本。
方案演进
无论大大小小的跨平台方案,按照其核心的设计思想,可以划分了三个阶段
- Web 容器
基于设备系统原生的浏览器组件来实现页面及业务功能。代表方案有:cordova等 - 泛Web容器
采用web标准进行开发,在运行时由原生系统负责渲染绘制。代表方案有:RN、Weex等 - 自渲染引擎
自带渲染引擎,客户端仅需要提供画布便可以实现业务功能到UI的多端一致的渲染体验。代表方案:Flutter
下面我们逐个分析这三个阶段不同的设计思想与各自的优势
Web容器
Web 容器的方案,是最简单也最易操作的方案,主要采用原生系统内嵌的浏览器控件(Android的WebView,iOS的WKWebView)的方式渲染H5页面。客户端与HT定义好交互的协议,将一些原生系统能力暴露给H5通过js来调起,也就是大家说的 JSBridge。
web容器的交互设计可以通过下图来直观提现
这种方案最终的渲染方还是浏览器,一个H5页面呈现出来是要经过较为复杂的过程,我们可以陈列下最基础的加载过程,就可以知道这个过程的复杂性。
- 浏览器控件加载 HTML5 页面的 HTML 主文档。
- 加载过程中遇到外部 CSS 文件,浏览器另外发出一个请求,来获取 CSS 文件。
- 遇到图片资源,浏览器也会另外发出一个请求,来获取图片资源。这是异步请求,并不会影响 HTML 文档的加载。
- 加载过程中遇到 JavaScript 文件,由于 JavaScript 代码可能会修改 DOM 树,因此 HTML 文档会挂起渲染(加载解析渲染同步)的线程,直到 JavaScript 文件加载解析并执行完毕,才可以恢复 HTML 文档的渲染线程。
- JavaScript 代码中有用到 CSS 文件中的属性样式,于是阻塞,等待 CSS 加载完毕才能恢复执行。
从这个过程我们可以看出,一个完成的H5页面的呈现要经过浏览器控件的加载、解析和渲染三大过程,性能消耗和呈现效率相比原生页面都有很大的负面增加。虽然Web容器方案开发体验友好,跨平台兼容性强等优势,但需要承载大量的与Web指定的协议标准,会导致容器过于笨重,而且较难实现复杂交互和呈现较好的用户体验
泛Web容器
泛Web容器的方案优化了Web容器方案的浏览器加载、解析和渲染这三大过程,把影响它们独立运行的 Web 标准进行了裁剪,以相对简单的方式支持了构建移动端页面必要的 Web 标准(如 Flexbox 等),也保证了便捷的前端开发体验;同时,这个时代的解决方案基本上完全放弃了浏览器控件渲染,而是采用原生自带的 UI 组件实现代替了核心的渲染引擎,仅保持必要的基本控件渲染能力,从而使得渲染过程更加简化,也保证了良好的渲染性能。也就是说,在泛 Web 容器时代,我们仍然采用前端友好的 JavaScript 进行开发,整体加载、渲染机制大大简化,并且由原生接管绘制,即将原生系统作为渲染的后端,为依托于 JavaScript 虚拟机的 JavaScript 代码提供所需要的 UI 控件的实体。这,也是现在绝大部分跨平台框架的思路。RN和Weex就是采用了这种设计方案。
为了追求更好的性能体验,进一步位置方案的简单可扩展性,一些公司已经放弃Web标准。放弃JS的动态执行能力,而自研一套原生的DSL解析器来实现跨端方案,例如天猫、美团、滴滴等。
自渲染引擎
泛 Web 容器方案使用原生控件承载界面渲染,解决了不少性能问题,但同时也带来了新的问题。抛开框架本身需要处理大量平台相关的逻辑外,随着系统版本变化和 API 的变化,我们还需要处理不同平台的原生控件渲染能力差异,修复各类奇奇怪怪的 Bug。始终需要 Follow Native 的思维方式,而Flutter 则使用了一种全新的思路,即从头到尾重写一套跨平台的 UI 框架,包括渲染逻辑,甚至是开发语言。
- 渲染引擎依靠跨平台的 Skia 图形库来实现,Skia 引擎会将使用 Dart 构建的抽象的视图结构数据加工成 GPU 数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。
-
开发语言选用的是同时支持 JIT(Just-in-Time,即时编译)和 AOT(Ahead-of-Time,预编译)的 Dart,不仅保证了开发效率,更提升了执行效率(比使用 JavaScript 开发的泛 Web 容器方案要高得多)。
通过这样的思路,Flutter 可以尽可能地减少不同平台之间的差异, 同时保持和原生开发一样的高性能。Flutter 成了三类跨平台移动开发方案中最灵活的那个,目前也是热度相对较高的跨平台方案。
我们的选择
对比三种方案最具代表的框架,我们可以对比他们不同的优劣
我们在做技术选型时,要从团队规模、开发效率、技术栈、性能表现、维护成本和社区生态来进行综合考虑。比如,是否必须支持动态化?是只解决 Android、iOS 的跨端问题,还是要包括 Web?对性能要求如何?对多端体验的绝对一致性和维护成本是否有强诉求?社区是否足够活跃,能够交流更多的疑难问题和解决方案,这些都是我们要考虑的。因为一旦选型后,业务的推动过程中,这些问题点最终都是要自己消化掉的。判断一个技术是否能成为未来大前端主流技术发展的趋势,主要看这个技术是否能减少对底层宿主环境的依赖,隔离各终端系统差异,能否从原理和运行机制及生态有领先同类产品的表现,向开发者提供统一而标准化的能力。