Flutter架构解析:从引擎层到应用层

对 Flutter(以下简称 Flutter)架构体系的 两大视角(框架本身的"底层框架层次" + 应用层面的"项目分层") 的详细说明。你可以先读"框架本身架构"理解 Flutter 引擎机制,再往下看"应用层架构"了解项目组织。


一、Flutter 框架本身的架构层次

Flutter 本身作为一个跨平台 UI 工具包,其内部设计是一个 分层架构(layered model) ,每一层只依赖其下层,不混用,上层可以替换、可扩展。 (docs.flutter.dev)

下面按从底层到底层 + 从上层到上层两个角度说明。

层次一览

  1. Embedder(嵌入层/平台层)
  2. Engine(引擎层/核心层)
  3. Framework(框架层/Dart 层 API)
  4. (开发者应用层,虽不一定在框架内部,但在使用上属于"你编写的部分")

下面分别说明每层的作用、组成、关键细节。


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 提供的状态(如 isLoadingerrorMessageuserData)来决定显示内容。
  • 当用户点击"提交"按钮,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,并返回 Order domain 模型给逻辑层。逻辑层再将 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)

典型交互流程:

假设有一个"加载用户资料"功能:

  1. UI 层(ProfileScreen)发出请求:调用 profileViewModel.loadUser()
  2. ViewModel(逻辑层)调用 userRepository.getUser(id)
  3. Repository(数据层)先从本地缓存查找,若无,则调用网络 API,再缓存结果。
  4. Repository 返回 User domain 模型给 ViewModel。
  5. ViewModel将 User 转为 UserViewData,更新状态(如 state = loaded(userViewData)/error/loading)。
  6. UI 监听状态变化,收到新状态后 rebuild,展示用户资料或错误。
  7. 如果用户点击编辑按钮,UI 再通过 ViewModel 发起更新操作,重复上述流程。

四、总结与建议

  • 如果你是刚开始用 Flutter:先理解 框架本身三层(Embedder → Engine → Framework),知道为什么 Flutter 可以跨平台且性能优越。

  • 当项目稍大或团队协作:引入 应用层分层架构(UI/Logic/Data/可选 Domain),按照职责划分模块、保证可维护性。

  • 在实践中:

    • UI 层尽量"瘦"------少逻辑,多展示。
    • 逻辑层或 Domain 层负责处理状态、用例、转换。
    • 数据层只负责数据存取、网络、缓存。
    • 遵循单向数据流、单一数据源原则。
    • 按 Feature 分模块(而不是全部扔一个文件夹),提高可扩展性。

如果你愿意,我也可以帮你准备一个 具体 Flutter 项目的层次结构模板(目录结构 + 文件抽象 +示例代码),你看要不要?

相关推荐
lqj_本人2 小时前
Flutter与鸿蒙EventChannel事件流通信详解
flutter
lpfasd1232 小时前
Flutter持续健康发展的多维度分析
flutter
GISer_Jing2 小时前
Flutter开发全攻略:从入门到精通
android·前端·flutter
艾小码2 小时前
Vue组件通信不再难!这8种方式让你彻底搞懂父子兄弟传值
前端·javascript·vue.js
lcc1872 小时前
Vue 数据代理
前端·javascript·vue.js
Moment2 小时前
为什么我们从 Python 迁移到 Node.js
前端·后端·node.js
excel2 小时前
📘 全面解析:JavaScript 时间格式化 API 实战指南
前端
咖啡の猫3 小时前
Vue基本路由
前端·vue.js·状态模式