下一代移动端跨平台框架-Flutter大解密

Flutter是谷歌的移动端UI开源框架,2018年2月27日, Google发布了Flutter的第一个Beta版本。它是Google使用Dart语言开发的移动应用开发框架,使用Dart代码构建高性能、高保真的iOS和Android应用程序。Flutter的工具和库能够帮助开发者轻松地将本身的想法带到 iOS 和Android 设备上。若是没有任何移动开发经验,用Flutter来构建漂亮的移动应用是不错的选择。前端

Flutter优势有哪些?

  • 热重载(Hot Reload),利用提供的IDE直接保存代码并重载,手机或者模拟器立马就能够看见效果,这一点调试起来很方便。
  • Widget的理念,对于Flutter来讲,手机应用里的全部组件都是Widget,经过可组合的空间集合、丰富的动画库以及分层可扩展的架构实现了富有感染力的灵活界面设计。
  • 借助GPU加速的渲染引擎以及高性能本地代码运行时以达到跨平台设备的高质量用户体验。

现有的移动平台:node

苹果的iOS SDKs发布于2008年,谷歌的Android软件开发工具包发布于2009年,这两种sdk包是基于不一样的编程语言的,分别是Objective-C和Java, 以下是大概的结构图:android

因此带来的问题是大多数APP要针对不一样系统提供不一样版本的应用,由于系统提供的组件和语言不同。随之而来的问题是如何只开发一套代码,两端均可以运行,也就有了以下的三代跨端平台的出现。ios

WebView

这是第一个跨平台的框架,基于JavaScript 和 WebView 例如 Cordova、PhoneGap、APPCan、Ionic等,应用程序能够编写成Html,并最终在移动平台的Webview中显示,并经过JavaScript interface和原生交互。git

缺点:github

  • 加载性能慢,达不到原生UI的体验;
  • 内存消耗比较大;
  • 手势/动画和原生差距比较大;
  • 相关原生功能支持有限。

响应式视图

原生体验的第二代跨平台框架,如ReactNative/Weex,生成虚拟DOM,并进一步对应生成原生的组件,让页面由原生组件组成,来到达原生的体验。JS代码和原生代码自己都是很快的,瓶颈常常发生在当咱们视图从一边转向另外一边时,因此构建高质量的应用程序时,咱们必须将使用桥接的次数控制到最小。算法

缺点:编程

  • 虚拟DOM和原生组件的沟通须要Bridge;
  • 一些复杂的交互组件和动画性能上表现并达不到原生;
  • 平台之间的兼容性问题。

Flutter

第三代跨平台框架,Flutter也提供响应式的视图,Flutter采用不一样的方法避免由JavaScript桥接器引发的性能问题,即用名为Dart的程序语言来编译,Dart是用预编译的方式编译多个平台的原生代码,这容许Flutter直接与平台通讯,同时使用Skia图形引擎来完成图形、文本、图像、动画等绘制,拥有本身独立的一套图形系统,再也不依赖于原生。缓存

缺点:性能优化

  • 学习成本较高;
  • 依赖库较大;
  • 目前版本处于beta版。

Flutter 架构

这种分层设计的目的是帮助开发者写更少的代码来实现功能。例如,Material层经过组合Widget层的控件来构建,而Widget层自己则依赖Rendering层来构建。上述分层为咱们开发App提供了不少选择,首先可使用Flutter提供的现有Widget来组合,或者建立自定义的Widget。

Widget

开发者经过实现一个build函数来定义一个Widget,这个build函数会返回一个Widget树,这棵Widget树更具体地描述了UI中的Widget层次。例如,一个ToolBar Widget的build函数可能会返回一个水平布局、一些文本和不一样的按钮,框架会递归地调用每一个Widget的build函数,直到全部的Widget都遍历完成,而后将这些Widget组合成一颗Widget树。

交互

若是Widget的特性基于用户交互或其余因素进行改变,则这个Widget是有状态的,Flutter提供两种类型的widget, StatelessWidget/StatefulWidget,前者为状态不可变,后者能够经过setState()改变state来改变动新UI,开发者能够根据本身的实际状况使用 StatefulWidget:

StatelessWidget:

Widget布局方式:

在Android系统中,咱们一般是使用xml来进行UI布局,同时能够经过addChild和removeChild添加或者移除视图。 可是在Flutter中,Widget 是不可变的,能够传入一个函数,该函数返回一个子Widget 给父 Widget。并在该函数中经过一个 bool 值来控制子 Widget 的建立。

