本文出处:Flutter 中文开发者网站
架构
embedder嵌入层
提供程序入口(其他原生应用也采用此方式),程序由此和底层操作系统协调(surface渲染、辅助功能和输入服务,管理事件循环队列)
嵌入层在android采用java和c++编写,苹果系采用object-c和object-C++,Windows和linux是c++
Engine引擎--核心
采用C++编写,提供了flutter应用所需的原语,核心api的底层实现
引擎将底层 C++ 代码包装成 Dart 代码,通过 dart:ui 暴露给 Flutter 框架层
补充:android和ios采用impeller渲染图形,其他平台采用skia(鸿蒙arkui也是使用的skia)
Framework框架层
开发者通过此层和flutter交互
build()方法
build方法就是将状态转换为ui的方法,widget重写该方法声明ui
此方法在框架需要时可以被调用,常规是一个渲染针一次
--得利于dart语言的可以快速实例化和清除对象
应用根据事件交互,同志框架替换旧widget为新widget
flutter拥有自己的ui控制实现,而不是由系统自带的方法进行托管
Widget
flutter对于widget的准则是,widget由更小的用途单一的widget组成
两种核心的 widget 类:有状态的 和 无状态的 widget
widget 则需要被重建以更新相关部分的 UI。这些 widget 会继承 StatefulWidget,并且「可变的」状态会保存在继承 State 的另一个子类中(因为 widget 本身是不可变的)。 StatefulWidget
自身没有 build 方法,而在其对应的 State
对象中
每当你更改 State
对象时(例如计数增加),你需要调用 setState() 来告知框架,再次调用 State
的构建方法来更新 UI
将状态和 widget 对象分离,可以使其他 widget 无差异地看待无状态和有状态 widget,而不必担心丢失状态
渲染方式
react native等跨平台框架,一般在android和ios的ui底层库上建立一层抽象,使用js等代码与android和ios系统交互构建ui界面
flutter上文提到额,使用自己的widget,绘制flutter图像的dart代码被编译为机器码,并使用skia渲染
flutter嵌入了自己的skia副本,使得开发者可以不用最新的系统也能跟进系统升级跟新自己的应用
flutter绘制代码片段时,调用build方法返回一个基于当前状态的widget树,build方法会在必要时引入其他的widget--如指定color,coloredBox会被加入用于颜色布局
构建阶段,flutter将widgets转换为对应的element树
在渲染树中,每个节点的基类都是 RenderObject,该基类为布局和绘制定义了一个抽象模型。这是再平凡不过的事情:它并不总是一个固定的大小,甚至不遵循笛卡尔坐标规律(根据该 极坐标系的示例 所示)。每一个 RenderObject
都了解其父节点的信息,但对于其子节点,除了如何 访问 和获得他们的布局约束,并没有更多的信息。这样的设计让 RenderObject
拥有高效的抽象能力,能够处理各种各样的使用场景。
在构建阶段,Flutter 会为 Element 树中的每个 RenderObjectElement
创建或更新其对应的一个从 RenderObject
继承的对象。 RenderObject
实际上是原语:渲染文字的 RenderParagraph、渲染图片的 RenderImage 以及在绘制子节点内容前应用变换的 RenderTransform 是更为上层的实现。
大部分的 Flutter widget 是由一个继承了 RenderBox
的子类的对象渲染的,它们呈现出的 RenderObject
会在二维笛卡尔空间中拥有固定的大小。 RenderBox
提供了 盒子限制模型,为每个 widget 关联了渲染的最小和最大的宽度和高度。
平台嵌入层
平台嵌入层是flutter引擎一部分,充当宿主操作系统和flutter之间的粘合剂
开发者可以创建自定义的嵌入层,如:https://github.com/ardera/flutter-pi是支持树莓派运行的例子
与其他代码集成
flutter提供通过平台通道调用自定义代码的能力,
通过创建一个常用的通道(封装通道名称和编码),开发者可以在 Dart 与使用 Kotlin 和 Swift 等语言编写的平台组件之间发送和接收消息。数据会由 Dart 类型(例如 Map)序列化为一种标准格式,然后反序列化为 Kotlin(例如 HashMap
)或者 Swift(例如 Dictionary
)中的等效类型。
外部函数接口
dart:ffi库提供了一套直接绑定原生代码的机制,比平台通道更快(不用序列化就可以传输数据)
flutter中渲染原生内容
flutter引入了平台widget解决在flutter应用展示原生组件的问题
目前桌面平台尚未支持平台视图,但这并不是一个架构层面的限制。未来可能将增加对桌面平台的支持
即成flutter widget至原生应用
Flutter 模块模板设计简单,易于嵌入。开发者可以将其作为源代码依赖项集成到 Gradle 或 Xcode 构建定义中,或者将其打包成 Android Archive (AAR) 或 iOS Framework 二进制供其他开发者使用,而无需安装 Flutter。
Flutter 引擎需要一段短暂的时间做初始化,用于加载 Flutter 的共享库、初始化 Dart 的运行时、创建并运行 Dart isolate 线程并将渲染层与 UI 进行绑定。为了最大限度地减少呈现 Flutter 界面时的延迟,最好是在应用初始化时或至少在第一个 Flutter 页面展示前,一并初始化 Flutter 引擎,如此一来用户不会在首个 Flutter 页面加载时感到突然地卡顿。另外,Flutter 的引擎分离使得多个 Flutter 页面可以复用引擎,共享必要库加载时的内存消耗。
flutter对于web的支持
Dart 语言存在之初就已经支持直接编译成 JavaScript,并且针对开发和生产目的对其工具链进行了优化。许多重要的应用已经使用 Dart 编译成的 JavaScript 在生产环境上运行,包括 Google Ads 的广告商工具。
然而,使用 C++ 编写的 Flutter 引擎是为了与底层操作系统进行交互的,而不是 Web 浏览器。因此我们需要另辟蹊径。Flutter 在 Web 平台上以浏览器的标准 API 重新实现了引擎。目前我们有两种在 Web 上呈现内容的选项:HTML 和 WebGL。在 HTML 模式下,Flutter 使用 HTML、CSS、Canvas 和 SVG 进行渲染。而在 WebGL 模式下,Flutter 使用了一个编译为 WebAssembly 的 Skia 版本,名为 CanvasKit。 HTML 模式提供了最佳的代码大小,CanvasKit 则提供了浏览器图形堆栈渲染的最快途径,并为原生平台的内容5提供了更高的图形保真度。
Flutter 框架本身和应用程序代码将一并编译成 JavaScript。同时Dart 在不同模式下(JIT 和 AOT、平台原生和 Web 编译)的语义几乎没有差异,大部分开发者绝对可以无差异地编写这两种模式下的代码。
在进行开发时,Web 版本的 Flutter 使用支持增量编译的编译器 dartdevc 进行编译,以支持应用热重启(尽管目前尚未支持热重载)。相反,当你准备好创建一个生产环境的 Web 应用时,Dart 深度优化的编译器 dart2js 将会用于编译,将 Flutter 核心框架和你的应用打包至缩小的源文件中,可部署在任何服务器上。代码可以在单个文件中提供,也可拆分至多个文件以 延迟加载库 提供。