功能在开发手机上能跑,代码也提交了,是不是就算完成?
还不算。真正的交付至少要回答四个问题:需求是否做对、异常场景是否可控、别人能否验证、上线出问题能否发现和处理。
核心结论:Flutter 开发交付不是“编码完成”,而是从需求确认到线上观察的闭环。流程可以按风险调整,但可验收、可测试、可追踪和可回退不能缺失。
一套最小交付流程
这不是为了增加审批,而是尽量在成本更低的阶段发现问题。需求阶段发现歧义,通常比上线后返工便宜得多。
第一步:先把需求变成可验证的结果
“增加搜索功能”还不能直接开始编码。至少要确认:
- 搜索范围和匹配规则;
- 空关键词、无结果和接口失败如何显示;
- 是否需要防抖、取消旧请求或保留历史记录;
- Android、iOS 是否一致;
- 什么结果算验收通过。
涉及接口、埋点、设计稿、权限或原生能力时,也要确认依赖方和交付时间。
一个简单原则是:如果开发无法写出验收步骤,需求通常还没有真正说清楚。
第二步:编码前先看风险
不是每个任务都需要设计文档,但要知道改动可能影响哪里。
Flutter 项目中经常被忽略的风险包括:
- 状态应该属于页面、模块还是全局;
- 异步返回后页面是否仍然
mounted; - 连续请求是否会出现旧数据覆盖新数据;
- Controller、订阅、Timer 是否有明确的释放方;
- 插件是否同时支持目标 Android、iOS 和当前 Flutter 版本;
- 后端接口是否兼容仍未升级的旧版 App;
- 功能关闭、接口降级或版本回退时会发生什么。
高风险改动要提前设计开关、降级和监控。低风险文案调整可以简化流程,但不能跳过基本验证。
第三步:让代码保持可检查
编码过程不只是把功能拼出来,还要让后续修改者看得懂。
日常可以守住几条底线:
- 一个改动围绕一个明确目标,避免混入无关重构;
- 业务状态有清晰来源,避免多个对象同时修改同一事实;
- Loading、空数据、错误和成功状态都能表达;
- 异步代码处理异常、生命周期和竞态;
- 新增依赖说明用途,并提交对应锁文件和原生配置;
- 生成代码按项目约定重新生成,不手工修改生成产物。
格式化、静态检查和测试命令应以项目脚本或 CI 配置为准。常见基础检查包括:
dart format --output=none --set-exit-if-changed .
flutter analyze
flutter test这些命令能挡住一部分问题,但不能代替真实设备上的业务验证。
第四步:自测不能只走成功路径
开发自测至少要覆盖:
- 正常流程是否符合验收条件;
- 空数据、错误、超时和重复点击;
- 返回、切后台、旋转或页面销毁后的行为;
- 弱网、断网和请求重试;
- Android 与 iOS 的关键差异;
- 窄屏、长文本、大字体和键盘弹出;
- 权限拒绝、永久拒绝和重新授权。
涉及性能时,要在目标设备的 Profile 或 Release 模式下测量。Debug 模式卡顿不能直接当成线上结论。
自测完成后,保留必要证据:录屏、截图、测试账号、构建号、日志时间范围或性能 Trace。这样测试和评审者不用重新猜测你验证了什么。
第五步:提交一份别人能评审的变更
一个可评审的 Pull Request 应该说明:
- 为什么要改;
- 主要改了什么;
- 哪些文件或模块风险较高;
- 如何验证;
- 是否有界面截图或录屏;
- 是否修改接口、存储、权限、插件或原生配置;
- 上线后如何观察,出问题如何关闭或回退。
评审不是检查代码风格这么简单。它还要确认状态边界、生命周期、错误处理、平台差异和测试范围是否合理。
CI 通过也不代表功能正确。CI 证明的是自动检查范围内没有发现问题,业务验收仍需要人或端到端测试完成。
第六步:发布前确认“这一包是谁”
发布产物必须能对应到源码和配置。至少保留:
- App 版本号和构建号;
- 提交或流水线编号;
- Flavor、后端环境和功能开关;
- Android 与 iOS 构建结果;
- 与当前构建匹配的符号文件;
- 发布说明、影响范围和回归结果。
签名、权限、推送、深链、网络安全配置和插件原生配置,往往只有 Release 构建或真机环境才能暴露问题。
移动端也不能假设“发错了马上回滚”。商店审核、分批发布和用户不升级都会让多个版本长期共存,因此后端兼容和功能开关非常重要。
第七步:上线不是流程终点
发布后要观察与本次改动直接相关的指标,例如:
- Crash 和非致命异常;
- 接口错误率与耗时;
- 页面成功率或关键业务转化;
- 启动、卡顿和内存指标;
- 用户反馈是否集中在特定平台或版本。
先小范围灰度,再根据指标扩大范围。发现异常时,要能快速判断是停止灰度、关闭功能、服务端降级还是发布修复版本。
一份可直接使用的完成清单
- [ ] 验收条件已确认,没有未决歧义
- [ ] 正常、空、错、加载状态已处理
- [ ] 异步生命周期、竞态和资源释放已检查
- [ ] Android / iOS 关键流程已验证
- [ ] 格式化、静态检查和相关测试通过
- [ ] PR 包含影响范围、验证证据和风险说明
- [ ] Release 构建、版本和符号文件可追踪
- [ ] 灰度、监控、开关或回退方案已确认清单不是越长越专业。团队应该根据事故和遗漏持续调整,把真正高频的风险留下来。
最后记住这几点
- 代码完成只是交付流程的中间节点。
- 没有验收条件,就无法判断是否做对。
- 自测要覆盖异常、生命周期、平台差异和真实设备。
- CI、评审和业务验收解决的是不同问题,不能互相替代。
- 发布产物必须可追踪,线上变化必须可观察。
- 移动端回退不即时,兼容、灰度和功能开关要提前设计。
问答复盘
Q1:功能在开发手机上正常,为什么还不能交付?
答: 单一设备只验证了一个环境。还要确认验收条件、异常路径、平台差异、构建配置和上线风险。
Q2:小改动也必须走完整流程吗?
答: 流程可以按风险缩减,但基本检查和可验证证据不能省。文案修改与支付链路改造不应使用相同强度。
Q3:CI 全绿是否代表可以直接上线?
答: 不代表。CI 只能覆盖已经配置的自动检查,无法自动证明业务逻辑、真机行为和用户体验全部正确。
Q4:Flutter 自测为什么要关注 Android 与 iOS?
答: 插件、权限、生命周期、键盘、返回行为和系统限制可能不同,共享 Dart 代码不代表平台行为完全一致。
Q5:性能问题为什么要在 Profile 或 Release 模式验证?
答: Debug 模式包含额外调试开销,不能代表发布产物。还要在目标设备和对应刷新率下测量。
Q6:移动端发布为什么特别强调兼容和功能开关?
答: 用户不会同时升级,应用商店回退也不即时。线上通常长期存在多个客户端版本,需要后端兼容和可控降级。