Initial Flutter project structure、
This commit is contained in:
@@ -0,0 +1,802 @@
|
||||
# 常见 App 项目结构
|
||||
|
||||
Flutter 项目里,真正主要写代码的是 `lib/`。一个常见、可维护的 App 结构通常不是按“页面类型”乱放,而是按“应用层级 + 功能模块”来组织。
|
||||
|
||||
推荐结构大概是这样:
|
||||
|
||||
```text
|
||||
lib/
|
||||
main.dart
|
||||
|
||||
app/
|
||||
app.dart
|
||||
router.dart
|
||||
theme.dart
|
||||
|
||||
core/
|
||||
config/
|
||||
constants/
|
||||
network/
|
||||
storage/
|
||||
errors/
|
||||
utils/
|
||||
|
||||
features/
|
||||
auth/
|
||||
data/
|
||||
domain/
|
||||
presentation/
|
||||
|
||||
home/
|
||||
data/
|
||||
domain/
|
||||
presentation/
|
||||
|
||||
profile/
|
||||
data/
|
||||
domain/
|
||||
presentation/
|
||||
|
||||
shared/
|
||||
widgets/
|
||||
models/
|
||||
extensions/
|
||||
|
||||
generated/
|
||||
```
|
||||
|
||||
这是一种比较适合中大型 App 的结构。小项目可以简化。
|
||||
|
||||
## `main.dart`
|
||||
|
||||
应用入口。
|
||||
|
||||
通常只做很少的事情:
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
runApp(const App());
|
||||
}
|
||||
```
|
||||
|
||||
如果项目复杂一点,可能还会做:
|
||||
|
||||
- 初始化 Flutter 绑定
|
||||
- 初始化本地存储
|
||||
- 初始化日志
|
||||
- 初始化 Firebase
|
||||
- 初始化依赖注入
|
||||
- 捕获全局异常
|
||||
|
||||
例如:
|
||||
|
||||
```dart
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
runApp(const App());
|
||||
}
|
||||
```
|
||||
|
||||
原则是:`main.dart` 不应该写页面 UI,也不应该堆业务逻辑。
|
||||
|
||||
## `app/`
|
||||
|
||||
放整个 App 级别的配置。
|
||||
|
||||
常见内容:
|
||||
|
||||
```text
|
||||
app/
|
||||
app.dart
|
||||
router.dart
|
||||
theme.dart
|
||||
```
|
||||
|
||||
### `app.dart`
|
||||
|
||||
放根组件,一般是 `MaterialApp` 或 `MaterialApp.router`。
|
||||
|
||||
例如:
|
||||
|
||||
```dart
|
||||
class App extends StatelessWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Patbond',
|
||||
theme: AppTheme.light,
|
||||
home: const HomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `router.dart`
|
||||
|
||||
放路由配置。
|
||||
|
||||
如果页面少,可以先不用这个文件。
|
||||
|
||||
如果后面页面多,建议用 `go_router`,比如:
|
||||
|
||||
```text
|
||||
/login
|
||||
/home
|
||||
/profile
|
||||
/settings
|
||||
```
|
||||
|
||||
### `theme.dart`
|
||||
|
||||
放主题配置,例如:
|
||||
|
||||
- 主色
|
||||
- 字体
|
||||
- 按钮样式
|
||||
- AppBar 样式
|
||||
- 输入框样式
|
||||
- 明暗主题
|
||||
|
||||
## `core/`
|
||||
|
||||
放“全局基础能力”。
|
||||
|
||||
这些东西通常不属于某个具体页面或业务模块,而是整个 App 都可能用。
|
||||
|
||||
常见结构:
|
||||
|
||||
```text
|
||||
core/
|
||||
config/
|
||||
constants/
|
||||
network/
|
||||
storage/
|
||||
errors/
|
||||
utils/
|
||||
```
|
||||
|
||||
### `core/config/`
|
||||
|
||||
放环境配置,例如:
|
||||
|
||||
```text
|
||||
dev
|
||||
test
|
||||
prod
|
||||
```
|
||||
|
||||
比如:
|
||||
|
||||
```dart
|
||||
class AppConfig {
|
||||
static const apiBaseUrl = 'https://api.example.com';
|
||||
}
|
||||
```
|
||||
|
||||
### `core/constants/`
|
||||
|
||||
放全局常量,例如:
|
||||
|
||||
```dart
|
||||
class AppConstants {
|
||||
static const appName = 'Patbond';
|
||||
}
|
||||
```
|
||||
|
||||
可以包括:
|
||||
|
||||
- App 名称
|
||||
- 默认分页大小
|
||||
- 缓存 key
|
||||
- 接口超时时间
|
||||
- 正则表达式
|
||||
|
||||
### `core/network/`
|
||||
|
||||
放网络请求相关代码,例如:
|
||||
|
||||
```text
|
||||
network/
|
||||
api_client.dart
|
||||
api_response.dart
|
||||
interceptors.dart
|
||||
```
|
||||
|
||||
如果用 `dio`,通常会在这里封装:
|
||||
|
||||
- baseUrl
|
||||
- 请求头
|
||||
- token
|
||||
- 错误处理
|
||||
- 超时
|
||||
- 日志拦截器
|
||||
|
||||
### `core/storage/`
|
||||
|
||||
放本地存储封装,例如:
|
||||
|
||||
- SharedPreferences
|
||||
- SecureStorage
|
||||
- Hive
|
||||
- SQLite
|
||||
|
||||
比如:
|
||||
|
||||
```text
|
||||
storage/
|
||||
local_storage.dart
|
||||
secure_storage.dart
|
||||
```
|
||||
|
||||
### `core/errors/`
|
||||
|
||||
放错误类型和异常处理。
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
errors/
|
||||
app_exception.dart
|
||||
failure.dart
|
||||
```
|
||||
|
||||
### `core/utils/`
|
||||
|
||||
放通用工具方法。
|
||||
|
||||
例如:
|
||||
|
||||
- 日期格式化
|
||||
- 金额格式化
|
||||
- 防抖
|
||||
- 校验函数
|
||||
- 文件大小转换
|
||||
|
||||
注意:不要把业务逻辑都塞进 `utils/`,否则它会变成垃圾桶目录。
|
||||
|
||||
## `features/`
|
||||
|
||||
这是业务模块目录,也是实际开发最常动的地方。
|
||||
|
||||
一个功能一个文件夹,比如:
|
||||
|
||||
```text
|
||||
features/
|
||||
auth/
|
||||
home/
|
||||
profile/
|
||||
order/
|
||||
settings/
|
||||
```
|
||||
|
||||
例如登录注册相关都放在:
|
||||
|
||||
```text
|
||||
features/auth/
|
||||
```
|
||||
|
||||
首页相关放在:
|
||||
|
||||
```text
|
||||
features/home/
|
||||
```
|
||||
|
||||
个人资料放在:
|
||||
|
||||
```text
|
||||
features/profile/
|
||||
```
|
||||
|
||||
## Feature 内部结构
|
||||
|
||||
中大型项目里,一个 feature 常见会分成三层:
|
||||
|
||||
```text
|
||||
features/auth/
|
||||
data/
|
||||
domain/
|
||||
presentation/
|
||||
```
|
||||
|
||||
这套结构接近 Clean Architecture,但不一定要一开始就完整照搬。
|
||||
|
||||
### `data/`
|
||||
|
||||
负责数据来源。
|
||||
|
||||
常见内容:
|
||||
|
||||
```text
|
||||
data/
|
||||
models/
|
||||
repositories/
|
||||
services/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
features/auth/data/
|
||||
models/
|
||||
user_model.dart
|
||||
login_request.dart
|
||||
services/
|
||||
auth_api_service.dart
|
||||
repositories/
|
||||
auth_repository_impl.dart
|
||||
```
|
||||
|
||||
这里一般处理:
|
||||
|
||||
- API 请求
|
||||
- JSON 解析
|
||||
- 本地缓存
|
||||
- 数据模型转换
|
||||
|
||||
例如 `UserModel.fromJson()` 通常就在 `data/models/`。
|
||||
|
||||
### `domain/`
|
||||
|
||||
负责业务规则。
|
||||
|
||||
常见内容:
|
||||
|
||||
```text
|
||||
domain/
|
||||
entities/
|
||||
repositories/
|
||||
usecases/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
features/auth/domain/
|
||||
entities/
|
||||
user.dart
|
||||
repositories/
|
||||
auth_repository.dart
|
||||
usecases/
|
||||
login.dart
|
||||
logout.dart
|
||||
```
|
||||
|
||||
`domain` 理论上不关心数据来自哪里。
|
||||
|
||||
它只关心业务是什么。
|
||||
|
||||
例如:
|
||||
|
||||
```dart
|
||||
abstract class AuthRepository {
|
||||
Future<User> login(String email, String password);
|
||||
}
|
||||
```
|
||||
|
||||
然后 `data` 层去实现它。
|
||||
|
||||
小项目可以先不拆 `domain/`,直接用 `data + presentation` 就够了。
|
||||
|
||||
### `presentation/`
|
||||
|
||||
负责 UI 和页面状态。
|
||||
|
||||
常见内容:
|
||||
|
||||
```text
|
||||
presentation/
|
||||
pages/
|
||||
widgets/
|
||||
controllers/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
features/auth/presentation/
|
||||
pages/
|
||||
login_page.dart
|
||||
register_page.dart
|
||||
widgets/
|
||||
login_form.dart
|
||||
controllers/
|
||||
login_controller.dart
|
||||
```
|
||||
|
||||
这里一般放:
|
||||
|
||||
- 页面
|
||||
- 组件
|
||||
- ViewModel / Controller / Bloc / Provider
|
||||
- 页面状态类
|
||||
|
||||
如果用 Riverpod,可能是:
|
||||
|
||||
```text
|
||||
login_controller.dart
|
||||
auth_provider.dart
|
||||
```
|
||||
|
||||
如果用 Bloc,可能是:
|
||||
|
||||
```text
|
||||
auth_bloc.dart
|
||||
auth_event.dart
|
||||
auth_state.dart
|
||||
```
|
||||
|
||||
## `shared/`
|
||||
|
||||
放跨模块复用的 UI 或类型。
|
||||
|
||||
常见结构:
|
||||
|
||||
```text
|
||||
shared/
|
||||
widgets/
|
||||
models/
|
||||
extensions/
|
||||
```
|
||||
|
||||
### `shared/widgets/`
|
||||
|
||||
通用组件,例如:
|
||||
|
||||
```text
|
||||
primary_button.dart
|
||||
empty_view.dart
|
||||
loading_view.dart
|
||||
app_text_field.dart
|
||||
network_image_view.dart
|
||||
```
|
||||
|
||||
这些组件不属于某个具体业务模块,多个页面都能用。
|
||||
|
||||
### `shared/models/`
|
||||
|
||||
通用模型,例如:
|
||||
|
||||
```text
|
||||
pagination.dart
|
||||
option_item.dart
|
||||
result.dart
|
||||
```
|
||||
|
||||
### `shared/extensions/`
|
||||
|
||||
Dart 扩展方法,例如:
|
||||
|
||||
```dart
|
||||
extension StringX on String {
|
||||
bool get isBlank => trim().isEmpty;
|
||||
}
|
||||
```
|
||||
|
||||
## `generated/`
|
||||
|
||||
放自动生成代码。
|
||||
|
||||
例如:
|
||||
|
||||
- 国际化生成文件
|
||||
- 路由生成文件
|
||||
- JSON 序列化生成文件
|
||||
- Assets 生成文件
|
||||
|
||||
这个目录通常不要手写业务逻辑。
|
||||
|
||||
## 资源目录
|
||||
|
||||
Flutter 资源通常不放在 `lib/` 里,而是放在项目根目录。
|
||||
|
||||
常见结构:
|
||||
|
||||
```text
|
||||
assets/
|
||||
images/
|
||||
icons/
|
||||
fonts/
|
||||
lottie/
|
||||
```
|
||||
|
||||
然后在 `pubspec.yaml` 注册:
|
||||
|
||||
```yaml
|
||||
flutter:
|
||||
assets:
|
||||
- assets/images/
|
||||
- assets/icons/
|
||||
- assets/lottie/
|
||||
|
||||
fonts:
|
||||
- family: Inter
|
||||
fonts:
|
||||
- asset: assets/fonts/Inter-Regular.ttf
|
||||
- asset: assets/fonts/Inter-Bold.ttf
|
||||
weight: 700
|
||||
```
|
||||
|
||||
## 测试目录
|
||||
|
||||
常见测试结构:
|
||||
|
||||
```text
|
||||
test/
|
||||
features/
|
||||
auth/
|
||||
login_controller_test.dart
|
||||
core/
|
||||
network/
|
||||
api_client_test.dart
|
||||
```
|
||||
|
||||
测试可以按 `lib/` 的结构对应放。
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
lib/features/auth/presentation/controllers/login_controller.dart
|
||||
```
|
||||
|
||||
对应测试:
|
||||
|
||||
```text
|
||||
test/features/auth/presentation/controllers/login_controller_test.dart
|
||||
```
|
||||
|
||||
## 小项目推荐结构
|
||||
|
||||
如果项目刚开始,不建议一上来就搞得太复杂。
|
||||
|
||||
当前项目可以先用这个结构:
|
||||
|
||||
```text
|
||||
lib/
|
||||
main.dart
|
||||
|
||||
app/
|
||||
app.dart
|
||||
theme.dart
|
||||
|
||||
features/
|
||||
home/
|
||||
home_page.dart
|
||||
|
||||
shared/
|
||||
widgets/
|
||||
```
|
||||
|
||||
这就够了。
|
||||
|
||||
等有登录、接口、缓存、状态管理之后,再扩展成:
|
||||
|
||||
```text
|
||||
lib/
|
||||
main.dart
|
||||
|
||||
app/
|
||||
app.dart
|
||||
router.dart
|
||||
theme.dart
|
||||
|
||||
core/
|
||||
network/
|
||||
storage/
|
||||
constants/
|
||||
utils/
|
||||
|
||||
features/
|
||||
auth/
|
||||
data/
|
||||
presentation/
|
||||
|
||||
home/
|
||||
presentation/
|
||||
|
||||
profile/
|
||||
data/
|
||||
presentation/
|
||||
|
||||
shared/
|
||||
widgets/
|
||||
extensions/
|
||||
```
|
||||
|
||||
## 不建议一开始这样做
|
||||
|
||||
不建议刚开始就建一堆空目录:
|
||||
|
||||
```text
|
||||
core/
|
||||
errors/
|
||||
failures/
|
||||
usecases/
|
||||
validators/
|
||||
services/
|
||||
managers/
|
||||
helpers/
|
||||
providers/
|
||||
mixins/
|
||||
```
|
||||
|
||||
这样看起来很专业,但实际开发时容易变成:
|
||||
|
||||
- 不知道代码该放哪
|
||||
- 文件很多但内容很少
|
||||
- 过度抽象
|
||||
- 后期维护成本高
|
||||
|
||||
最好的做法是:随着需求出现再拆。
|
||||
|
||||
## 常见页面模块示例
|
||||
|
||||
假设要做一个带登录、首页、个人中心的 App,可以这样组织:
|
||||
|
||||
```text
|
||||
lib/
|
||||
main.dart
|
||||
|
||||
app/
|
||||
app.dart
|
||||
router.dart
|
||||
theme.dart
|
||||
|
||||
core/
|
||||
network/
|
||||
api_client.dart
|
||||
storage/
|
||||
token_storage.dart
|
||||
constants/
|
||||
app_constants.dart
|
||||
|
||||
features/
|
||||
auth/
|
||||
data/
|
||||
auth_api.dart
|
||||
auth_repository.dart
|
||||
presentation/
|
||||
login_page.dart
|
||||
register_page.dart
|
||||
auth_controller.dart
|
||||
|
||||
home/
|
||||
presentation/
|
||||
home_page.dart
|
||||
home_controller.dart
|
||||
widgets/
|
||||
home_card.dart
|
||||
|
||||
profile/
|
||||
data/
|
||||
profile_api.dart
|
||||
profile_repository.dart
|
||||
presentation/
|
||||
profile_page.dart
|
||||
edit_profile_page.dart
|
||||
|
||||
shared/
|
||||
widgets/
|
||||
primary_button.dart
|
||||
app_text_field.dart
|
||||
loading_view.dart
|
||||
empty_view.dart
|
||||
```
|
||||
|
||||
## 常见开发流程
|
||||
|
||||
一般做 App 时,顺序可以是:
|
||||
|
||||
1. 搭好 `main.dart` 和 `app/app.dart`
|
||||
2. 建立主题 `app/theme.dart`
|
||||
3. 创建首页 `features/home/home_page.dart`
|
||||
4. 如果有多页面,再加 `app/router.dart`
|
||||
5. 如果有接口,再加 `core/network/`
|
||||
6. 如果有登录 token,再加 `core/storage/`
|
||||
7. 每做一个功能,就在 `features/` 下新建一个模块
|
||||
8. 多个模块共用的组件,再提到 `shared/widgets/`
|
||||
|
||||
## 放代码时的判断标准
|
||||
|
||||
页面放哪里:
|
||||
|
||||
```text
|
||||
features/模块名/presentation/
|
||||
```
|
||||
|
||||
例如登录页:
|
||||
|
||||
```text
|
||||
features/auth/presentation/login_page.dart
|
||||
```
|
||||
|
||||
接口请求放哪里:
|
||||
|
||||
```text
|
||||
features/模块名/data/
|
||||
```
|
||||
|
||||
例如登录接口:
|
||||
|
||||
```text
|
||||
features/auth/data/auth_api.dart
|
||||
```
|
||||
|
||||
多个模块共用的网络封装放哪里:
|
||||
|
||||
```text
|
||||
core/network/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
core/network/api_client.dart
|
||||
```
|
||||
|
||||
多个页面共用的按钮放哪里:
|
||||
|
||||
```text
|
||||
shared/widgets/
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
shared/widgets/primary_button.dart
|
||||
```
|
||||
|
||||
App 主题放哪里:
|
||||
|
||||
```text
|
||||
app/theme.dart
|
||||
```
|
||||
|
||||
路由放哪里:
|
||||
|
||||
```text
|
||||
app/router.dart
|
||||
```
|
||||
|
||||
常量放哪里:
|
||||
|
||||
```text
|
||||
core/constants/
|
||||
```
|
||||
|
||||
图片放哪里:
|
||||
|
||||
```text
|
||||
assets/images/
|
||||
```
|
||||
|
||||
## 对当前项目的建议
|
||||
|
||||
现在最适合从这个结构开始:
|
||||
|
||||
```text
|
||||
lib/
|
||||
main.dart
|
||||
app/
|
||||
app.dart
|
||||
theme.dart
|
||||
features/
|
||||
home/
|
||||
home_page.dart
|
||||
shared/
|
||||
widgets/
|
||||
```
|
||||
|
||||
等开始做真实功能,比如登录、个人中心、业务列表,再扩展成:
|
||||
|
||||
```text
|
||||
features/
|
||||
auth/
|
||||
profile/
|
||||
bond/
|
||||
settings/
|
||||
```
|
||||
|
||||
如果只是练手或做 MVP,不要过早引入完整 Clean Architecture。先保持简单,把页面跑起来、流程走通,再根据复杂度拆分。
|
||||
Reference in New Issue
Block a user