Skip to content

Flutter 完整项目承接清单

完整承接 Flutter 项目,不是从写第一个页面开始,而是从确认业务边界、平台边界、工程边界开始。页面能跑只是第一步,真正可交付的项目还要能配置环境、联调接口、处理异常、打包发布、排查线上问题,并让后续开发者能继续维护。

这份清单按真实项目推进顺序组织:先判断项目能不能做,再确定架构和目录,再落到页面、接口、状态、测试、发布和线上运维。

接项目先问清楚什么

开始编码前,至少确认这些问题:

问题为什么重要
目标平台Android、iOS、Web、桌面能力差异很大,插件和发布链路不同
核心用户流程决定页面、路由、状态和接口优先级
账号体系登录、刷新 token、权限、游客模式会影响全局架构
接口形态REST、GraphQL、WebSocket、文件上传、分页和错误码会影响数据层
离线要求只缓存列表,还是要支持离线创建、编辑、同步
设备能力相机、定位、蓝牙、推送、支付、分享都涉及原生配置
多环境dev、test、staging、prod 的域名、证书、日志和开关必须隔离
发布渠道应用商店、企业分发、测试平台、灰度发布的要求不同
质量要求崩溃率、启动速度、包体大小、弱网体验、低端机流畅度

如果这些问题没有答案,项目后面很容易出现“页面写完了,但不能上线”的情况。

从需求拆到页面和数据

拿到需求后,可以按四层拆:

层次拆什么例子
业务流程用户从哪里进入、完成什么动作、失败后怎么办登录 -> 待办列表 -> 新建 -> 同步成功
页面结构需要哪些页面、弹窗、空状态、错误状态登录页、列表页、详情页、编辑页
数据模型页面需要什么数据,接口返回什么数据,本地保存什么数据TaskDtoTaskTaskViewState
异常分支网络失败、权限不足、数据为空、重复提交怎么处理保留缓存、提示重试、禁用按钮

一个简单待办项目可以这样拆:

功能页面数据状态
登录登录页账号、密码、token、用户信息输入中、提交中、成功、失败
列表待办列表页待办列表、分页游标、筛选条件加载中、成功、空数据、刷新中、加载更多失败
详情待办详情页待办详情、操作权限加载中、成功、不存在、无权限
编辑新建/编辑页表单字段、草稿、校验错误未修改、已修改、保存中、保存失败
离线后台同步待同步队列、失败原因、重试次数等待同步、同步中、冲突、已完成

拆到这个程度后,开发顺序会清晰很多:先做页面骨架和假数据,再接接口,再补缓存、错误和发布链路。

推荐工程结构

中小型项目可以先使用特性分组,避免所有页面、模型、接口堆在同一层。

text
lib/
  main.dart
  app.dart
  bootstrap.dart
  core/
    config/
    error/
    logging/
    network/
    storage/
    security/
  shared/
    theme/
    widgets/
    utils/
  features/
    auth/
      presentation/
      application/
      data/
      domain/
    task/
      presentation/
      application/
      data/
      domain/

几个关键文件的职责:

文件或目录职责
main.dart程序入口,只做最少启动工作
bootstrap.dart初始化环境、日志、依赖注入、错误捕获
app.dart根 Widget、主题、路由、国际化入口
core/config多环境配置、接口域名、功能开关
core/networkHTTP Client、拦截器、超时、错误映射
core/storage安全存储、偏好、本地数据库封装
features/*/domain业务实体、规则、Repository 抽象
features/*/dataDTO、API、缓存、Repository 实现
features/*/application用例编排、状态管理、页面命令
features/*/presentationPage、Widget、ViewState

初学者最容易犯的错误,是页面直接调用 HTTP、直接读写本地存储、直接处理 token、直接拼接错误文案。项目小的时候看起来快,功能一多就会变成每个页面都有一套重复逻辑。

启动入口和全局初始化

入口要尽量稳定。推荐把初始化和根组件分开:

dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final appContext = await bootstrap();
  runApp(App(appContext: appContext));
}