Touch事件监听:

Flutter中有两种方式来处理touch:

  1. 直接传递一个处理事件的方法给Widget;
  2. 经过GestureDetector来实现事件监听与处理。
  • Tap(onTapDown/ onTapUp/ onTap/ onTapCancel)
  • Double tap(onDoubleTap)
  • Long press(onLongPress)
  • Vertical drag(onVerticalDragStart/ onVerticalDragUpdate/ onVerticalDragEnd)
  • Horizontal drag(onHorizontalDragStart/ onHorizontalDragUpdate/ onHorizontalDragEnd)

动画:

在 Android 中咱们能用View.animate()来启动一个动画,在Flutter中咱们是把Widget包在Animation中。在 Flutter中,有AnimationController 和Interpolator来控制动画的启动。

Canvas:

在 Android 中 咱们能使用Canvas来画或者定制一些UI。在 Flutter中,有CustomPaint 和 CustomPainter来提供一些算法完成绘画功能。

自定义Widget:

在 Android 中 咱们经过继承实现View/ViewGroup等组件来完成一些自定义的组件,在 Flutter中,不提供继承这种方式,而是经过一些小的组件组合。

页面切换:

在 Android 中 咱们经过Intents的方式来启动页面或者service,在 Flutter中没有Intent, 咱们就须要route 和 Navigator来管理页面了,Route能够看成一个page或者activity,Navigator 是一个widget用来管理routes的,能push或者pop页面。

原生生命周期监听:

在android中,页面的生命周期都在activity和fragment中控制,可是Flutter只有一个FlutterView, 咱们须要hook WidgetsBinding 的observer并监听didChangeAppLifecycleState的event消息。

页面间参数传递:

Flutter 页面切换是经过Router和Navigator完成的,一样能够经过result back的方式获取你push的router返回的数据。

和原生之间的数据交互

Flutter 是支持原生页面和Flutter页面混合开发的,可是不支持原生组件在Flutter中使用,原生端有methodchannel 来支持Flutter对原生的一些API调用。

网络请求

在Andorid中,咱们有不少相似Okhttp之类的网络使用,很是方便,在Flutter中,咱们使用http package来简单的完成一个网络请求调用。

Flutter UI组件

Flutter 内置有不少 Material Design 和 Cupertino(iOS 风格)的部件、丰富的手势 API、天然平滑的滑动动画

  • ListView/GridView/ViewPager/Card …
  • Row/Column/Stack等等的布局
  • import 'package:flutter/material.dart'

其余功能:

Android端设计分析:

UI

从Android端页面层次来看,主页面MainActivity是继承了FlutterActivity,经过FlutterActivityDelegate控制一些初始化,包括FlutterView,而整个Flutter展现的页面是绘制在FlutterView中的。

Flutter跨平台的基础就是UI跨平台,UI绘制不依赖系统组件, FlutterView将Dart编写的界面封装成android平台可使用的组件,这个组件完成了android应用界面的全部绘制工做,ios也有相同的一套机制,从而实现了不一样平台共用一套绘制界面的代码。

FlutterView继承了SurfaceView,从API中能够看出SurfaceView属于View的子类,提供双缓存功能,它是专门为制做游戏而产生的,功能很是强大,最重要的是它支持OpenGL ES库,2D和3D的效果都,既然Flutter界面是直接继承于SurfaceView的,它的绘制过程就再也不依赖于系统平台,解耦了系统控件的调用。

Flutter的消息系统:

采用MethodChanel实现7个消息模块管理:多语言、路由导航、按键消息、生命周期、系统信息、用户设置和平台插件,这几乎涵盖了不一样平台全部差别化最大的功能,并且很是依赖原生系统。

MethodChanel:

下面咱们以keyevent为例子简单说明事件传递机制:

FlutterView类有两个处理按键事件的接口,一个是onKeyUp(),一个是onKeyDown(),分别对应按键松开和按下事件,两个方法流程同样,Flutter再将平台的按键事件以消息方式拦截,具体步流程建议参考源码:

  • system_channels.dart
  • raw_keyboard.dart
  • raw_keyboard_listener.dart

Flutter 、ReactNative、原生的比较分析:

UI 层次比较:

能够看到Flutter架构里面只有一个FlutterView用来呈现全部的widget的布局的,因此整个渲染过程是独立于原生UI,而ReactNative和原生是比较相似的,会将js中的UI组件一一对应到原生组件。

Flutter UI层次:

ReactNative UI层次:

内存/cpu/gpu分析:

咱们作了一个简单demo,测试滑动一个有100条数据的list,内存上Flutter和原生相差不大,比较稳定,ReactNative内存波动比较大。CPU方面Flutter比较原生高了接近两倍,相比ReactNative也明显要高。GPU方面Flutter除了初始化时GPU比较高,应该是初始化FlutterView,后面的拖动过程当中看不到GPU的渲染,缘由应该是独立的渲染体系,android studio 提取不出来。因此总体而言原生的性能是最佳的。

Flutter性能:

ReactNative性能:

原生性能:

APK大小分析:

Flutter debug包下,lib库包含86_64/x86/armeabi-v7a,接近50M,考虑如今的手机支持X86比较少,在release包中只包含了armeabi-v7a,lib库大小压缩到了3.3M,整个APK压缩后将在7.5M左右,其余资源大部分是Flutter的代码,主要集中在assets下,并且有优化空间。 相比较于ReactNative,自己的SDK库在3.5M左右,简单的页面对应的JS包大小在300K左右,占用空间能减小很多,可是Flutter是本身实现的一套engine,彻底独立于系统平台,占用比较大,其实也能理解。

Flutter apk结构:

ReactNative apk结构:

原生结构:

性能比较分析:

ReactNative是基于前端思想开发的框架,对于原生复杂的ListView/Gridview等容器,没有办法直接实现,并且还有些复杂的UI依赖于View的嵌套叠加,在这种设计,相比较原生的设计,就会多出不少的View,相比native 实现来讲会多不少view对象,形成了性能下降。也就是说复杂UI需求下,RN对UI的表达效率远低于native,形成性能低下。Flutter是基于Skia本身实现的UI组件库,因此在布局和动画层次上有跟多的灵活性和性能优化空间,能够作到最优化。

开发语言上, js或dart都是一种声明式的写法,但js须要解释,dart是直接语言层面支持了node tree的书写,且对象建立成本低,可直接编译成native代码(AOT),VM效率更高,因此运行上dart效率高不少, 并且Dart 是一种同时支持 JIT/AOT 编译的语言,JIT 开发模式时能快速编译生效,是Hot Reload体验的关键。

兼容性分析:

Flutter所提供的全部的widget/动画还有事件机制都是基于skia来实现的,与平台无关,因此有很高的跨平台的兼容性。可是独立的UI系统致使了,不少Android/iOS对应的工具没法使用。

ReactNative全部的组件都是依赖于原生的,而Android/iOS自己的组件和实现就不同,致使了不少兼容性问题,不一样平台要作适配和桥接,致使了不少的功能成本/开发成本和性能牺牲,好比动画/手势/数据容器等等。

适配性:

Flutter 提供的widget都是基于skia来实现和精心定制的,与具体平台没关,因此能保持很高的跨平台的兼容性,对将来平台的适应性上Flutter从更基础的层去抹平平台差别,Flutter站在了更宽广、更可控的一个基础平台上去演变和发展。ReactNative永远须要follow native开发的这套约束,桥接和抹平差别乃至应用层去适配的成本、面对具体场景去优化性能所须要的成本都是居高不下的。

Flutter引擎+Dart语言将颇有可能成为Google Fuchsia系统主要的UI开发框架, 这将会将其跨平台的特性发挥的淋漓尽致。

Flutter 不足的地方:

  • 开发语言是基于Dart, 对开发者而言,增长了很多学习成本
  • UI布局方面,层次不够明显,不如原生xml写法那么直接,复杂化了程序的可读性
  • Flutter是一种新的框架,目前市面上应用和社区不太成熟,并且支持的库不如ReactNative及原生
  • 目前Dart代码会AOT编译到native,不像ReactNative,支持热更新起来会很难,但从API的结构设计上来看,后期应该很快会实现热更新
  • 不能支持原生组件在Flutter中显示,致使不少组件须要从新开发,不如ReactNative灵活

总之从Flutter的设计理念来看,总体架构都是具备革命性的,相比于其余跨平台实现了真正意义的跨平台,各平台体验一致,并且让用户体验达到了最优,各类UI库和组件也在不断的增长,各类生态系统和社区在不断的完善,对于之后新的操做系统适配性会更强,如Fuchsia系统,很是值得你们了解和学习,相信不久的未来,会慢慢成熟起来,成为主流开发语言。

ARES团队也在持续保持更新,将来会和JDReact引擎一块儿成为京东多端融合平台的双引擎。