Flutter(一)Hello, Flutter!

语言: CN / TW / HK

1. 移动端开发演变过程

1.1 原生开发

原生应用程序是指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开发工具和语言,直接调用系统SDK API。

  • Android原生应用:使用Java或Kotlin直接调用Android SDK开发的应用程序;

  • iOS原生应用:通过Objective-C或Swift语言直接调用iOS SDK开发的应用程序。

主要优势:

  • 可直接无障碍的访问平台全部功能;

  • 速度快、性能高、可以实现复杂动画及绘制,整体用户体验好;

主要缺点:

  • 开发成本高;不同平台必须维护不同代码,人力成本、测试成本大;

  • 内容固定,动态化弱,大多数情况下,有新功能更新时只能发版,但应用上架、审核是需要周期的,这对高速变化的互联网时代来说是很难接受的;

针对动态化和开发成本两个问题,诞生了一些跨平台的动态化框架。👇👇👇👇👇👇

1.2 跨平台技术简介

这里的跨平台指Android和iOS两个平台。根据其原理,主要分为三类:

  • H5+原生(Cordova、Ionic、微信小程序)=> Hybrid/混合开发

  • 原理:APP需要动态变化的内容通过H5来实现,进一步通过原生的网页加载控件WebView (Android)或WKWebView(iOS)来加载。

  • WebView实质上是一个浏览器内核,其JavaScript依然运行在一个权限受限的沙箱中,所以对于大多数系统能力都没有访问权限,如无法访问文件系统、不能使用蓝牙等。所以,对于H5不能实现的功能,都需要原生去做。

  • 核心:混合框架会在原生代码中预先实现一些访问系统能力的API, 暴露给WebView以供JavaScript调用,让WebView成为JavaScript与原生API之间通信的桥梁,主要负责JavaScript与原生之间传递调用消息 => JsBridge(WebView JavaScript Bridge)

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

这里主要介绍下 React Native 特点

  • 和 React 原理相似,支持响应式编程,开发者只需关注状态转移,不需要关注UI绘制;

  • React 和 React Native 主要的区别在于虚拟DOM映射的对象是什么:

  • React中虚拟DOM最终会映射为浏览器DOM树;

  • RN中虚拟DOM会通过 JavaScriptCore 映射为原生控件树。(两步)

  • 第一步:布局消息传递; 将虚拟DOM布局信息传递给原生;

  • 第二步:原生根据布局信息通过对应的原生控件渲染控件树;

  • 优点:

  • 采用Web开发技术栈,社区庞大、上手快、开发成本相对较低。

  • 原生渲染,性能相比H5提高很多。

  • 动态化较好,支持热更新。

  • 不足:

  • 渲染时需要JavaScript和原生之间通信,在有些场景如拖动可能会因为通信频繁导致卡顿;

  • JavaScript为脚本语言,执行时需要JIT(Just In Time),执行效率和AOT(Ahead Of Time)代码仍有差距;

  • 由于渲染依赖原生控件,不同平台的控件需要单独维护。

RN架构升级,进行中,解决频繁和原生通信的瓶颈问题。)

  • 自绘UI+原生(QT for mobile、Flutter)

  • QT for mobile(是移动端开发跨平台自绘引擎的先驱,也是烈士。)

  • Flutter 👇👇👇👇👇👇

2. Flutter 介绍

Flutter 是 Google 推出并开源的移动应用框架,主打跨平台、高保真、高性能。

2.1 跨平台自绘引擎

Flutter 与用于构建应用程序的其他框架不同,是因为 Flutter 既不使用 WebView 也不使用操作系统的原生控件。相反,Flutter 自己实现了自绘引擎。这样不仅能保证一套代码可以同时运行在 IOS 和 Android 平台上,还保证了 Android 和 IOS 上 UI 的一致性,而且也可以避免对原生控件依赖带来的限制和高昂的成本维护,也不用和native层做过多的通信,大大提高性能。

Flutter 使用 Skia 作为其2D渲染引擎,Skia 是一个 Google 的2D图形处理函数,包含字符、坐标转换,以及点阵图都有高效能且简介的表现,Skia 是跨平台的,并提供了非常友好的 API ,目前 Google Chrome 浏览器和 Android 均采用 Skia 作为其绘图引擎。

目前 Flutter 默认支持 Android、IOS、Fuchsia(Google新的自研操作系统)、鸿蒙四个移动平台,也支持 Web 开发(Flutter for web)、 PC 、小程序的开发。

2.2 采用Dart语言

这是一个很有意思也很有争议的问题,Flutter为什么选择Dart语言?