bootstrap 常见职责:

  • 加载环境配置,例如接口域名、日志级别、功能开关。
  • 初始化本地存储、数据库、崩溃收集、日志系统。
  • 配置网络客户端、请求拦截器、token 刷新。
  • 注册依赖,例如 Repository、Service、状态对象工厂。
  • 捕获 Flutter 和 Dart 异常,把异常接入日志和崩溃平台。

不要在 build 里做这些事。根组件可以因为主题、语言、登录状态变化而重建,但全局初始化应该有明确入口和生命周期。

多环境配置

真实项目至少区分开发、测试和生产环境。常见做法是用 --dart-define 传入环境:

bash
flutter run --dart-define=APP_ENV=dev
flutter build apk --release --dart-define=APP_ENV=prod
flutter build ipa --release --dart-define=APP_ENV=prod

配置里通常包含:

配置示例注意点
接口域名https://api.example.com不要把测试域名打进生产包
日志级别debug、info、error生产环境避免输出敏感信息
功能开关是否开启新页面、新流程要有默认值和回滚策略
第三方 Key地图、推送、统计区分平台和环境,避免泄露
证书策略HTTPS、证书锁定谨慎处理测试证书和生产证书

配置错误会导致很隐蔽的问题:登录到测试环境、支付走错商户、日志上报到错误项目、生产包打开实验功能。发布前必须有环境核对步骤。

状态管理怎么选

状态管理库不是越复杂越好。先按状态范围判断:

状态范围例子适合方式
组件内部开关、Tab、动画进度、输入框焦点StatefulWidgetValueNotifier
页面级列表、详情、表单提交、分页Controller、ChangeNotifier、Riverpod、Bloc
跨页面登录用户、购物车、全局配置、权限全局状态容器或依赖注入
持久化token、缓存、用户偏好、草稿本地存储或数据库

选型时看三个指标:

  1. 团队是否能理解和维护。
  2. 页面状态是否能被清楚表达和测试。
  3. 异步请求、错误、取消订阅、资源释放是否有统一写法。

初学阶段可以先用 StatefulWidget + Repository 跑通,再逐步引入更清晰的状态对象。项目变大后,不要让一个页面里的状态对象同时负责 UI、接口、缓存、导航和埋点。

页面开发标准

每个页面至少要有这些状态:

状态说明
首次加载进入页面时的数据加载
成功内容正常展示业务数据
空数据没有数据时给出下一步动作
失败展示可理解错误和重试入口
刷新中保留旧数据,同时显示刷新状态
提交中防止重复点击,必要时显示进度
权限不足说明原因,给出返回、申请或登录入口

页面代码要避免:

  • build 里发请求。
  • 页面直接解析 HTTP 状态码。
  • 页面直接操作数据库。
  • 每个按钮各自写一套防重复提交。
  • 表单校验只靠后端错误返回。
  • 异常被吞掉后只显示空白。

页面可以先写假数据和 ViewState,等状态分支完整后再接接口。这样页面结构不会被接口细节牵着走。

接口联调和数据层

接口联调不要从页面开始。更稳定的顺序是:

  1. 确认接口文档、字段类型、错误码、分页方式。
  2. 定义 DTO,对齐接口 JSON。
  3. 定义 Entity,表达项目内部稳定模型。
  4. 定义 Repository 抽象,屏蔽远程和本地数据来源。
  5. 写 RemoteDataSource 和 LocalDataSource。
  6. 写错误映射,把网络错误、认证错误、业务错误统一成应用错误。
  7. 页面只消费 ViewState,不直接依赖接口 JSON。

分页接口要额外确认:

问题说明
分页方式page/pageSize、offset/limit、cursor
排序规则新数据插入后旧分页是否稳定
下拉刷新是否清空旧数据,失败时是否保留旧数据
加载更多最后一页如何判断,失败是否可重试
本地缓存缓存第一页还是缓存完整查询条件

联调阶段要保存几组典型数据:正常列表、空列表、字段缺失、权限不足、服务错误、超时、分页最后一页。这些数据能用于页面验收和自动化测试。

