# flutter-app **Repository Path**: sliver-ring_admin/flutter-app ## Basic Information - **Project Name**: flutter-app - **Description**: 专为没有技术背景要使用flutter开发APP而打造的快速启动架构,从抖音来的人看这里,直接将仓库地址发给AI即可。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 2 - **Created**: 2026-08-02 - **Last Updated**: 2026-08-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Flutter Starter Template 一套面向“没有技术背景 + 依靠 AI 开发”的 Flutter App 生长骨架。 用户负责描述产品结果,AI 负责架构、编码和技术验收。模板通过唯一 owner、依赖方向、自动守卫、守卫负例和统一验证入口阻止 AI 随意生长;它不是只给程序员阅读的目录示例。 它不是成品 App,也不包含后端、数据库、真实登录、支付、推送或发布配置。 ## 加入交流群 如果你在模板初始化、Flutter 环境或 AI 开发规则方面遇到问题,可以加入 QQ 群交流。 ### QQ 群 群号:`166244138` ![甲壳虫 AI 编程交流 QQ 群二维码](./docs/assets/qq-group-qr.png) 也可以访问 [甲壳虫社区](https://www.openbeetles.com/),获取最新模板、交流入口和项目动态。 ## 当前验证基线 - Flutter 3.44.8 stable - Dart 3.12.2 - Material 3 - Riverpod 3.4.2 - go_router 17.3.0 - flutter_screenutil 5.9.3 - shared_preferences 2.5.5(`SharedPreferencesAsync`) - Dio 5.11.0 - json_annotation 4.12.0 / json_serializable 6.14.1 - build_runner 2.15.1(当前 Flutter stable 可解析上限) - Flutter 官方 ARB / gen_l10n - 目标平台:iOS、Android 上述版本在 2026-08-02 再次 fresh 核对;本机确认 stable 已是最新,不是让未来使用者降级到旧版本。开始新项目时仍须先切到 Flutter stable 并执行 `flutter upgrade`;若 stable 已更新,应使用新的 stable 重新跑完整门禁并更新技术真源。替换状态、路由、尺寸、存储或多语言方案仍属于基础决策,不能只修改依赖版本后继续开发。 ## 快速启动 先准备 Flutter stable,以及目标平台所需的 Xcode 或 Android SDK。然后在本目录运行: ```bash flutter channel stable flutter upgrade flutter --version flutter doctor -v flutter pub get flutter gen-l10n dart run build_runner build flutter devices flutter run -d ``` 如果当前只连接了一个可运行设备,也可以直接执行: ```bash flutter run ``` 启动后可走完这条演示流程: ```text 欢迎页 -> 进入模板 -> 首页 -> 切换明暗主题 -> 退出 -> 欢迎页 ``` “进入模板”和“退出”只修改内存中的演示会话,用于验证 Riverpod 与 go_router 的联动。它不是登录功能,不校验账号、凭据、角色或权限,也不能作为任何安全边界。接入真实登录前必须重新设计服务端认证、授权、凭据存储和失败处理。 ## 目录与唯一 owner 这里仅列出日常开发需要知道的入口;详细规则以 [Flutter 前端架构真源](dev-docs/frontend-architecture.md) 为准。 | 目录或文件 | 职责 | | --- | --- | | `lib/app/` | App 根组件组装 | | `lib/core/routing/app_router.dart` | feature 路由分片聚合、错误页和全局路由组装 | | `lib/core/routing/guards/`、`observers/` | 官方路由守卫与只读导航观察 | | `lib/core/logging/app_log.dart` | 统一日志级别与输出入口 | | `lib/core/errors/` | Result/Failure、统一未知异常上报和 Riverpod 错误策略 | | `lib/core/storage/preferences/` | typed 简单偏好、唯一 Async adapter、命名空间清理和版本迁移 | | `lib/core/network/api/` | Dio 无关的请求、解码、列表/分页与无 data 合同 | | `lib/core/network/config/` | test/production、Base URL、唯一成功码和超时 | | `lib/core/network/dio/` | 唯一允许 import/创建 Dio 的 adapter 与异常映射 | | `lib/core/network/failures/` | 不携带响应正文和 server msg 的 typed 网络失败 | | `lib/core/network/network_provider.dart` | 唯一 ApiClient 注入与释放 | | `lib/features//domain/models/` | 纯 Dart 业务实体、值对象和只读投影;按需创建 | | `lib/features//data/remote/dto/` | 单个接口的请求/响应 JSON DTO;不得越出 data 层 | | `lib/features//data/mappers/` | DTO 到 owner 业务模型的显式转换 | | `lib/features//data/remote/adapters/` | 已登记接口 producer;唯一允许 feature 调用 ApiClient 的位置 | | `dev-docs/business-model-ownership.json` | v3 entity/projection、DTO→mapper→producer 与精确 runtime consumers 的机器真源 | | `lib/app/app_error_fallback.dart` | 只展示 ARB 安全文案的构建错误替换器 | | `lib/core/theme/` | Material 主题与视觉尺寸 token | | `lib/features//application/` | 该 feature 的跨页面 Riverpod 状态 | | `lib/features//application/_contract.dart` | 明确允许跨 feature 使用的 application 公共合同 | | `lib/features//application/rules/` | 纯业务判断,按需创建 | | `lib/features//application/validation/` | feature 字段格式校验,按需创建 | | `lib/features//presentation/navigation/_route_ids.dart` | 该 feature 的稳定 route name/path | | `lib/features//presentation/navigation/_routes.dart` | 该 feature 的 RouteId 与 Page 精确绑定 | | `lib/features//presentation/pages//_page.dart` | 一个可路由业务页;每页固定独立目录 | | `lib/features//presentation/pages//widgets/` | 只服务该页面树的组件,按需创建 | | `lib/features//presentation/widgets/` | 同一 feature 多页面复用的组件,按需创建 | | `lib/shared/` | 已经跨 feature 复用的组件或无业务语义扩展 | | `lib/l10n/*.arb` | 用户可见文案源 | | `test/` | 行为与回归测试 | | `test/page_test_coverage.json` | 每个可路由 Page 的 T2 测试或有效 T3 豁免索引 | | `scripts/check-template-guardrails.mjs` | 目录和禁止写法的自动守卫 | | `scripts/check-template-guardrails.test.mjs` | 守卫自身的持久负例 | | `scripts/validate-template.mjs` | AI 唯一完成验证入口 | | `dev-docs/` | 产品、技术、架构与验收真源 | 页面不能另存一份共享状态或业务模型、临时发明路由、硬编码视觉值或直接写用户可见文案。公共函数必须按语义归属,禁止 `utils/common/helpers/functions` 大杂烩。也不要为还不存在的数据源预建空的 `data/`、`domain/`、repository 或 service 层。 ## 正确使用本地偏好 简单设置不要在页面里直接调用插件。AI 应在对应 feature 的 `application/_preferences.dart` 中声明稳定 key 和窄方法,再由 controller 调用: ```dart const sortOrderKey = PreferenceKey( 'reader.sort_order', StringPreferenceCodec(), ); ``` - 支持 `String`、`bool`、`int`、`double`、`List`,以及显式 JSON object/list/模型 codec。 - 读取返回 `Result`;`null` 只表示未存过。平台失败、类型损坏和 JSON 损坏不会被默认值吞掉。 - 删除使用 typed key;批量清理只能调用 `clearNamespace()`,不能无范围清空全部宿主偏好。 - 每次 schema 变化都增加连续、幂等的 migration step;迁移失败不自动清数据。 - 密码、token、Cookie、私钥、真实登录 session、身份权限、交易和关键记录禁止进入该模块;查询、关系、事务或大对象应改用经确认的数据库/服务端方案。 完整合同和示例实现见 [Flutter 前端架构真源](dev-docs/frontend-architecture.md) 与 `lib/features/settings/application/theme_mode_preferences.dart`。 ## 正确接入一个接口 服务器顶层响应必须统一为 `{"code": 0, "data": ..., "msg": ""}`。普通列表的 `data` 直接是 `[]`;分页列表固定使用: ```json { "code": 0, "data": { "paged": { "page": 1, "pageSize": 20, "total": 0, "totalPages": 0, "hasNext": false, "hasPrevious": false }, "items": [] }, "msg": "" } ``` AI 应先查 `dev-docs/business-model-ownership.json`。DTO 只是接口 JSON 合同:在真实 feature 的 `data/remote/dto/` 定义 `@JsonSerializable()` DTO 和同名测试,运行 `dart run build_runner build` 生成 `.g.dart`;请求 DTO 实现 `ApiRequestModel`。DTO 只能被同 feature data 层消费,并由 `data/mappers/` 转为 `domain/models/` 中的业务模型,application 和页面不得长期持有 DTO。 ```dart Future>> loadArticleItems() { return apiClient.requestMappedList( ApiRequest.get( '/articles', query: const ArticleQueryDto(page: 1, pageSize: 20), ), fromJson: ArticleItemDto.fromJson, mapper: mapArticleItemDtoToArticleItem, ); } Future> logout() { return apiClient.requestVoid(ApiRequest.post('/session/logout')); } ``` 上例中的类型是接入真实文章功能时的命名示意,不是模板预建业务。对象、数组和分页响应分别使用 `requestMappedModel/requestMappedList/requestMappedPaged`;只有标量允许直接使用 `value`,无返回值使用 `requestVoid` 或各方法的 Void 版本。真实调用只能放在同 feature 的 `data/remote/adapters/*_remote_adapter.dart`,application 调用 adapter,页面不接触 client/DTO。每个响应 DTO 必须在 v3 登记表绑定 mapper、唯一 producer 方法和真实 application consumer;GET 和默认 DELETE 只发 query,确需 DELETE body 时使用 `ApiRequest.deleteWithBody`。成功码全项目只能配置一个值,不能同时兼容 0 和 200。 首页和用户中心若展示同一文章列表投影,应共同消费文章 owner contract 暴露的同一个 `ArticleItem`。两个 endpoint 返回 JSON 不同,可以各有 DTO 和 mapper;不得因此创建 `HomeArticleItem` 与 `ProfileArticleItem`。反过来,身份、不变量或数据完整性确实不同,也不能仅凭字段相似强行合并,必须登记新的 projection 和业务理由。 运行真实接口时通过公开客户端配置传入 origin,不把服务端密钥写入 App: ```bash flutter run \ --dart-define=APP_ENV=test \ --dart-define=API_BASE_URL=http://127.0.0.1:8080 \ --dart-define=API_SUCCESS_CODE=0 ``` production 环境只接受 HTTPS。Base URL 只允许 origin;endpoint 必须以 `/` 开头且不能包含域名、query、fragment 或路径穿越。网络层不会自动重试,也不会用 Dio `LogInterceptor` 输出 headers/body;认证、token、刷新、缓存、上传下载和 WebSocket 必须在真实需求出现后另立合同。 ## 正确添加一个 feature 1. 先阅读 [AGENTS.md](AGENTS.md)、[项目边界](dev-docs/project-brief.md)、[产品设计真源](dev-docs/design-system.md) 和 [Flutter 前端架构](dev-docs/frontend-architecture.md),确认新功能仍在当前产品、设计、技术与平台边界内。 2. 先写清用户动作、可见结果、失败状态和不修改的范围,再判断状态只属于一个页面,还是需要跨页面共享。 3. 先按产品能力确定 `feature`,不要把每个页面都拆成一个 feature。新增数据前按业务身份搜索模型登记表;同一实体同一投影复用 owner 模型,跨 feature 只 import owner contract。跨页面状态进入 `application/`;每个路由页创建 `presentation/pages//_page.dart`,页面私有组件放在该 page 的 `widgets/`。 4. 纯业务规则进入 `application/rules/`,字段格式校验进入 `application/validation/`;需要状态、权限、时钟或远端数据的场景使用 application controller,不叫公共 validator。 5. 在本 feature 的 `presentation/navigation/` 同时增加 RouteId record 和 GoRoute;页面目录 `snake_case`、route key `lowerCamelCase`、Page class `UpperCamelCasePage` 必须同名对应。只有首次创建一个带路由的新 feature 时,才由中央集成 owner 在 `app_router.dart` 聚合一次该 feature fragment。 6. 所有新文案先写入 ARB,样式和尺寸复用 Theme 与命名 token;日志只通过 `AppLog`,不得记录敏感信息。可预期失败返回 `Result`,未知异常继续交给统一 reporter,页面不得直接展示异常正文。 7. 同一种语义跳转被两个以上调用方使用,或涉及参数编码、query、`go/push/replace` 栈语义时,封装为目标 feature 的命名导航意图;一次性简单跳转直接使用 RouteId,页面不得写路径字符串。中间件只用 go_router 官方 `onEnter`、redirect、route-level redirect 和 `onExit`,禁止自建 middleware 链。 8. 同 feature 的多个页面真实复用时才提升到 `presentation/widgets/`;两个以上 feature 真实复用且没有业务语义时,才提升到 `lib/shared/widgets/`。简单偏好使用既有 typed store;真实 API 使用既有 ApiClient 和生成模型;查询、关系、事务或大对象出现后再选择数据库,禁止先建空壳。 9. 为每个可路由 Page 更新 `test/page_test_coverage.json`。稳定、可自动化的新行为使用 T2,先观察测试失败再实现;确实不能自动化时才允许写明原因、证据和到期日的 T3。 10. 参数化 Riverpod provider 默认使用 `autoDispose.family`;使用 `ref.keepAlive()` 必须同时登记 `ref.onDispose()` 并有生命周期测试。根 ProviderScope 已关闭 Riverpod 默认错误重试;feature 只有在操作可安全重试并有测试时才能自行增加重试。最后运行本 README 的完整验证命令。 AI_TEMPLATE_INIT.md 是复制模板后的必做文件,不是可选参考。该文件存在时,模板处于“未初始化”状态,AI 必须先按 [AI_TEMPLATE_INIT.md](AI_TEMPLATE_INIT.md) 确认产品、首个闭环、平台身份、设计、数据与高影响边界。用户只确认产品事实,技术命名、owner、实现和验收方法由 AI 推荐。 `dev-docs/design-system.md` 是初始化后持续维护的唯一产品设计真源。初始化完成时,AI 必须先写清设计依据、适用范围、视觉语言和验收边界,再将 Theme/Token 作为运行时投影;[项目边界](dev-docs/project-brief.md) 顶部只保留设计摘要和链接。随后更新名称、package/ID、平台入口与 ARB 标题,处理模板演示内容,运行目标平台统一门禁,最后才删除 `AI_TEMPLATE_INIT.md`。守卫会阻断摘要缺项、模板设计冒充已初始化、主色投影漂移、默认身份残留和已登记 owner 漂移;设备视觉与冷启动仍需单独验收。 dev-docs 在用户项目中必须保持本地私有。模板仓库为了让 AI 拿到完整初始化真源会公开跟踪该目录;克隆后,AI 必须在初始化末尾先确认 `origin` 已切换到用户仓库或被移除,再运行 `node scripts/privatize-dev-docs.mjs`。脚本会保留本地文件、向根 `.gitignore` 写入 `/dev-docs/`,并从主 Git 索引取消跟踪。只有 `git ls-files dev-docs` 无输出且 `git check-ignore dev-docs/project-brief.md` 成功,才允许首次提交用户项目。内部资料需要跨设备保存时,应使用用户确认的私有备份,不能重新强制加入业务仓库。 平台 ID 与展示名不靠 AI 手工硬换:先激活当前最新版 `change_app_package_name` 和 `rename`,分别完成平台 package/MainActivity 迁移与 App 名称修改;Dart package/import、ARB、主题、日志和偏好 namespace 由 AI 补齐,最终以守卫和构建结果为准。 ## 不要手改生成物 以下内容由 Flutter、Dart、依赖解析器或平台工具生成,应修改源文件后重新生成: - `lib/l10n/app_localizations*.dart`:修改 `lib/l10n/*.arb` 后运行 `flutter gen-l10n`。 - `**/*.g.dart`:修改对应 `@JsonSerializable()` 源模型后运行 `dart run build_runner build`,业务代码只通过同文件的 `part` 使用生成物。 - `.dart_tool/`、`build/`、`coverage/`:本地缓存或构建输出,不作为源码维护。 - `ios/Flutter/Generated.xcconfig`、`ios/Flutter/flutter_export_environment.sh`、`ios/Flutter/ephemeral/`。 - iOS / Android 的 `GeneratedPluginRegistrant*`。 - `pubspec.lock`:通过 `pubspec.yaml` 和 `flutter pub get` 更新,不直接编辑解析结果。 `ios/` 与 `android/` 中并非所有文件都是生成物。接入平台能力时应先找到对应源配置或原生入口,不能用“全部重生成”覆盖已有修改。 ## 唯一验证入口 Android 项目在根目录只需要运行: ```bash node scripts/validate-template.mjs --build=android ``` 可选构建目标: ```bash node scripts/validate-template.mjs --build=ios node scripts/validate-template.mjs --build=all node scripts/validate-template.mjs --build=none ``` 脚本按 DEP、GEN、GEN-JSON、FORMAT、GUARD、GUARD-SELFTEST、ANALYZE、TEST、BUILD 分层输出;依赖解析固定使用官方 pub.dev,避免滞后镜像迫使模板降级;会解析实际完成的非跳过测试数,并在中文路径触发 Flutter analyze 的 LSP 截断时自动用纯英文临时副本复核。`--build=none` 会明确输出 `UNVERIFIED`,不能作为移动端构建证据。 完成自动检查后,还应在可用模拟器或真机上走完欢迎页、进入、主题切换和退出,并检查窄屏、大屏与系统字体放大。自动门禁不能替代真机、签名、商店、真实后端或生产安全验收。 ## 平台边界 - iOS:模板包含 iOS 工程;模拟器构建不代表签名、真机或 App Store 已就绪。 - Android:模板包含 Android 工程;debug APK 构建不代表签名、真机兼容或应用商店已就绪。 - 鸿蒙:不在当前支持范围内。Flutter 官方主线不能被当作纯血鸿蒙的直接第三平台;若产品必须支持鸿蒙,应先独立验证目标 Flutter 版本、插件和厂商 SDK,或重新选择平台路线,不能在本模板里顺手加入兼容分支。 真实设备、签名、隐私合规、商店审核、真实后端、真实认证和生产安全均需要单独验收。 ## 项目真源 - [内部开发真源索引](dev-docs/README.md) - [项目边界](dev-docs/project-brief.md) - [技术选型](dev-docs/technical-selection.md) - [架构真源](dev-docs/architecture.md) - [Flutter 前端架构](dev-docs/frontend-architecture.md) - [产品设计真源](dev-docs/design-system.md) - [验收真源](dev-docs/acceptance.md) ## 许可证 本模板采用 [MIT License](LICENSE)。