对 Flutter(以下简称 Flutter)架构体系的 两大视角(框架本身的"底层框架层次" + 应用层面的"项目分层") 的详细说明。你可以先读"框架本身架构"理解 Flutter 引擎机制,再往下看"应用层架构"了解项目组织。
一、Flutter 框架本身的架构层次
Flutter 本身作为一个跨平台 UI 工具包,其内部设计是一个 分层架构(layered model) ,每一层只依赖其下层,不混用,上层可以替换、可扩展。 (docs.flutter.dev)
下面按从底层到底层 + 从上层到上层两个角度说明。
层次一览
- Embedder(嵌入层/平台层)
- Engine(引擎层/核心层)
- Framework(框架层/Dart 层 API)
- (开发者应用层,虽不一定在框架内部,但在使用上属于"你编写的部分")
下面分别说明每层的作用、组成、关键细节。
1) Embedder(嵌入层/平台层)



作用:
- 这是最底部的一层,负责将 Flutter 框架/引擎与具体操作系统平台(如 Android、iOS、Windows、Linux)连接起来。 (docs.flutter.dev)
- 它管理平台提供的渲染表面(canvas/SurfaceView/Metal/Win32 window 等)、输入事件、系统消息循环、插件与平台通道、打包成原生应用。 (WPWeb Infotech)
- 为引擎提供必要的"平台接口"(Platform APIs):例如画布、线程管理、系统调用、生命周期、输入/输出。 (MindInventory)
- 它的语言实现依平台而异:Android 通常 Java/Kotlin + C++,iOS/macOS 为 Objective-C/Swift + C++,桌面为 C++ 等。 (docs.flutter.dev)
为什么重要/关键点:
- 跨平台的关键在于这一层,它屏蔽了不同 OS 的差异,让上面的 Engine + Framework 可以"通用"。
- 如果你要把 Flutter 嵌入已有原生应用(module 模式),就是通过这个 Embedder 层。 (somniosoftware.com)
- 性能瓶颈或平台特定特性(如手势、输入法、原生插件)通常介于这一层与引擎之间。
底层讲解:
- 在 Android,Embedder 创建一个 Android Activity 或 Fragment,设置 SurfaceView 或 TextureView 作为渲染目标,启动 Flutter 引擎(C++)线程,处理事件循环。
- 在 iOS,则可能创建一个 UIViewController,使用 Metal/Canvas 绘制,调用 Engine 的 embedder API。
- 它还负责"平台通道"(Platform Channels)------让 Dart 与原生代码通信。
- 它还负责"消息循环"(event loop)------确保平台的事件(触摸、键盘、生命周期)被转发到 Engine,再到 Framework。
2) Engine(引擎层/核心层)






作用:
- Engine 是 Flutter 的核心,用 C++ 编写(也有少量平台语言)--- 它提供了引擎级别的功能:渲染、文本布局、图形、Dart 运行时、插件接口、平台交互等。 (docs.flutter.dev)
- 它暴露了
dart:ui接口给上述 Framework 使用。 (Medium) - 执行流程大致为:Dart 代码调用 Framework → Framework 调用
dart:ui接口 → 进入 Engine 执行 C++ 代码进行绘制、合成、GPU 渲染、线程管理。 - 渲染:通常通过 Skia 图形库(或在某些场景使用新的 Impeller 渲染器)完成。 (somniosoftware.com)
关键组成:
- Dart VM 或 Ahead-of-Time (AOT) 编译器:在发布版本,Dart 被编译为本机代码。 Framework 层的 Dart 代码最终在 Engine 的 Dart 实现里执行。 (docs.flutter.dev)
- Renderer 图层:负责从 Widget 树/Element 树 → RenderObject 树 → Composited Scene → GPU 绘制。
- Input & Gesture 识别基础:接收平台传来的触摸、鼠标、键盘事件,通过 Engine 分发给 Framework。
- Text、Image、Canvas、Layer 管理:例如文本布局、图像解码、合成层管理都是 Engine 的任务。
- Platform Channels 接口:Engine 为 Dart 与原生 (Embedder) 双向通信提供桥梁。
底层讲解:
- 当你编写一个 StatelessWidget → build() 返回 Widget 树 → Flutter 将构造 Element 树 → 再转为 RenderObject 树 → 最终 Engine 将这些 RenderObjects 的绘制命令转为 GPU/Canvas 命令。
- Engine 的 "每帧" 流程大致:输入事件处理 → 更新状态 → 触发 build/layout/paint → 坐标转换/图层合成 → GPU 提交 → 显示。
- 如果你玩转自定义绘制 (CustomPaint)、Canvas、Shader,基本上就是在 Engine 的绘制通道上操作。
- 性能优化(如避免频繁 rebuild、减少 layer 数量、合成缓存)直接受 Engine 层影响。
3) Framework(框架层/Dart 层 API)






