背景

作为一个FE儿,相信你肯定听说过这些跨端技术:react native、weex、flutter、kraken 等等。都快2022年了,作为一个只了解H5和React Native跨端的人,这肯定是不行的🙅,我们也要卷起来!
截屏2021-12-12 下午9.12.41.png
本文尝试探讨:

  • 当下有些跨端技术,他们有什么痛点?
  • 大厂现在都在用什么?
  • 跨端未来的趋势,选择技术方案要考虑哪些点?

跨端是什么?

一般来说,跨端技术有 4 类场景,分别是跨设备平台(跨 Web 端和手机端)、跨操作系统(如跨安卓和 iOS)、跨 App 以及跨渲染容器。
跨平台指的是跨操作系统,而跨端是指客户端。客户端的特点就是有界面、有逻辑,所以包含逻辑跨端和渲染跨端。
本篇文章将重点围绕移动领域的跨端技术进行深入探讨。

当下比较流行的跨端技术

H5

网页具有跨端的天然优势,无论什么渲染框架,WebView 都是必不可少的核心组件

  1. 优点:成本低,上手快,可选择多种框架
  2. 缺点:各个浏览器的适配问题、性能问题、体验问题
    1. 适配问题:各个浏览器厂商根据W3C规范实现浏览器产生的异同,导致需要处理各种适配问题。比如css样式和js事件。
    2. 性能问题:Web 标准在设计上不是 Design for Performance 的,导致很多地方难以进一步改善,例如 JS 执行和 Layout、渲染互斥无法并行,导致过长的 JS 执行任务会执行正常的渲染导致卡顿。
    3. 体验问题:比如白屏问题,交互体验等。与Native 还是有很大的距离,Native还是交互体验的天花板

H5 PLUS:JS + Native 能力

WebView内嵌H5是最简单的做法,能满足大部分需求。但是对于一些:需要调用系统能力、与Native同步状态此类需求,就需要借助JS Bridge。

  1. 优点:同上 +
    1. 通过Native能力可以实现部分优化,比如:加载资源、请求劫持、Native实现组件替换和复用
  2. 缺点:同上 +
    1. Apple 明确指出不欢迎 WebView 套壳 APP,有拒审危险
    2. WebView 渲染引擎设计的上的缺陷
      • JS Execute,Layout, Paint 都在MainThread ,无法并行化
      • JS 的性能赶不上 Native Tookit 的 Java Dart Object-C 等编译型语言,执行复杂逻辑时会卡顿
      • 渲染流水线非常长,导致浏览器对合成器动画和非合成器动画区分对待,非合成器动画性能不佳
      • 光栅化是异步进行的,进行惯性滚动时,会出现白屏,这个是 Webview 始终无法避免的问题

如果想借助 Native 加强 Web 怎么办?这时候就有了一些探索:

  • 预热:提前创建和初始化 WebView,甚至实现 WebView 容器池,减少 WebView 的启动时间
  • 缓存:把常用的H5资源预先存在 Native 本地,然后拦截浏览器网络请求重定向到本地,这样就可以加快 H5请求的资源加载速度(也叫“离线包”方案);
  • 劫持:比如说 H5 对网络加载的控制力比较弱,部分有能力的厂商会把所有的网络请求都劫持下来交给 Native 去做,这样做可以更灵活的管理 H5 请求
  • 替换:替换一般指替换 H5 的 Img 标签和 Video 标签,这个最常见的地方就是各大新闻类客户端。因为新闻的动态性和实时性,新闻都是由各个编辑/自媒体通过后台编辑下发的,这时候要利用 Web 强大的排版功能去显示文本内容;但是为了加载速度和观看体验,图片和视频都是 Native 组件替换的

React Native

截屏2021-12-12 下午9.32.27.png
React 2013 年发布,两年后 React Native 就发布了,RN 这个跨段方案的创新性在于它保留了 JS Engine,在渲染引擎这条路上,他没有自己造轮子,而是复用了现有的 Native 渲染管线。
这样做的好处在于,保留 JS Engine,可以最大程度的复用 Web 生态,毕竟 GitHub 上轮子最多的语言就是 JavaScript 了;复用 Native RenderPipeLine,好处在于脱离 WebKit 的历史包袱,相对来说渲染管线更短,性能自然而然就上去了。
这种体系充分将 Native 的 View 体系输出到前端体系中,在进行 Android/iOS Native View 的封装过程中,存在不少难以逾越的障碍。如:难以磨平的双端一致性问题、复杂样式能力难以实现、 Layout 动画问题。组件的封装成本随着复杂度增加也越来越高,难以逾越 Native View 限制来提供更细致的 W3C 标准能力。

RN 的逻辑跨端是基于 js 引擎,通过 bridge 注入一些设备能力的 api;而渲染跨端则是使用安卓、ios 实现 React 的 virtual dom 的渲染。

优点:基于React 前端上手快,一套代码支持IOS和安卓,代码编译快热加载,能支持热更新
缺点

  1. iOS/Android 双端本身不一致的组件和布局机制,让双端一致性难以得到保障
  2. 复杂样式能力难以实现、 Layout 动画问题、长列表丢帧等
  3. native api 和组件并没有做到双端一致,而且有的时候需要原生配合,混杂 rn 代码和自己扩展的代码导致代码比较难管理。最著名的事件就是 airbnb 从最大的 react native 支持者到弃用 react native