表单、权限和资源

很多 Flutter 项目不是难在页面展示,而是难在边界场景。

场景需要考虑
表单本地校验、后端校验、重复提交、草稿恢复、键盘遮挡
文件上传文件大小、格式、进度、失败重试、权限拒绝
图片加载图、错误图、缓存、内存、裁剪、不同屏幕密度
权限首次申请、拒绝、永久拒绝、系统设置返回
推送token 注册、登录切换、通知点击路由、权限关闭
深链冷启动、后台唤醒、参数缺失、无权限页面
国际化文案、日期、数字、货币、文字长度
可访问性语义标签、点击区域、字体缩放、颜色对比

这些内容最好在项目早期就建立统一封装。等功能写完再补,通常会牵动大量页面。

测试和质量门禁

一个可维护项目至少有三层验证:

层级验证什么
静态检查格式、lint、未使用代码、明显类型问题
自动化测试业务规则、状态分支、Repository、关键页面
手工验收真机、弱网、权限、发布包、异常流程

常用命令:

bash
dart format --set-exit-if-changed .
flutter analyze
flutter test
flutter test integration_test

手工验收不要只走成功路径。至少覆盖:

  • 首次安装和升级安装。
  • 未登录、登录过期、账号切换。
  • 无网络、弱网、接口超时、服务端错误。
  • 空数据、长文本、大图片、大列表。
  • 权限拒绝、永久拒绝、从系统设置返回。
  • Android 返回键、iOS 手势返回、应用切后台再回来。

发布前检查

发布前可以按这张表过一遍:

检查项AndroidiOS
应用 IDapplicationId 是否正确Bundle ID 是否正确
版本号versionCodeversionNameBuild、Version
签名keystore、别名、密码、渠道证书、描述文件、Team
权限Manifest、运行时权限Info.plist 权限文案
混淆R8/ProGuard 规则原生 SDK 配置
包体ABI、资源压缩、图片大小资源、符号配置
环境生产域名、生产 Key生产域名、生产 Key
观测崩溃、日志、性能、埋点崩溃、日志、性能、埋点

发布记录建议包含:版本号、Git 提交、构建命令、环境、主要变更、已知问题、回滚方式。没有这些信息,线上出问题时很难判断影响范围。

线上问题闭环

上线后需要能从现象追到原因:

现象需要的数据
崩溃升高版本、设备、系统、堆栈、用户路径
启动慢冷启动耗时、初始化步骤、插件耗时
页面白屏路由、接口、状态、异常日志
接口错误请求 ID、错误码、耗时、重试次数
卡顿帧耗时、页面、设备、图片和列表数据
支付/定位/相机异常权限状态、插件版本、系统版本、原生错误

线上问题处理顺序:

  1. 判断影响范围:单用户、单设备、单版本、全量用户。
  2. 找到可复现路径:页面、账号状态、网络、系统版本。
  3. 定位责任层:页面状态、数据层、接口、插件、平台配置。
  4. 制定处理方式:回滚、热修配置、灰度修复、发新版本。
  5. 补测试和监控:避免同类问题再次出现。

完整承接自检

读完并完成一个练习项目后,应该能独立说明:

  • 项目适合 Flutter 的原因和边界。
  • 目标平台、环境、接口、权限和发布渠道。
  • 目录结构中每一层为什么存在。
  • 一个页面从路由进入、加载数据、展示状态、处理错误的完整流程。
  • 状态管理选择的理由,以及状态如何释放。
  • 接口 DTO、业务 Entity、页面 ViewState 的区别。
  • 本地缓存、离线同步、token 存储的边界。
  • Android/iOS 权限、签名、构建和发布要检查什么。
  • 出现白屏、卡顿、构建失败、线上崩溃时怎么定位。
  • 项目交给别人继续维护时,需要留下哪些文档和脚本。

能回答这些问题,才算从“会写 Flutter 页面”进入“能承接 Flutter 项目”的阶段。

别急,先让缓存热一下。