5.5 KiB
5.5 KiB
Flutter 项目规范
严格遵循本文档定义的架构模式、状态管理标准和代码风格。未经授权不得引入新的第三方包或架构模式。优先组合而非继承,业务逻辑不进入 UI 组件。
1. 技术栈
- 语言: Dart(SDK >=3.0.0,严格空安全)
- 框架: Flutter(最新稳定通道)
- 状态管理:
flutter_riverpod(v2.x,注解 + 代码生成) - 路由:
go_router - 网络请求:
dio(配合json_annotation+freezed进行 JSON 序列化) - 数据模型:
freezed+build_runner - 本地存储:
shared_preferences(非敏感偏好)+flutter_secure_storage(令牌) - 依赖注入: Riverpod Providers(不使用 GetIt)
- 国际化:
flutter_localizations(l10n / ARB 格式)
2. 目录结构
采用 特性优先架构(Feature-First),特性内部结合 整洁架构(Clean Architecture) 分层:
lib/
├── main.dart # 应用程序入口(ProviderScope + runApp)
├── app/ # 全局应用配置
│ ├── app.dart # CupertinoApp.router 入口
│ ├── router/ # 路由定义(GoRouter)
│ ├── theme/ # 主题、颜色、排版
│ └── constants/ # 全局常量、API 端点、ICE 配置
├── core/ # 跨特性共享代码
│ ├── network/ # dio 客户端、错误处理
│ ├── proto/ # Protobuf 生成代码(控制指令协议)
│ ├── storage/ # 本地存储辅助工具
│ ├── utils/ # 辅助函数、扩展方法
│ └── widgets/ # 共享 UI 组件(触摸层)
├── features/ # 特性模块
│ ├── auth/ # 登录 / 令牌 / 绑定列表
│ │ ├── data/ # Repository 实现(dio)
│ │ ├── domain/ # 仓库接口、状态模型(freezed)
│ │ └── presentation/ # 控制器、登录对话框
│ └── connection/ # 信令 / WebRTC / 控制面板
│ ├── data/ # 信令客户端、WebRTC、编排器、解码器、录制器
│ ├── domain/ # 信令消息、会话状态(freezed)
│ └── presentation/ # 控制器、设置页、控制页、鉴权对话框
└── l10n/ # 国际化(.arb 文件)
3. 分层职责
表示层(presentation/)
UI 组件 + Riverpod Notifier / AsyncNotifier 控制器。
- 只能通过
ref.watch或ref.listen消费状态。 - 禁止在
onPressed或build()中直接调用 API 或编写业务逻辑。 - 一次性提示通过状态中的
alert字段传递,UI 展示后调用consumeAlert()消费。
领域层(domain/)
纯 Dart 实体(freezed)和仓库接口定义。
- 零 Flutter/UI 依赖(协议模型除外)。
- 状态类命名避免与 Flutter SDK 冲突(如用
ConnectionSessionState而非ConnectionState)。
数据层(data/)
实现仓库接口,通过 dio 处理 API 请求,将 JSON DTO 映射为领域实体。
4. 编码规范
状态管理(Riverpod)
- 使用
@riverpod注解 +build_runner代码生成。 - 会话级控制器(如登录、连接)使用
@Riverpod(keepAlive: true),避免页面切换时销毁。 - 异步操作优先使用
AsyncNotifierProvider,配合AsyncValue(Loading / Data / Error)。 - 业务回调(信令/WebRTC 事件)统一在控制器内映射到状态,不在 UI 层直接持有控制器实例。
数据建模(freezed)
所有数据类/实体必须用 freezed 实现不可变,并配置 JSON 序列化:
@freezed
class SignalMessage with _$SignalMessage {
const SignalMessage._();
const factory SignalMessage({
String? type,
String? payload,
}) = _SignalMessage;
factory SignalMessage.fromJson(Map<String, dynamic> json) =>
_$SignalMessageFromJson(json);
@override
String toString() => jsonEncode(toJson());
}
UI 组件
- 尽可能使用
const构造函数,避免不必要的重建。 - 复杂子树提取为独立私有/公有无状态组件,不要写冗长的内联辅助方法。
- 响应式适配使用
LayoutBuilder/MediaQuery或项目统一的屏幕适配工具。
5. 命名约定
| 类别 | 规范 | 示例 |
|---|---|---|
| 文件/文件夹 | snake_case.dart |
connection_controller.dart |
| 类/枚举 | PascalCase |
ConnectionSessionState |
| 变量/方法 | camelCase |
sendResolutionChange() |
| Provider | 以 Provider 结尾 |
authRepositoryProvider |
| 私有成员 | _ 前缀 |
_handleSignalMessage() |
6. 代码生成
修改或新增带代码生成的模型/控制器后,运行:
# 一次性生成(freezed / json_serializable / riverpod_generator)
dart run build_runner build --delete-conflicting-outputs
# 监听模式
dart run build_runner watch --delete-conflicting-outputs
# 生成国际化(l10n.yaml 已配置)
flutter gen-l10n
7. 完成标准
- 新文件遵循特性优先结构(app / core / features / l10n)。
- 代码为空安全、完全类型化,并进行
const优化。 - 对应创建数据层、领域层和表示层组件。
- 提交前
flutter analyze无 issue;flutter test通过。 - 协议(
.proto/ 信令 JSON)变更需同步 Android / iOS / Web 各端。