App跨平台方案的发展
最近一段时间 Flutter 的技术热度非常高,经常在逛 Github 的时候瞄到,出现的多了,也就引起了我的兴趣;然后来看看这是个什么玩意。
稍微搜一下大概能知道:
Flutter 是 Google 一个新的用于构建跨平台的手机 App 的 SDK,同时也将是 Google Fuchsia 下开发应用的主要工具。
它在 2017 年发布初始版本,很明显是一个为了解决不同平台 App 重复开发的问题,这也不是什么新技术,类似的还有 React Native、Weex。
简单说就是达到 “write once, run everywhere” 的目的,怎么这么耳熟呢。。。
深入了解可以看一下这篇:为什么说 Flutter 是革命性的
Dart
Flutter 使用 Dart 语言开发,Dart 可以被编译(AOT)成不同平台的本地代码,让 Flutter 可以直接和平台通讯而不需要一个中间的桥接过程,从而提高了性能。
这里,有必要提一下 React Native,也是一种流行的跨平台构建方案,是 Facebook 在 2015 年左右搞出来的,要比 Google 早的多。
Facebook 最明智的一点就是让 RN 采用 JS 作为开发语言。因为 JS 拥有非常好的群众基础和较低的学习门槛,所以 RN 不仅可以吸引大量的前端开发者加入,而且可以和 React 社区形成正向互补,进一步巩固 Facebook 在前端领域的统治力。基本上所有合格的前端开发者都可以低成本的学习并使用 RN 进行跨端开发。
Google 让 Flutter 采用 Dart 进行开发,可能是基于对未来的判断,希望 Dart 可以逐步取代 JS 成为前端的开发标准。实际上 Dart 的语法更接近原生开发语言,用 Java 或者 Swift 的开发者会更加喜欢。
RN 采用了桥接系统服务,顺带将系统 UI 也桥接到了 JaveScript 中,可通过原生 UI 系统进行渲染,效率方面肯定比 Flutter 差一点,但是成熟度与方便程度与新发展的 Flutter 根本不是一个量级,不过后续怎样我们继续看吧。
跨平台方案的发展
WebView
第一个跨平台的框架基于 JavaScript 和 WebView,例如 PhoneGap, Apache Cordova, Ionic 等,在苹果发布 iOS 之前,他们鼓励第三方开发者为 iPhone 构建网页应用程序,因此使用 Web 技术构建跨平台应用程序是顺理成章的一步。
我感觉这跟我们之前说的用 HTML5 响应式布局写差不多,既可以简单打包成 App,又可以让手机直接在浏览器中访问,不过像 JavaScript 这样的语言很难直接与本地代码(例如服务)进行通信,因此他们会通过一个在 JavaScript 代码和原生代码的“桥梁”进行上下文切换,因为平台服务通常不会经常被调用,所以这并不会导致太大的性能问题。
React Native
响应式视图火起来后,他们通过使用从响应式编程中借用的编程模式来简化 Web 视图的创建过程。2015 年, React Native 将响应式视图的许多优势带给了移动应用程序。
因为 JavaScript 时常会访问原生 UI 组件,所以它也必须经过这些“桥接器”,界面上的 UI 控件通常被频繁地访问(在动画、转化或者用户用手指“滑动”屏幕上的某些东西时,每秒被访问高达 60 次),因此这很可能会导致性能问题。
这是理解 React Native 性能的其中一个关键,JS 代码和原生代码本身都是很快的,瓶颈经常发生在当我们视图从一边转向另一边时。
未来构建高质量的应用程序时,我们必须将使用桥接的次数控制到最小。
桥接器是 RN 的核心,相比 WebView 它不光桥接了系统服务,还把 UI 顺便也桥接了过去,这样写出来的 UI 最终也会被渲染为原生控件,这也让它在混合开发的时候变得容易。
对于 JS 开发者来说, 画 UI 只需要画到 Virtual DOM 中,不需要特别关心具体的平台, 还是原来的单线程开发,还是原来 HTML 组装 UI(JSX),还是原来的样式模型(部分兼容 )。
不过 UI 的渲染是比较频繁的,想要不卡顿还必须要 60FPS+,这对性能是个不小的挑战。
因为 RN 是采用 JS 开发,还需要一个 JS 的环境,不过这个不用太操心,想多了解下 RN,可以看一下:React Native运行原理解析
Flutter
和 React Native 一样,Flutter 也提供响应式的视图,Flutter 采用不同的方法避免由 JavaScript 桥接器引起的性能问题,即用名为 Dart 的程序语言来编译。
Dart 是用预编译的方式编译多个平台的原生代码,这允许 Flutter 直接与平台通信,而不需要通过执行上下文切换的 JavaScript 桥接器。编译为原生代码也可以加快应用程序的启动时间。
实际上,Flutter 是唯一提供响应式视图而不需要 JavaScript 桥接器的移动 SDK,这就足以让 Fluttter 变得有趣而值得一试,但 Flutter 还有一些革命性的东西,例如它是如何实现 UI 组件的。
组件(Widgets)
这应该是最重要的一块东西,我们可以轻松的用 Web 技术模拟出原生的界面或者符合预期的界面与动画,但是让他们拥有原生组件的特性与流畅度或者事件绑定是比较难的,比较这些模拟的组件最终还是外来物,再说性能方面也是一个问题。
Flutter 的系统架构包含大量赏心悦目、快速、可定制、可扩展的 Widgets。没错,Flutter 不需要使用系统 UI 组件(或 DOM WebViews),它自带了 Widgets。
Flutter 将 UI 组件和渲染器从平台移动到应用程序中,这使得它们可以自定义和可扩展。Flutter 唯一要求系统提供的是 canvas,以便定制的 UI 组件可以出现在设备的屏幕上,以及访问事件(触摸,定时器等)和服务(位置、相机等)。
Dart 程序和执行数据编码与解码的原生平台代码之间仍然有一个接口(参考上图中的蓝绿色部分),但这能比 JavaScript 桥接器快几个数量级。
Flutter 最大的改进之一就是它的布局,它大大简化了布局的“规则”,例如我们都用过的 CSS3 定义了 375 个属性,规则可以相互影响甚至发生冲突,要处理他们之间的关系非常复杂,然而我们常用的一些规则占比非常小,所以 Flutter 改变了传统的布局方式。
体验过 Flutter 的基本都能感觉到界面是非常顺滑的。
虚拟DOM
现有的响应式 web 视图库都引入了虚拟 DOM,DOM 代表 HTML 的文档对象模型,虚拟 DOM 则代表 JS 利用 DOM API 抽象出来的版本。
在响应式 Web 视图(由 ReactJS 和其他系统实现)中,虚拟 DOM 是不可变的,每次更改,所有的东西都得重建。系统将虚拟 DOM 与真正的 DOM 进行比较,生成一组最小的更改,然后执行这些更改,以更新真正的 DOM。最后,平台重新绘制真实的 DOM 到画布中。
这听起来增加了很多额外的工作,但它是值得的,因为操纵 HTML DOM 是非常耗费系统资源的。
React Native 也做类似的工作,但是是在移动应用程序当中进行的。它会操控移动平台上的原生组件而不是 DOM。它构建一个 UI 组件的虚拟树,与原生组件进行比较,并只更新已更改的部件。
结语
其实无论 RN 还是 Flutter 都有相当大的野心实现全平台制霸。除了 Android、iOS 平台之外,RN 已经可以通过第三方工具支持 Windows UMP、Web、Desktop、macOS,甚至近期京东开源的 Alita 项目已经实现 RN 到微信小程序的打通。
RN 当下还是最成熟的一个解决方案,毕竟已经发展的多年,资料也比较多,即使这样官方 Github 也有不少的 issue 未处理,更不要说新兴的 Flutter,不过从长远看,Flutter 也必将是一场革命吧。
最后我想说,JS NB!,加上 Node、Vue、React、Element 的加持,还有什么不能写,前端、后端、桌面 GUI、App 通吃,不知道明天又会被玩出什么花样来。