开发效率高。Dart运行时和编译器支持Flutter两个关键特性的组合:

基于JIT的快读开发周期:Flutter在开发阶段采用JIT模式。这样就避免了每次改动都要进行编译,极大节省了开发时间;并且在iOS和Android模拟器或真机上可以实现毫秒级热重载,并且不会丢失状态。

基于AOT的发布包:Flutter 在发布时间可以通过AOT生成高效的ARM代码以保证应用性能。而JavaScript则不具有这个能力(虽然可以通过打包工具实现)。

目前,程序主要有两种运行方式:静态编译与动态解释。
静态编译:在执行前全部被翻译为机器码
👉 AOT(Ahead of time)即“提前编译”; AOT程序的典型代表是用C/C++开发的应用,他们必须在执行前编译成机器码; 动态解释(解释执行)则是一句一句边翻译边运行
👉 JIT(Just-in-time)即“即时编译”。 JIT的代表则非常多,如JavaScript、Python等。
事实上,所有脚本语言都支持JIT模式。但需要注意的是,JIT和AOT 指的是程序运行方式,和编译语言并非强相关,有些语言既可以以JIT方式运行也可以以AOT方式运行,如Java、Python,他们可以在第一次执行时编译成中间字节码,然后在之后执行时可以直接执行字节码,也许有人会说,中间字节码并非机器码,在程序执行时仍需动态将字节码转换成机器码,是的,这没有错,不过通常我们区分是否为AOT的标准就是看代码在执行前是否需要编译,只要需要编译,无论其编译产物是字节码还是机器码,都属于AOT(不必纠结于概念,概念是为了传达精神而发明的,理解原理即可)。

高性能。Flutter提供流畅、高保真的UI体验,为了实现这一点,Flutter中需要能够在每个动画帧中运行大量的代码。这意味着需要一种既能提供高性能的语言,而不会出现丢帧的周期性暂停的问题,而Dart支持AOT,在这一点上可以比JavaScript做的更好。

类型安全。由于Dart 是类型安全的语言,支持静态类型检查,所以可以在编译前发现一些类型错误,并排除潜在问题。这一点对于前端开发者极具吸引力,为了解决JavaScript弱类型的缺点,前端社区出现了很多给JavaScript代码添加静态类型检测的扩展语言和工具,如:微软的TypeScript、Facebook的Flow。而 Dart 本身就支持静态类型,这是他的一个重要优势。

快速内存分配。Flutter框架使用函数式流,这使得它在很大程度上依赖底层内存分配器。因此,拥有一个能够有效的处理琐碎任务的内存分配器将显得十分重要。但其实在内存分配上Dart并没有超越JavaScript,只是Flutter需要,Dart 恰好满足。

Dart 团队就在 Flutter身边。Dart 语言也是谷歌推出的,由于有Dart团队的积极投入,Flutter团队可以获得更多、更方便的支持。

例如:Dart 最初并没有提供原生二进制文件的工具链(这对于实现可预测的高性能有很大帮助),但是现在它实现了,因为 Dart 团队专门为 Flutter 构建了它。 Dart VM 之前已经针对吞吐量进行了优化,但团队现在正忙于优化VM的延迟,这对于Flutter的工作负载更为重要。

2.3 高性能

Flutter 高性能主要是靠以上刚刚介绍的两点来保证的:

采用 Dart 语言开发。Dart 在 JIT(即时编译)模式下,速度与 JavaScript 基本持平,但是 Dart 支持 AOT,当以 AOT 模式运行时,JavaScript 就远远追不上了。速度的提升对高帧率下的数据计算很有帮助。

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

2.4 响应式框架

借鉴 React 响应式的 UI 框架设计思想。中心思想是用 widget 构建你的 UI。 Widget 描述了他们的视图在给定其当前配置和状态时应该看起来像什么。当 widget 的状态发生变化时,widget 会重新构建 UI,Flutter 会对比前后变化的不同, 来确定底层渲染树从一个状态转换到下一个状态所需的最小更改(类似于 React/Vue 中虚拟 DOM 的 diff 算法)。

2.5 多端编译

2.5.1 移动端

  • 打包 Android 并发布手机商店 👉 VSCode

  • 打包命令

    flutter build apk

  • 发布:

  • 注册各大应用市场开发者账号

  • 创建要发布的app信息

  • 按照流程上传

  • 打包 IOS 并发布 Apple Store 👉 XCode

  • 打包命令

    flutter build ios

  • 发布:

  • 注册 Apple 开发者

  • 创建要发布的app信息

  • 配置钥匙串

  • 在xcode配置apple stoer的证书和bundle id

  • xcode>Product>Archive>Distribute App

