> 技术文档 > Flutter 完全组件化的项目结构设计实践

Flutter 完全组件化的项目结构设计实践


Flutter 完全组件化的项目结构设计实践

在做 Flutter 项目的时候,随着业务不断扩展,如果所有代码都堆在 lib/ 目录里,后期维护会越来越痛苦。组件化(Componentization) 是一种常见的解决方案,它能让项目更清晰、更易扩展,团队协作也会更高效。本文结合实践,分享一种 Flutter 完全组件化的项目结构设计方案


为什么要组件化?

  • 高内聚,低耦合:每个模块(feature)独立,边界清晰。
  • 多人协作:不同的功能模块可以交给不同的开发同学,互不干扰。
  • 可复用性:部分模块可以直接复用到其他项目中。
  • 可维护性:改动时只需要关注单个模块,降低风险。

顶层目录结构

假设我们的项目叫 my_app,整体结构可以这样设计:

my_app/
├── apps/ # 主应用(App 容器)
│ └── main_app/ # 真正运行的壳工程
├── core/ # 核心基础层(工具 & SDK)
│ ├── network/ # 网络封装(dio/http)
│ ├── database/ # 本地存储(sqflite/hive)
│ ├── common_ui/ # 公共UI组件(按钮、弹窗、空页面)
│ ├── utils/ # 工具类(日志、加密、日期)
│ └── theme/ # 全局主题(颜色、文字样式)
├── features/ # 各业务功能模块
│ ├── home/ # 首页
│ ├── video/ # 视频模块(短视频/播放器)
│ ├── chat/ # 聊天模块
│ └── profile/ # 用户中心
├── shared/ # 跨模块共享的模型、服务
│ ├── models/ # 数据实体
│ └── services/ # 公共 Service(用户、配置、埋点)
├── plugins/ # 自研 Flutter 插件(原生能力)
│ ├── photo_picker/ # 相册选择插件
│ └── short_video_player # 短视频播放器插件
├── pubspec.yaml # 顶层依赖管理
└── README.md


Feature 模块内部结构

features/video/ 模块为例:

video/
├── lib/
│ ├── src/
│ │ ├── pages/ # 页面
│ │ ├── widgets/ # 模块内私有 widget
│ │ ├── controllers/ # 状态管理(GetX/Bloc)
│ │ ├── services/ # 数据仓库(repository)
│ │ └── models/ # 模块内的数据模型
│ └── video.dart # 对外暴露的统一入口(类似 index.dart)
├── pubspec.yaml # 模块独立依赖

设计要点:

  • 模块内自成体系,拥有页面、状态、数据。
  • 只暴露 video.dart 给外部使用,内部实现不对外开放。
  • 可以被其他项目直接引入复用。

模块间通信方式

1.路由解耦(基于 GetX)
使用 GetX 的命名路由来统一管理,避免模块间直接依赖页面类。
apps/main_app 中维护一个全局路由表,例如:
// app_routes.dart

 class AppRoutes { static const home = \'/home\'; static const videoDetail = \'/videoDetail\'; static const chat = \'/chat\'; static const profile = \'/profile\'; }

路由配置集中在 GetMaterialApp 中:
// main.dart

import \'package:get/get.dart\';import \'app_routes.dart\';void main() { runApp( GetMaterialApp( initialRoute: AppRoutes.home, getPages: [ GetPage(name: AppRoutes.home, page: () => const HomePage()), GetPage(name: AppRoutes.videoDetail, page: () => const VideoDetailPage()), GetPage(name: AppRoutes.chat, page: () => const ChatPage()), GetPage(name: AppRoutes.profile, page: () => const ProfilePage()), ], ), );}

业务模块跳转时,只需要依赖路由常量,而不是直接依赖页面类:

Get.toNamed(\'${AppRoutes.videoDetail}?id=$videoId\');

这样一来,features/video 模块的内部页面不会被外部直接 import,达到解耦目的。
2. 数据传递
使用 Get.arguments 或事件总线(EventBus/Stream/RxBus)来传递参数,而不是直接依赖模块。

// 跳转时传参

Get.toNamed(AppRoutes.videoDetail, arguments: {\'id\': videoId});

// 接收参数

final args = Get.arguments as Map;final videoId = args[\'id\'];

3.共享数据
放在 shared/ 或 core/services/ 中,使用 Get.find() 获取,避免 feature 之间直接耦合。


依赖管理策略
•每个 feature 拥有独立的 pubspec.yaml,自行管理依赖。
•模块之间禁止直接 import,只能依赖 core 和 shared。
•顶层 pubspec.yaml 使用 dependency_overrides 来统一第三方依赖版本。


开发流程
1.新需求 → 新建 features/xxx 模块。
2.在 apps/main_app 中集成对应模块。
3.公共逻辑沉淀到 core 或 shared,避免重复。
4.原生能力统一封装到 plugins/,避免业务直接写 platform channel。


组件化带来的好处
•团队协作更高效:模块独立,互不干扰。
•扩展性强:新业务只需新增模块,不会污染现有代码。
•维护成本低:定位 bug 或修改逻辑时,只需关注单一模块。
•跨项目可复用:一些业务模块或插件可以直接抽出来独立使用。


模块依赖关系图
Flutter 完全组件化的项目结构设计实践

这张图的含义:
•main_app 是壳应用,依赖所有 features。
•各个 features 只能依赖 core 和 shared,不能互相依赖。
•插件 plugins 可以被某些 feature 调用,但也只依赖 core 公共能力。


总结

组件化不是 Flutter 独有的概念,但在中大型 Flutter 项目中,它能带来巨大的维护优势。本文给出的结构是一种通用的实践方案,你可以根据团队规模和业务复杂度,灵活调整。