64

浅谈跨平台框架 Flutter 的优势与结构

 5 years ago
source link: https://segmentfault.com/a/1190000018602621?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者:个推ios工程师 伊泽瑞尔

一、背景

目前,移动开发技术主要分为原生开发和跨平台开发两种。其中,原生应用是指在某个特定的移动平台上,使用平台所支持的开发工具和语言,直接调用系统提供的API所开发的应用。

原生开发的主要优势体现在:

1.可以快速访问本平台的全部功能,比如摄像头、GPS等;

2.原生应用的速度快、性能高,而且可以实现比较复杂的动画和绘制效果,用户体验较好。

原生开发的缺点也很明显,主要体现在:

1.开发成本较高,不同的平台必须维护不同的代码,人力成本也会随之增加;

2.有新的功能需要更新时,只能进行版本升级。

随着移动互联网的高速发展,在很多的业务场景下,传统的纯原生开发已经不能满足日益增长的业务需求,主要表现在以下两个方面:

1.应用动态化的需求增大。当需求发生变化,或者是需要增加新的功能时,传统的纯原生应用开发只能通过版本的升级来更新内容,然而应用的上架和审核都需要一定的时间。因此,开发人员迫切地希望进行应用内容的更新时,可以不更新版本,提升工作效率。

2.业务需求变化快,开发成本变高。原生开发一般需要技术团队对iOS、Android两个开发平台进行维护。当版本更新迭代时,开发和测试的成本都会增加。

针对上述两个问题,跨平台框架应运而生。

二、跨平台技术简介

针对上文提到的原生开发所面临的问题,目前在IT界已经诞生了很多跨平台框架,主要分为三类:

1.H5+原生(Cordova、Ionic、微信小程序);

2.JavaScript开发+原生渲染(React Native、Weex、快应用);

3.自绘UI+原生(Flutter)。

在本文中,我们将对React Native、Weex和Flutter进行对比。

1.React Native

React Native是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook开源的JS框架React在原生移动应用平台的衍生物。React Native使用了react的设计模式,但是其UI渲染、动画效果、网络请求等均是由原生来实现的。开发者编写JS代码,通过React Native的中间层转化为原生控件,并进行操作。也就是说通过JS代码来调用原生的组件,从而实现相应的功能。

React Native实现跨平台的功能,主要由Java、C++和Javascript三层所构成的。其中,C++实现的动态链接库(.so),作为中间适配层桥接,实现了JS端与原生端的双向通信交互。React Native会把应用的JS代码编译成一个JS文件,React Native整体框架目标就是为了解释并运行这个JS脚本文件,如果是JS扩展的API,则直接通过bridge调用native;如果是UI界面,则映射到virtual DOM这个虚拟的JS数据结构中,通过bridge传递到native,然后根据数据设置各个对应的真实native的View。

vI7zYrn.png!web

2.Weex

在Weex设计之初,开发者就考虑到,使其能够在三端(iOS、安卓和H5)上均能得到展现。在最上面的DSL,阿里一般称之为Weex文件(.we),通过Transform转换为js-bundle,再部署到服务器,这样服务端就完成了。在客户端,第一层是JS-Framework,最后是RenderRengine。

fiIrmeZ.png!web

如上图所示,Weex的输入是Virtual DOM,输出是native或H5 view,还原为内存中的树型数据结构,再创建view,把事件绑定在view上,设置view的基本属性。Weex Render会分三个线程,不同的线程负责不同的事情,让JS线程优先保障流畅性。

表面上,Weex是一种客户端技术,但实际上,它串联起了从本地开发、云端部署到分发的整个链路。开发者可以在本地像编写Web页面一样先编写一个APP界面,然后通过命令行工具将之编译为一段JavaScript代码,生成一个Weex的JS bundle。与此同时,开发者可以将生成的JS bundle部署至云端,之后通过网络请求或者预下发的方式加载至用户的移动应用客户端。

在移动应用客户端,Weex SDK会准备一个JavaScript执行环境,在用户打开一个Weex页面时,在该环境中执行相应的JS bundle,并将执行过程中产生的各种命令发送到native端,进行界面渲染、数据存储、网络通信、调用设备及用户交互响应等。如果用户希望使用浏览器访问这个界面,那么他可以在浏览器中打开一个相同的Web页面,这个页面和移动应用使用相同的页面源代码,但被编译成适合Web展示的JS Bundle,通过浏览器里的javaScript引擎及Weex SDK运行起来的。

3.Flutter

Flutter 是Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过Dart语言进行APP开发,只需要一套代码就可以同时构建Android和iOS应用,并且可以达到与原生应用一样的性能。Flutter还提供了丰富的组件、接口,开发者可以高效地为 Flutter添加native扩展。此外,Flutter还使用了Native引擎渲染视图,为用户提供了良好的体验。

Flutter与用于构建移动应用程序的其它多数框架不同,因为Flutter既不使用WebView,也不使用操作系统的原生控件。相反,Flutter使用自己的高性能渲染引擎来绘制widget。这样不仅可以保证在Android和iOS的UI一致性,而且也可以避免对原生控件依赖而带来的限制和高昂的维护成本。

