前言
大家好,我是 simbawu,关于这篇文章,有问题欢迎来这里讨论。
随着移动互联网的普及和快速发展,手机成了互联网行业最大的流量分发入口。以及随着 5G 的快速发展,未来越来越多的“端”也会如雨后春笋般快速兴起。而“快”作为互联网的生存之道,为了占领市场,企业也会积极跟进,快速布局。同一个应用,各个“端”独立开发,不仅开发周期长,而且人员成本高。同时,作为技术人员,也不应该满足于这种重复、低能的工作状态。在这样的形势下,跨平台的技术方案也受到越来越多人和企业的关注。接下来,我将从原理、优缺点等方面为大家分享《跨平台技术演进》。
H5
说到跨平台,没人不知道 H5。不管是在 Mac、Windows、Linux、iOS、Android 还是其他平台,只要给一个浏览器,连“月球”上它都能跑。
浏览器架构
下面,我们来看看让 H5 如此横行霸道的浏览器的架构:
User Interface 用户界面:提供用户与浏览器交互
Browser Engine 浏览器引擎:控制渲染引擎与 JS 解释器
Rendering Engine 渲染引擎:负责页面渲染
JavaScript Interpreter JS 解释器:执行 JS 代码,输出结果给渲染引擎
Networking 网络工作组:处理网络请求
UI Backend UI 后端:绘制窗口小部件
Data Storage 数据存储:管理用户数据
浏览器由以上 7 个部分组成,而“渲染引擎”是性能优化的重中之重,一起了解其中的渲染原理。
渲染引擎原理
不同的浏览器内核不同,渲染过程会不太一样,但主要流程还是一致的。
分为下面 6 步骤:
HTML 解析出 DOM Tree
CSS 解析出 CSSOM
DOM Tree 与 CSSOM 关联生成 Render Tree
Layout 根据 Render Tree 计算每个节点的尺寸、位置
Painting 根据计算好的信息绘制整个页面的像素信息
Composite 将多个复合图层发送给 GPU,GPU 会将各层合成,然后显示在屏幕上。
从以上 6 步,我们可以总结渲染优化的要点:
Layout 在浏览器渲染过程中比较耗时,应尽可能避免重排的产生
复合图层占用内存比重非常高,可采用减小复合图层进行优化
以上就是浏览器端的内容。但 H5 作为跨平台技术的载体,是如何与不同平台的 App 进行交互的呢?这时候 JSBridge 就该出场了。
JSBridge 原理
JSBridge,顾名思义,是 JS 和 Native 之间的桥梁,用来进行 JS 和 Native 之间的通信。
通信分为以下两个维度:
JavaScript 调用 Native,有两种方式:
拦截 URL Scheme:URL Scheme 是一种类似于 url 的链接(boohee://goods/876898), 当 web 前端发送 URL Scheme 请求之后,Native 拦截到请求并根据 URL Scheme 进行相关操作。
注入 API:通过 WebView 提供的接口,向 JavaScript 的 Context(window)中注入对象或者方法,让 JavaScript 调用时,直接执行相应的 Native 代码逻辑,达到 JavaScript 调用 Native 的目的。
Native 调用 JavaScript:JavaScript 暴露一个对象如 JSBridge 给 window,让 Native 能直接访问。
那么 App 内加载 H5 的过程是什么样的呢?
App 打开 H5 过程
打开 H5 分为 4 个阶段:
交互无反馈
打开页面 白屏
请求 API,处于 loading 状态
出现数据,正常展现
这四步,对应的过程如上图所以,我们可以针对性的做性能优化。
优缺点分析
下面,我们进行 H5 的优缺点分析:
优点
跨平台:只要有浏览器,任何平台都可以访问
开发成本低:生态成熟,学习成本低,调试方便
迭代速度快:无需审核,及时响应,用户可毫无感知使用最新版
缺点
性能问题:在反应速度、流畅度、动画方面远不及原生
功能问题:对摄像头、陀螺仪、麦克风等硬件支持较差
虽然 H5 目前还存在不足,但随着 PWA、WebAssembly 等技术的进步,相信 H5 在未来能够得到越来也好的发展。
小程序
2018 年是微信小程序飞速发展的一年,19 年,各大厂商快速跟进,已经有了很大的影响力。下面,我们以微信小程序为例,分析小程序的技术架构。
小程序跟 H5 一样,也是基于 Webview 实现。但它包含 View 视图层、App Service 逻辑层两部分,分别独立运行在各自的 WebView 线程中。
View
可以理解为 h5 的页面,提供 UI 渲染。由 WAWebview.js 来提供底层的功能, 具体如下:
消息通信封装为 WeixinJSBridge
日志组件 Reporter 封装
wx api(UI 相关)
小程序组件实现和注册
VirtualDOM,Diff 和 Render UI 实现
页面事件触发
每个窗口都有一个独立的 WebView 进程,因此微信限制不能打开超过 5 个层级的页面来保障用户体验。
App Service
提供逻辑处理、数据请求、接口调用。由 WAService.js 来提供底层的功能, 具体如下:
日志组件 Reporter 封装
wx api
App,Page,getApp,getCurrentPages 等全局方法
AMD 模块规范的实现
运行环境:
iOS:JavaScriptCore
Andriod:X5 内核,基于 Mobile Chrome 53/57
DevTool:nwjs Chrome 内核
仅有一个 WebView 进程
View & App Service 通信
视图层和逻辑层通过系统层的 JSBridage 进行通信,逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层将触发的事件通知到逻辑层进行业务处理。
优缺点分析
优点
预加载 WebView,准备新页面渲染
View 层和逻辑层分离,通过数据驱动,不直接操作 DOM
使用 Virtual DOM,进行局部更新
组件化开发
缺点
仍使用 WebView 渲染,并非原生渲染,体验不佳
不能运行在非微信环境内
没有 window、document 对象,不能使用基于浏览器的 JS 库
不能灵活操作 DOM,无法实现较为复杂的效果
页面大小、打开页面数量都受到限制
既然 WebView 性能不佳,那有没有更好的方案呢?下面我们看看 React Native。
React Native
RN 的理念是在不同平台上编写基于 React 的代码,实现 Learn once, write anywhere。
Virtual DOM 在内存中,可以通过不同的渲染引擎生成不同平台下的 UI,JS 和 Native 之间通过 Bridge 通信
React Native 工作原理
在 React 框架中,JSX 源码通过 React 框架最终渲染到了浏览器的真实 DOM 中,而在 React Native 框架中,JSX 源码通过 React Native 框架编译后,与 Native 原生的 UI 组件进行映射,用原生代替 DOM 元素来渲染,在 UI 渲染上非常接近 Native App。
### React Native 与 Native 平台通信
React Native 用 JavaScriptCore 作为 JS 的解析引擎,在 Android 上,需要应用自己附带 JavaScriptCore,iOS 上 JavaScriptCore 属于系统的一部分,不需要应用附带。
用 Bridge 将 JS 和原生 Native Code 连接起来。Native 和 JavaScript 两端都保存了一份配置表,里面标记了所有 Native 暴露给 JavaScript 的模块和方法。交互通过传递 ModuleId、MethodId 和 Arguments 进行。
优缺点分析
优点
垮平台开发:相比原生的 ios 和 android app 各自维护一套业务逻辑大同小异的代码,React Native 只需要同一套 javascript 代码就可以运行于 ios 和 android 两个平台,在开发、测试和维护的成本上要低很多。
快速编译:相比 Xcode 中原生代码需要较长时间的编译,React Native 采用热加载的即时编译方式,使得 App UI 的开发体验得到改善,几乎做到了和网页开发一样随时更改,随时可见的效果。
快速发布:React Native 可以通过 JSBundle 即时更新 App。相比原来冗长的审核和上传过程,发布和测试新功能的效率大幅提高。
渲染和布局更高效:React Native 摆脱了 WebView 的交互和性能问题,同时可以直接套用网页开发中的 css 布局机制。脱了 autolayout 和 frame 布局中繁琐的数学计算,更加直接简便。
缺点
动画性能差:React Native 在动画效率和性能的支持还存在一些问题,性能上不如原生 Api。
不能完全屏蔽原生平台:就目前的 React Native 官方文档中可以发现仍有部分组件和 API 都区分了 Android 和 IOS 版本, 即便是共享组件, 也会有平台独享的函数。也就是说仍不能真正实现严格意义上的“一套代码,多平台使用”。另外,因为仍对 ios 和 android 的原生细节有所依赖,所以需要开发者若不了解原生平台,可能会遇到一些坑。
生态不完善:缺乏很多基本控件,第三方开源质量良莠不齐
展望未来
虽然 RN 还存在不足,但 RN 新版本已经做了如下改进,并且 RN 团队也在积极准备大版本重构,能否成为开发者们所信赖的跨平台方案,让我们拭目以待。
改变线程模式。UI 更新不再同时需要在三个不同的线程上触发执行,而是可以在任意线程上同步调用 JavaScript 进行优先更新,同时将低优先级工作推出主线程,以便保持对 UI 的响应。
引入异步渲染能力。允许多个渲染并简化异步数据处理。
简化 JSBridge,让它更快、更轻量。
既然 React Native 在渲染方面还摆脱不了原生,那有没有一种方案是直接操控 GPU,自制引擎渲染呢,我们终于迎来了 Flutter!
Flutter
Flutter 是 Google 开发的一套全新的跨平台、开源 UI 框架,支持 iOS、Android 系统开发,并且是未来新操作系统 Fuchsia 的默认开发套件。渲染引擎依靠跨平台的 Skia 图形库来实现,依赖系统的只有图形绘制相关的接口,可以在最大程度上保证不同平台、不同设备的体验一致性,逻辑处理使用支持 AOT 的 Dart 语言,执行效率也比 JavaScript 高得多。
Flutter 架构原理
Framework:由 Dart 实现,包括 Material Design 风格的 Widget,Cupertino(针对 iOS)风格的 Widgets,文本 / 图片 / 按钮等基础 Widgets,渲染,动画,手势等。此部分的核心代码是:flutter 仓库下的 flutter package,以及 sky_engine 仓库下的 io,async,ui(dart:ui 库提供了 Flutter 框架和引擎之间的接口)等 package。
Engine:由 C ++ 实现,主要包括:Skia,Dart 和 Text。
Skia 是开源的二维图形库,提供了适用于多种软硬件平台的通用 API。其已作为 Google Chrome,Chrome OS,Android, Mozilla Firefox, Firefox OS 等其他众多产品的图形引擎,支持平台还包括 Windows7+,macOS 10.10.5+,iOS8+,Android4.1+,Ubuntu14.04+ 等。Skia 作为渲染 /GPU 后端,在 Android 和 Fuchsia 上使用 FreeType 渲染,在 iOS 上使用 CoreGraphics 来渲染字体。
Dart 部分主要包括:Dart Runtime,Garbage Collection(GC),如果是 Debug 模式的话,还包括 JIT(Just In Time)支持。Release 和 Profile 模式下,是 AOT(Ahead Of Time)编译成了原生的 arm 代码,并不存在 JIT 部分。
Text 即文本渲染,其渲染层次如下: 衍生自 minikin 的 libtxt 库(用于字体选择,分隔行)。HartBuzz 用于字形选择和成型。
Embedder:是一个嵌入层,即把 Flutter 嵌入到各个平台上去,这里做的主要工作包括渲染 Surface 设置, 线程设置,以及插件等。从这里可以看出,Flutter 的平台相关层很低,平台 (如 iOS) 只是提供一个画布,剩余的所有渲染相关的逻辑都在 Flutter 内部,这就使得它具有了很好的跨端一致性。
Dart 优势
很多人会好奇,为什么 Flutter 要用 Dart,而不是用 JavaScript 开发,这里列下 Dart 的优势
Dart 的性能更好。Dart 在 JIT 模式下,速度与 JavaScript 基本持平。但是 Dart 支持 AOT,当以 AOT 模式运行时,JavaScript 便远远追不上了。速度的提升对高帧率下的视图数据计算很有帮助。
Native Binding。在 Android 上,v8 的 Native Binding 可以很好地实现,但是 iOS 上的 JavaScriptCore 不可以,所以如果使用 JavaScript,Flutter 基础框架的代码模式就很难统一了。而 Dart 的 Native Binding 可以很好地通过 Dart Lib 实现。
Fuchsia OS。Fuchsia OS 内置的应用浏览器就是使用 Dart 语言作为 App 的开发语言。
优缺点分析
优点
性能强大:在两个平台上重写了各自的 UIKit,对接到平台底层,减少 UI 层的多层转换,UI 性能可以比肩原生
优秀的语言特性:参考上面 Dart 优势分析
路由设计优秀:Flutter 的路由传值非常方便,push 一个路由,会返回一个 Future 对象(也就是 Promise 对象),使用 await 或者.then 就可以在目标路由 pop,回到当前页面时收到返回值。
缺点
优点即缺点,Dart 语言的生态小,精通成本比较高
UI 控件 API 设计不佳
与原生融合障碍很多,不利于渐进式升级
总结
移动互联网的普及和快速发展,跨平台技术风起云涌,这也是技术发展过程中的必经之路,等浪潮退去,才知道谁在裸泳。我个人更看好 H5 或类 H5 方案,给它一个浏览器,连“月球”都能跑,这才是真正的跨平台,其他都是浮云。
广而告之
本文发布于薄荷前端周刊,欢迎 Watch & Star ★,转载请注明出处。
欢迎讨论,点个赞再走吧 。◕‿◕。 ~