作用:
- 这是我们开发者"日常交互"的层,使用 Dart 编写。它暴露了大量库(如 widgets、rendering、animation、gestures、material、cupertino)供构建 UI。 (docs.flutter.dev)
- 它提供了响应式 UI 模型(UI = f(state))的编程方式:当状态改变,UI 重建。 (somniosoftware.com)
- 它封装了 Widget → Element → RenderObject 的完整流程;你作为开发者主要构建 Widget 树。
组成与分层 :
在 Framework 内部,其实也有"子层"或"模块化分层"可识别,例如:
- 基础库(foundation):包含基本类如 ChangeNotifier、Diagnostics、Key 等。
- Widgets 层:提供 StatelessWidget、StatefulWidget、各种常用 Widgets。
- Rendering 层:管理 RenderObject、layout、painting。
- Painting/Canvas 层:高层 Dart 封装绘制 API。
- Gestures 层:手势识别、触摸事件处理。
- Animation 层:动画控制、插值、驱动。
- Widgets: material/cupertino 设计语言库。
底层讲解:
- 当你调用
runApp(MyApp()),框架将创建一个根 Widget,进入 Widget → Element 树创建。 - 当状态变化(例如某个 StatefulWidget 调用
setState()),框架标记 Element 为 dirty,并调度 rebuild。 - Rebuild 生成新的 Widget 树 → 框架对比旧树,决定哪些 Element 可以复用,哪些需要替换(Widget 更新逻辑) → layout/paint 阶段产生 RenderObject 操作 → 通过 Engine 绘制。
- 框架暴露了丰富的 API:Navigator(路由栈)、Theme(主题)、Localization(本地化)、Accessibility(可访问性)等。
- 框架层是 Flutter 的可替换之处:因为它完全建立在 Engine 提供的
dart:ui之上。你可以用自定义引擎、替换 widget 库等。官方说明:"Each layer is optional and replaceable." (docs.flutter.dev)
4) 应用层(Developer App Layer)
虽然不属于 Flutter 框架自身,但在你构建 Flutter 应用时,这一层即你写的业务逻辑、UI 层、状态管理、路由、服务、数据。Flutter 官方文档也谈到"app architecture"时将其视为一层。 (docs.flutter.dev)
作用:负责你的具体业务:UI 展示、状态管理、数据交互、功能场景。
二、Flutter 应用项目的分层架构(项目层面)
除了框架内部的三大层次,在实际开发大型 Flutter 应用时,还要考虑 项目层次分割。下面基于官方与社区推荐架构说明。
项目层次一览
- UI(Presentation)层
- 逻辑(Domain/ViewModel)层(可选)
- 数据(Data)层
- (可能还有 Application 层 / Use-case 层)
官方把:"UI 层、Logic 层(可选)、Data 层"作为推荐。 (docs.flutter.dev) 社区如 "Very Good Ventures" 推荐四层:Data / Domain / Business Logic / Presentation。 (verygood.ventures)
下面详细说明每层的职责、典型组成、底层细节。
1) UI 层(Presentation 层)
作用:
- 与用户交互,展示数据,捕获用户输入。官方称为 UI layer (presentation layer) 。 (docs.flutter.dev)
- 负责接收来自 ViewModel / 控制器的数据,渲染 Widgets;同时处理用户事件(点击、滑动)并将事件传递给上层逻辑。
典型组成:
- Views(屏幕、页面、Widget 组合)
- ViewModels / Controllers(如果采取 MVVM/MVC 架构)
- Widgets + UI 样式 + 主题 + 路由逻辑
底层讲解:
- 一个
LoginView显示 UI,内部使用LoginViewModel提供的状态(如isLoading、errorMessage、userData)来决定显示内容。 - 当用户点击"提交"按钮,UI 层将调用 viewModel 的
login()方法。然后 viewModel 发起逻辑处理,状态变化后通过notifyListeners()/Stream/StateNotifier 通知 UI 重建。 - UI 层要做到尽量"瘦"------不包含业务逻辑或数据操作,只展示与用户直接交互的内容。官方建议:Widgets 应尽可能少逻辑。 (docs.flutter.dev)
2) 逻辑层(Domain 或 ViewModel 层)
作用:
- "中介"角色,连接 UI 与数据层。它将数据层提供的原始数据转为 UI 可用状态,或将 UI 事件转换为数据层调用。 (docs.flutter.dev)
- 有些架构中,这一层称为 "用例(Use Cases)/业务逻辑(Business Logic)",也可能直接称 "ViewModel"/"Controller"。
典型组成:
- ViewModel / Controller 类:管理状态、处理 UI 事件、调用数据层。
- UseCase / Interactor(在更清晰的 clean 架构里):封装单一业务操作,如 "LoginUser"/"LoadCartItems"。
- 状态管理:使用 Provider、Riverpod、BLoC、StateNotifier 等。
底层讲解:
- 举例:CartService(应用层)会调用 CartRepository,从数据层获取数据,然后在 ViewModel 中将其转换为 UI 模型(如
CartItemViewData),然后触发 UI 更新。类似于文章中所说。 (codewithandrea.com) - 在这种分层内,逻辑层 不直接操作 UI 控件 ,也 不直接访问外部服务/数据库,而是通过数据层接口。这样可测试性更高。
- 状态流动通常是:用户操作 → ViewModel → 调用 UseCase/Repository → 返回数据 → ViewModel 更新状态 → UI 响应。官方称这是"单向数据流(Unidirectional Data Flow)"。 (docs.flutter.dev)
3) 数据层(Data 层)
作用:
- 与数据源交互:如网络请求、数据库、本地存储、平台插件等。提供数据给逻辑层。官方文档中称为 data layer。 (docs.flutter.dev)
- 负责数据变换、缓存、存取、映射(raw model → domain model)等任务。
典型组成:
- Repositories:封装具体数据来源(Remote API + Local DB + Cache)并对外提供统一接口。 (docs.flutter.dev)
- Data Sources:如
AuthApi,UserDatabase,SharedPreferencesStorage等。 - DTO/Model 映射:将网络返回 JSON 映射为 domain 模型。
底层讲解:
- Repository 接口定义如
Future<User> getUser(int id),内部可能先查缓存,再落数据库,再调用网络。这些细节逻辑都在数据层。 - 数据层提供"单一数据源"(Single Source of Truth, SSOT)原则,确保数据的一致性。官方文档提及:每种数据类型应只有一个真实状态源。 (docs.flutter.dev)
- 数据层不应该含有 UI 逻辑/业务逻辑。在实践中,越简单耦合越好。社区意见也强调避免将业务逻辑隐藏在数据层。 (verygood.ventures)
4) 可选:Domain 层(更清晰分离业务)
部分架构(如 Clean Architecture)会再插入一个 Domain 层,位于逻辑层与数据层之间,专注于业务规则/实体/用例。比如 Very Good Ventures 提到"domain layer: transform data that comes from data layer" (verygood.ventures)
作用:
- 将数据层的模型转换为业务模型(domain model)
- 定义用例/交互(use cases / interactors)/业务实体
- 减少业务代码依赖于 UI 或数据实现,增强可重用性、可测试性
底层讲解:
- 你的
FetchOrderUseCase接收OrderRepository,并返回Orderdomain 模型给逻辑层。逻辑层再将Order转为OrderViewData给 UI。 - Domain 层通常不依赖于 Flutter SDK 或 UI 库,只依赖于 Dart 基础库。
三、为什么要这么分层 + 各层之间的交互流程
为什么分层:
- 职责单一(Separation of Concerns) :每层专注一类任务。官方强调"Separation-of-concerns is the most important principle" (docs.flutter.dev)
- 可替换/可测试/可维护 :例如你可以替换数据源、替换状态管理、替换 UI,而不用大规模重构。官方说:"Each layer can only communicate with the layers directly below or above it." (docs.flutter.dev)
- 单向数据流(Unidirectional Data Flow) :数据从数据层流向 UI,操作事件从 UI 向上流。这样减少混乱和状态不一致。 (docs.flutter.dev)
典型交互流程:
假设有一个"加载用户资料"功能:
- UI 层(ProfileScreen)发出请求:调用
profileViewModel.loadUser()。 - ViewModel(逻辑层)调用
userRepository.getUser(id)。 - Repository(数据层)先从本地缓存查找,若无,则调用网络 API,再缓存结果。
- Repository 返回
Userdomain 模型给 ViewModel。 - ViewModel将
User转为UserViewData,更新状态(如state = loaded(userViewData)/error/loading)。 - UI 监听状态变化,收到新状态后 rebuild,展示用户资料或错误。
- 如果用户点击编辑按钮,UI 再通过 ViewModel 发起更新操作,重复上述流程。
四、总结与建议
-
如果你是刚开始用 Flutter:先理解 框架本身三层(Embedder → Engine → Framework),知道为什么 Flutter 可以跨平台且性能优越。
-
当项目稍大或团队协作:引入 应用层分层架构(UI/Logic/Data/可选 Domain),按照职责划分模块、保证可维护性。
-
在实践中:
- UI 层尽量"瘦"------少逻辑,多展示。
- 逻辑层或 Domain 层负责处理状态、用例、转换。
- 数据层只负责数据存取、网络、缓存。
- 遵循单向数据流、单一数据源原则。
- 按 Feature 分模块(而不是全部扔一个文件夹),提高可扩展性。
如果你愿意,我也可以帮你准备一个 具体 Flutter 项目的层次结构模板(目录结构 + 文件抽象 +示例代码),你看要不要?