同时,Flutter使用Skia作为2D引擎渲染,Skia是Google的一个2D图形处理函数库,在字型、坐标转换以及点阵图等方面都有高效而且简洁的表现。Skia是跨平台的,并提供了非常友好的API。由于Android系统已经内置了Skia,所以Flutter在打包APK时,不需要再将Skia打包到APK中,但是iOS系统并未内置Skia,所以在构建API时,必须将Skia一起打包。

三、高性能的Flutter

目前,Flutter程序主要有两种运行方式:静态编译与动态解释。静态编译的程序在执行前,会被全部翻译为机器码,通常将这种类型称为AOT,即 “提前编译”。解释执行则是一句句地边翻译边运行,通常将这种类型称为JIT,即“即时编译”。

AOT程序的典型代表是用C/C++开发的应用,它们必须在执行前编译成机器码。而JIT的代表则非常多,如JavaScript、python等。事实上,所有脚本语言都支持JIT模式。但需要注意的是,JIT和AOT指的是程序运行方式,和编程语言并非是强关联的,有些语言既可以以JIT方式运行,也可以以AOT方式运行,如Java、Python,它们可以在第一次执行时编译成中间字节码,然后在之后的执行中,直接执行字节码。

Flutter的高性能主要靠两点来保证,首先,Flutter APP采用Dart语言进行开发。当Dart在 JIT模式下时,其运行速度与 JavaScript基本持平。此外Dart支持 还AOT,当Dart在 AOT模式下事,其运行速度远超JavaScript。速度的提升对高帧率下的视图数据计算很有帮助。

其次,Flutter使用自己的渲染引擎来绘制UI,布局数据等由Dart语言直接控制,所以在布局过程中不需要像RN那样要在JavaScript和Native之间通信,在一些滑动和拖动的场景下具有明显优势。由于滑动和拖动往往会引起布局的变化,所以JavaScript需要不停地与Native之间同步布局信息,这和在浏览器中要JavaScript频繁操作DOM所带来的问题是相同的,都会带来比较可观的性能开销。

四、为什么Flutter会选择Dart语言?

1.开发效率高。Dart运行时和编译器支持Flutter的两个关键特性的组合,分别是基于JIT的快速开发周期和基于AOT的发布包。基于JIT的快速开发周期:Flutter在开发阶段,采用JIT模式,这样就避免了每次改动都需要进行编译,极大地节省了开发时间。基于AOT的发布包,Flutter在发布时可以通过AOT生成高效的ARM代码,以保证应用性能。而JavaScript则不具备这个能力。

2.高性能。为了实现流畅、高保真的的UI体验,Flutter必须在每个动画帧中都运行大量的代码。这意味着需要一种既能支持高性能,又能保证不丢帧的周期性暂停的语言,而Dart支持AOT,在这一点上比JavaScript更有优势。

3.快速分配内存。Flutter框架使用函数式流,这使得它在很大程度上依赖于底层的内存分配器。

4.类型安全。由于Dart是类型安全的语言,支持静态类型检测,所以可以在编译前就发现一些类型的错误,并排除潜在问题。这对于前端开发者来说更具有吸引力。而JavaScript是一个弱类型语言,这也是为什么在诸多前端社区中,会有众多为JavaScript代码添加静态类型检测的扩展语言和工具。

五、Flutter框架结构

BrMvma6.png!web

Flutter Framework是一个完全由Dart语言构建的SDK,它实现了一整套自底而上的基础库。

1.底部两层(Foundation和Animation、Painting、Gestures)是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。

2.Rendering层是一个抽象的布局层,它依赖于dart UI层。Rendering层会构建一个UI树,当UI树有变化时,它会随即计算出有变化的部分,然后更新UI树,最终将UI树绘制到屏幕上。这个过程类似于React中的虚拟DOM。Rendering层可以说是Flutter UI框架最核心的部分,它除了确定每个UI元素的位置、大小之外,还要进行坐标变换和绘制(调用底层dart:ui)。

3.Widgets层是Flutter提供的一套基础组件库,在基础组件库之上,Flutter还提供了 Material 和Cupertino两种视觉风格的组件库。

Flutter Engine:这是一个完全由 C++实现的 SDK,其中包括了 Skia引擎、Dart运行时和文字排版引擎等。在代码调用 dart:ui库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。

React Native、Weex和Flutter进行对比结果如下所示:

yaEj63A.png!web

六、总结

从Flutter的设计理念来看,其整体架构都是具有革命性的,相比于其他架构,它实现了真正意义上的跨平台。它能够让各平台的体验一致,并且让用户体验达到更优。现如今,Flutter的各种UI库和组件都在不断增加,与之相关的各种生态系统和社区也在不断完善,它对新的操作系统的适配性将会越来越强。相信在不久的将来,Flutter会慢慢成熟起来,成为主流的开发语言之一。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK