为什么选择Flutter

693 阅读10分钟

「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战」。

image.png

基本概念
  1. Flutter 是来自谷歌的一个出色的跨平台框架,可用来为移动、桌面和 Web 平台构建应用程序
  2. 基于出色的语言(Dart)和快速的高性能渲染引擎(Skia)从头开始设计出来的
  3. Google 开源的 UI 工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动、Web、桌面和嵌入式平台。Flutter 开源、免费,拥有宽松的开源协议,适合商业项目
  4. 采用响应式框架构建,这是从React中获得的灵感,中心思想是用组件(widget)构建你的UI。 组件描述了在给定其当前配置和状态时他们显示的样子。当组件状态改变,组件会重构它的描述(description),Flutter 会对比之前的描述, 以确定底层渲染树从当前状态转换到下一个状态所需要的最小更改
  5. Flutter 是 Google 开发的一套全新的跨平台、开源 UI 框架,支持 iOS、Android 系统开发,它也是构建未来的 Google Fuchsia 系统应用的主要方式。

Fuchsia

Flutter与Fuchsia简介

接触入手

19年 三月份左右接触Flutter,随着业务需要 开始着手Flutter开发

选择原因
  • 产品业务的需求以及团队开发的需要,支持跨平台 一套代码,多端运行
  • 较少的代码书写,减轻开发工作的难度。Flutter坚持用更少的代码做更多的事。比如兼容问题 (减少html、 js、css 布局上的臃肿)
  • 用Flutter编写代码,几乎95%的代码可以反复使用。与其他平台不同,Flutter有它自己的组件库。因此,我们不必深入了解在iOS和Android上的实现细节。一旦Flutter应用在iOS上经过测试和质量保证,它也将在Android上顺利进行。这意味着在iOS上进行的测试也同样适用于Android。这大大减少了用于在Flutter应用测试和质量保证的时间

用户体验大幅落后于原生 APP,操作的流畅度,程序的执行效率,与原生 APP都有较大差距; HTML5 APP 受网速的影响较大,在网络情况较差的情况下,HTML5 APP 往往连打开都困难。

性能优势

官方介绍的特性:

  • 快速开发热重载性: Android原生开发 会遇到 编译-打包-安装 三部曲。开发效率迟迟得不到提升。热重载技术在Flutter内完美体现

    随着互联网技术的发展,业务平台对多设备、多终端的需求越来越多。Flutter的热重载可以快速地进行测试、构建UI、添加功能并更快地修复错误。

  • 富有表现力,漂亮的用户界面:自带的Material Design(android风格)和Cupertino(iOS风格)widget、丰富的motion API、平滑而自然的滑动效果。

  • 响应式框架:使用Flutter的现代、响应式框架,和一系列基础widget,轻松构建用户界面。

  • 访问本地功能和SDK:Flutter可以复用现有的Java、Swift或ObjC代码,访问iOS和Android上的原生系统功能和系统SDK。

  • 统一的应用开发体验:Flutter拥有丰富的工具和库,可以帮助开发者轻松地同时在iOS和Android系统中实现想法和创意。

  • 原生性能:Flutter包含了许多核心的widget,如滚动、导航、图标和字体等,这些都可以在iOS和Android上达到原生应用一样的性能。

1、跨平台性: Flutter基于图像绘制引擎进行渲染,在不同平台下绘制效果是绝对一致的,能做到真正的跨平台

2、性能优异性: 不同于H5通过DOM渲染 和RN映射组件,Flutter直接基于native进行绘制。性能上完全超过原生

3、节省人力成本,同时不影响用户体验

选择 Flutter 并不是为了代替 iOS 或者 Android,而是做一个技术互补,比如,Flutter 负责业务功能,而 iOS 和 Android 则负责部分的底层交互提供服务给到 Flutter 应用。Flutter 也是在这两年刚刚兴起的,在应用起步初期还需要部分底层的服务与原生平台进行交互。相信再经过一段时间的发展,Flutter 在这方面会不断地优化和提升,也将能够独立覆盖到更多复杂的业务场景

image.png

选型对比

从 Hybrid 到 Weex、React Native 这些跨端技术的出现,确实很好地解决了跨端技术不一致、热加载、提升开发效率,以及降低开发成本的问题,但一个核心技术痛点“性能问题”却一直没有非常好的解决方案。而仅仅出道 2 年的 Flutter,通过自渲染模式,以及在体验和性能上的优异表现一时风头无两,其性能更是在跨端技术中处于领跑地位。

除了大量为适应快速发展节奏和节省人力成本的中小型企业,很多一线互联网企业也在重要项目中落地了 Flutter 技术,包括阿里(闲鱼)、蚂蚁金服(蚂蚁财富)、腾讯(多款在线教育App)、字节跳动(头条和西瓜视频),以及美团(美团 App)和快手(快手 App),等等

image.png

image.png