2.5.2 Web端

  • Flutter 2.x

  • 检查是否支持web开发 $ flutter devices

  • 打包命令

    flutter build web --web-renderer html # 打开速度最快,兼容性好 flutter build web # 打开速度一般,兼容性好 flutter build web --web-renderer canvaskit # 打开速度最慢,兼容性好

  • 部署:直接部署到服务器上即可

3. Flutter 框架结构

3.1 移动架构

3.1.1 Framework 框架层

框架层。这是一个纯dart实现的响应式框架,它实现了一套基础库。

  • 底下两层(Foundation、Animation、Painting、Gestures)在Google的一些视频中被合并为一个Dart UI层,对应的是Flutter中的dart:ui包,它是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。

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

  • Widgets层是Flutter提供的一套基础组件

  • Material 和 Cupertino 是 Flutter 提供的两种视觉风格的组件库,Material 安卓风格,Cupertino 是IOS风格。

实际开发过程中,主要都是和最上面的Widgets、Material/Cupertino两层打交道。

3.1.2 Engine 引擎层

纯C++实现的SDK,为Flutter的核心,提供了Flutter核心API的底层实现。其中包括了Dart运行时、Skia引擎、文字排版引擎等,是连接框架和系统(Android/IOS)的桥梁。在代码调用dart:ui库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。

3.1.3 Embedder 嵌入层

嵌入层基本是由平台对应的语言来实现的。例如:在Android上,是由Java和C++ 来实现的,IOS是由Object-C和Object-C++来实现的。

嵌入层为Flutter提供了一个入口,Flutter系统是通过该入口访问底层系统提供的服务,例如输入法、绘制surface等。

3.2 Web端架构

3.3 移动端开发方式架构比较

4. 移动端开发对比

4.1 方案对比

4.2 性能对比

感兴趣 这里 有详细的性能对比介绍,不赘述。

5. Flutter 周边——调试工具

Flutter日志 和 print(); 是比较常用的检查数据的调试方法,但是不支持图形化界面、布局等的检查。👇👇👇👇👇👇

5.1 inspector 插件

可视化和浏览Flutter Widget树的工具。查看渲染树,了解布局信息。

5.2 Dev Tools

5.3 UME

字节 Flutter Infra 团队推出的开源 应用内 调试工具。

Pub.dev 发布地址
https://pub.flutter-io.cn/packages/flutter_ume
GitHub 开源地址
https://github.com/bytedance/flutter_ume

功能 => UI 检查、代码查看、日志查看、性能工具 ...

服务于 => 设计师、产品经理、研发工程师或质量工程师 ...

  • UI 检查插件包。点选 widget 获取 widget 基本信息、代码所在目录、widget 层级结构、RenderObject 的 build 链与描述的能力,颜色拾取与对齐标尺在视觉验收环节提供有力帮助。

  • 代码查看插件。允许用户输入关键字,进行模糊匹配,对任意代码内容的查看能力。

  • 日志查看。日志信息可通过统一面板提供筛选、导出等。

  • 性能检测包。提供了当前 VM 对象实例数量与内存占用大小等信息。

6. Flutter 周边——学习路线

6.1 学习社区

  • Flutter 中文网 👉 入门文档

  • Flutter 中文社区 👉 入门文档

  • 咸鱼Flutter 👉 可借鉴的架构方案

  • 掘进Flutter 👉 专业性强的博客

  • StackOverflow 👉 问答社区,我遇到的flutter的问题,这里的答案最靠谱

  • 源码及注释 👉 🙋‍♂️🙋‍♂️🙋‍♂️🙋‍♂️🙋‍♂️🙋‍♂️ 最方便开发时查找

6.2 学习路线

1、准备期

  • 目标:

  • 通过学习 Dart 基本语法,了解 Flutter 中的 Dart 的基本使用;

  • 学习 Flutter 提供的基础布局和基本内容组件,完成基本页面展示。

  • 技术点:

  • Dart语法

  • Flutter 基础组件

  • Material Design

  • Cupertino

    > *   [Flutter Widget概述](https://flutterchina.club/widgets-intro/)
    
    > *   [Flutter Layout Widget](https://flutter.dev/docs/development/ui/widgets/layout)
    
    > *   [Flutter 布局教程](https://flutterchina.club/tutorials/layout/)
    
    > *   [Material Design](https://material.io/)
    
  • Flutter 事件处理

  • Flutter 页面跳转

2、入门期

3、进阶期

6.3 学习开源项目

UI组件集项目 FlutterUnit

7. Flutter 周边——JS2Flutter

JS 转 Dart => JS2Flutter