weex

weex是基于vue开发的。在原理上1.0仿rn, 2.0仿flutter,这里就不再赘述了
截屏2021-12-12 下午9.37.02.png

flutter

截屏2021-12-12 下午9.45.45.png
flutter 是近些年流行的跨端方案,跨端包括安卓、ios、web 等。它最大的特点是渲染不是基于操作系统的组件,而是直接基于绘图库(skia)来绘制的,这样做到了渲染的跨端。逻辑的跨端也不是基于 js 引擎,而是自研的 dart vm 来跨端,通过 dart 语言来写逻辑。
基于 Skia 构建跨平台组件,解决了 Weex 难以解决的双端一致性等问题。但这似乎也是一种双刃剑,他注定难以复用 Native 多年来积累的强大组件。
Widget 标准对于前端不友好,因此不少团队开始尝试把 Widget 体系转换成前端标准子集进行功能输出。在完善的 Flutter Widget 的前提下,Flutter Widget 通过 Component 封装转换成前端 HTML5 标准进行输出。从 Native View 到 W3C 的标准转换很难去完美适配。在深层次标准适配时,会出现难以解决的样式和布局能力扩展的问题整体来看: Widget 的标准转换到 HTML5 标准只能做部分实现,难以完美适配;进行复杂样式组合时会碰到和标准不一致的现象,难以像下一代定制内核的UI渲染引擎一样高效。
优点

  • 渲染双端一致性等问题

缺点

  • flutter for web暂时不明晰
  • NativeView 的融合上也存在一些问题,难以复用 Native 多年来积累的强大组件
  • 社区支持较少
  • 目前大厂基于flutter做了一些探索和自研,侧面证明一些场景存在问题

自研引擎

跨端引擎很依赖底层实现的组件和 api,用开源方案也一样得扩展这部分,所以有一定规模的团队都会选择自研。
自研跨端引擎会和 rn、weex 不同:

  • 渲染部分不需要实现 virtual dom 的渲染,而是直接对接 dom api,上层应用基于这些 dom api 实现跨端渲染。这样理论上可以对接任意前端框架。
  • 逻辑部分也是基于 js 引擎,通过 binding 直接注入一些 c++ 实现的 api,或者运行时通过 bridge 来注入一些安卓、ios 实现的 api。

跨端初探 - 图5
优点:自研跨端引擎的好处是组件和 api 可以自己扩展,更快的响应业务的需求。
缺点:其中组件和 api 的双端一致性,以及统一的 api 的设计都是难点。

当下跨端技术的痛点

  • 原生体验就是天花板
  • 多端一致性是双刃剑
  • 研发效率,工程填坑,研发成本转移

大厂做的技术优化

lynx https://www.yuque.com/hebingqian/sd5tn0/ldhoi3

hummer https://ppt.infoq.cn/slide/show?cid=94&pid=3678

dartNative:https://ppt.infoq.cn/slide/show?cid=94&pid=3673

大会ppt: https://ppt.infoq.cn/list/gmtcsz2021

未来趋势

  • 并没有哪一种框架可以真正上说能给完美解决以上的问题,同时博众人之所长,一超多强。
  • 至少在未来的3年,仍是群雄并立的时代,不会出现终极跨段解决方案
  • 原生渲染的方案逐渐收敛,整体朝着自渲染方向演进

选择跨端技术的关注点

我们都应该理解,从 Hybrid 的方案到 React Native、Weex 再到 Flutter,本质上都是在研发成本、灵活性、性能体验三者间找一个平衡点,只是大家切入的点不太一样,最终导致整个解决方案有了不同。假设说现在你要做一个新的 App,可能整个开发团队是多前端、少客户端的,那么我可能会比较建议大家多考虑 Hybrid 的模式;如果对性能要求比较高,就可以考虑用用 Weex 或者 React Native;反过来,如果是客户端同学比较多,那么考虑下 Flutter 未尝不可。

移动端的跨平台技术并不是仅仅考虑一套代码能够运行在不同场景即可,还需要解决性能、动态性、研发效率以及一致性的问题。
性能: 如何通过前端和客户端的结合,实现更优的渲染性能以及交互性能;
动态性: 客户端怎样能够实现更低成本的发版、甚至不发版直接动态更新代码;
研发效率:如何提升不同客户端的动态调试之类的研发效率;
一致性: 如何实现一份代码的多端部署,并保证代码在多个客户端内展示形态的一致性以及兼容性问题。

思考

virtual dom带来的思考:我们知道virtual dom是react带来的新思考,他带来了很多好处,比如减少重绘和重排以提高性能,但是他也有一些缺点。自react提出后,vue2也引入了这种设计,还有weex等。
除了web端,vm也给跨端带了新的思考,比如rn将vm映射成Native组件等。

vdom 作为一个纯对象,可以清晰的提炼出出布局的嵌套结构,而且这个抽象描述是平台无关的,那么我们就可以利用 JS 生成 vdom,然后将 vdom 映射到 Native 的布局结构上,最终让 Native 渲染视图,以达到跨平台开发的目的。