Hybrid混合式开发,在技术原理上的核心是将原生的一些能力通过 JSBridge 封装给 Web 来调用,扩充了 Web 应用能力。但是这种方法有两个不足,一是依赖客户端,二是在性能和体验上都非常依赖于 Web 端。因此,整体上的体验不太好。目前这个技术还经常被应用到,例如,当前 App 内会提供白名单域名和可调用的 JSBridge 方法,由此来增强 H5 与客户端交互能力,从而提升 App 内 H5 的灵活性。基于网页技术包装,里面仍然是HTML+CSS,利用JS通过桥接形式开发,开发出来的内容还是网页的形式,体验感和流畅度都不如原生 React Native/Weex,在原来的 Hybrid 的 JSBridge 基础上进行改进,将 JavaScript 的界面以及交互转化为 Native 的控件,从而在体验上和原生界面基本一致。但因为是 JIT 模式,因此需要频繁地在 JavaScript 与 Native 之间进行通信,从而会有一定的性能损耗影响,导致体验上与原生会有一些差异。 Flutter,取长补短,结合了之前的一些优点,解决了与 Native 之间通信的问题,同时也有了自渲染模式(框架自身实现了一套 UI 基础框架,与原来的渲染模式基本一致)。从而在体验和性能上相对之前的两种框架表现都较好

出色的渲染能力

Flutter 的 UI 渲染性能很好。在生产环境下,Flutter 将代码编译成机器码执行,并充分利用 GPU 的图形加速能力,因此使用 Flutter 开发的移动应用即使在低配手机上也能实现每秒 60 帧的 UI 渲染速度。

利用Skia绘图引擎,直接通过CPU、GPU进行绘制,不需要依赖任何原生的控件

Flutter 引擎使用 C++ 编写,包括高效的 Skia 2D 渲染引擎,Dart 运行时和文本渲染库。

这个引擎使得 Flutter 框架可以自由、灵活、高效地绘制 UI 组件。而应用开发者则可以用 Flutter 框架来轻松实现各种设计语言和动画效果

举个例子 (GIF图)Flutter 最高120桢/秒

不足之处

Flutter 虽潜力上限很高,但仍需打磨和雕琢,我们在 Flutter 推动过程中遇到很多问题,比如包体积过大的问题、性能达不到预期、对混合工程的支持不够友好、各宿主 Flutter 引擎版本不一致、基础库不完善、Flutter 改造后各项数据打平等。

由于 Flutter 是一个跨平台 UI 库,因此不支持原生系统的功能,例如:

  • 系统通知;
  • 系统感应、相机、电量、LBS、声音、语音识别;
  • 分享、打开其他 App 或者打开自身 App;
  • 设备信息、本地存储。

项目结构

image.png

Dart语言

Dart 语言从一开始就被设计为构建客户端应用程序的绝佳工具,并已针对 UI 开发工作做了调整和优化。

Dart 有着干净且极为强大的语法,促进且鼓励了强大的应用程序架构和设计,更不用说团队一致性、标准化、长寿命、易于维护,以及许多现有的跨平台工具往往缺失的特性。它与其他流行语言(例如 C#、Java 和 TypeScript)相似,这意味着有相关经验的开发人员很容易快速上手并开始使用 Dart。

Dart 和 JavaScript 一样,有一个库管理资源(pub.dev)。你可以在这里搜索找到你想要的一些库,接下来只要在 Dart 的配置文件 pubspec.yaml 中增加该库即可。这点类似于在 JavaScript 的 package.json 中增加声明一样,同样也有 dependencies 和 dev_dependencies。

增加类似的数据配置,如下代码:

dependencies:

  dio: ^3.0.4

dev_dependencies:

  flutter_test:

    sdk: flutter

Flutter的Widget分为StatelessWidget和StatefulWidget两种。

StatelessWidget是无状态的,StatefulWidget是有状态的,因此实际使用时,更多的是StatefulWidget。

  • StatelessWidget: 一旦创建就不关心任何变化,在下次构建之前都不会改变。它们除了依赖于自身的配置信息(在父节点构建时提供)外不再依赖于任何其他信息。比如典型的Text、Row、Column、Container等,都是StatelessWidget。它的生命周期相当简单:初始化、通过build()渲染。
  • StatefulWidget: 在生命周期内,该类Widget所持有的数据可能会发生变化,这样的数据被称为State,这些拥有动态内部数据的Widget被称为StatefulWidget。比如复选框、Button等。State会与Context相关联,并且此关联是永久性的,State对象将永远不会改变其Context,即使可以在树结构周围移动,也仍将与该context相关联。当state与context关联时,state被视为已挂载。StatefulWidget由两部分组成,在初始化时必须要在createState()时初始化一个与之相关的State对象。

StatefulWidget的生命周期如下

  • initState() :Widget 初始化当前 State,在当前方法中是不能获取到 Context 的,如想获取,可以试试 Future.delayed()
  • didChangeDependencies() :在 initState() 后调用,State对象依赖关系发生变化的时候也会调用。
  • deactivate() :当 State 被暂时从视图树中移除时会调用这个方法,页面切换时也会调用该方法,和Android里的 onPause 差不多。
  • dispose() :Widget 销毁时调用。
  • didUpdateWidget:Widget 状态发生变化的时候调用。
调用库

引入库的方式也与 ES6 的 import 语法很相似。先看看下面的一个例子,其目的是引入 pages 下的 homepage.dart 模块。

import 'package:boss/pages/homepage.dart';

import 为关键词,

package 为协议,可以使用 http 的方式,不过最好使用本地 package 方式,避免性能受影响

boss 为库名或者说是该项目名

pages 为 lib 下的一个文件夹

homepage.dart 则为具体需要引入的库文件名。

当然这里也可以使用相对路径的方式,不过建议使用 package 的方式,以保持整个项目代码的一致性,因为对于第三方模块则必须使用 package 的方式。

一切皆是组件

控件

image.png

资料

\