升级 Flutter 3.50 不应直接在生产分支覆盖 SDK,而应先核对版本与兼容边界,再迁移依赖并完成全平台验证。Flutter 官方安装页明确提示“Flutter 3.50 is live”,但版本上线不等于现有应用可以直接升级。SDK 约束、旧语言版本、第三方插件和多平台行为都可能成为阻断点。
存量项目应先建立版本基线,再完成空安全迁移、依赖拆分更新、静态分析、自动化测试、目标平台构建和回退演练。掘金热榜文章《Flutter 3.50 & Dart 3.14 发布,快来看看有什么更新吧》讨论的是“有什么更新”,但生产项目更关心这些变化会不会影响现有代码,以及升级失败后如何恢复到已知可用状态。
Flutter 3.50 与 Dart 3.14 的改动范围
Flutter 是一套使用 Dart 开发的跨平台应用框架,目标是从单一代码库构建移动、Web、桌面和嵌入式应用;其渲染体系直接输出像素,而不是依赖目标平台原有的 UI 渲染栈。 因此,Flutter 3.50 应对照框架层发布说明检查,Dart 3.14 应对照语言层发布说明检查,两者不能混成一份笼统的“版本更新说明”。
版本对应关系也需要单独核对。Flutter 与 Dart 存在配套关系,但不能仅凭两个版本号推断实际组合。现有历史对应表只覆盖到 Flutter 3.13.5,无法用来证明 Flutter 3.50 携带哪个具体 Dart 补丁版本。 项目应以当前安装的 SDK 输出为准:
flutter --version
dart --version
flutter doctor -v
官方安装页目前确认 Flutter 3.50 已上线,但页面未附带 Flutter 3.50 与 Dart 3.14 的完整更新日志。 因此,本文不列出未经官方发布说明确认的新 API、性能数字或插件支持状态。更稳妥的做法是,将两版官方发布说明逐条录入项目升级台账,再判断每项变化是否与现有模块有关。
框架侧要核对哪些变化
框架侧至少应按下面五类核对 3.50 官方说明。每一条都要标记为“新增、弃用、破坏性变更或无需动作”,不能只摘录新增功能。
| 检查类别 | 官方说明中需要找什么 | 对存量项目的影响 |
|---|---|---|
| UI 与渲染 | Widget API、主题、布局、渲染行为、无障碍语义变化 | 可能引起界面差异、交互变化和自动化测试失败 |
| 性能 | 运行时、渲染、启动、构建或内存占用相关变化 | 只能在相同设备、相同构建模式下测量,不能直接引用宣传数字 |
| 平台适配 | 系统接口、权限、生命周期、输入与文本处理变化 | 需要在真实目标系统验证,不能只跑模拟器 |
| 构建工具 | 各平台构建链、打包流程和工具版本要求 | 可能造成本地成功、CI 失败或商店构建失败 |
| 开发者工具 | 分析器、调试器、测试工具和 IDE 支持变化 | 可能增加新的分析告警,或要求同步升级 IDE 插件 |
升级台账可采用以下结构:
Flutter 版本:
Dart 版本:
发布说明条目:
分类:UI / 性能 / 平台 / 构建 / 工具
变更级别:新增 / 弃用 / 破坏性 / 无需动作
影响模块:
需要修改的代码:
验证方式:
负责人:
尤其不要遗漏“没有新增功能,但改变了默认行为或弃用旧接口”的条目。对长期维护项目而言,这类变化往往比醒目的新 Widget 更值得优先处理。
语言侧要核对哪些变化
Dart 3.14 应按语法、类型系统、核心库、编译器与运行时、开发者工具五类核对。判断时需要区分两件事:Dart 3 早已生效的历史基线,以及 Dart 3.14 本次新增的限制、弃用项和工具变化。
| 检查类别 | 需要核对的内容 | 项目侧动作 |
|---|---|---|
| 语法 | 新语法、旧语法移除、格式化规则变化 | 搜索旧写法,先用分析工具定位,再人工审查修改 |
| 类型系统 | 类型推断、泛型、模式匹配或错误诊断变化 | 重新执行静态分析,比较升级前后的告警差异 |
| 核心库 | API 新增、弃用和移除 | 更新调用代码,删除已废弃用法 |
| 编译器与运行时 | 代码生成、运行参数、平台行为变化 | 做完整构建、基准测试和设备回归 |
| 开发者工具 | 分析器、格式化器、调试器、DevTools 变化 | 固定工具版本,避免本地与 CI 输出不同 |
Dart 3 的历史基线应单独核对:从 Dart 3 开始只支持健全空安全;低于 2.12 的 SDK 约束会停止解析;依赖约束仍低于 2.12 时,带有旧语言版本标记的源代码也会失效。同时,Dart 3 移除了部分废弃的核心库 API、默认参数的历史语法,并要求使用明确的 tear-off 写法。 这些是升级到 Dart 3 时需要满足的要求,不应被误写成 Dart 3.14 的新增特性。
存量项目的兼容问题会在哪些环节暴露
存量项目的问题通常沿 SDK 约束、依赖解析、代码编译、原生构建和运行时行为逐层暴露。
第一层是 pubspec.yaml。如果项目仍声明过低的 Dart 下限、保留了 Dart 2 时代的上限,或者 Flutter 与 Dart 约束互相冲突,依赖解析阶段就可能失败。
第二层是第三方依赖。某个直接依赖可能允许 Dart 3,但它依赖的传递包仍未完成空安全迁移;或者纯 Dart 包可以解析,包含原生代码的插件却无法通过当前平台工具链构建。
第三层是项目代码。Dart 3 只支持健全空安全,旧语言版本标记、已移除 API 和不再接受的历史语法都可能在这里暴露。
第四层才是框架运行时。Widget 行为、渲染结果、系统权限、生命周期和平台插件调用即使能够编译,也可能在真实设备上出现差异。
因此,排查顺序应当是:
- 先检查 SDK 约束和依赖解析结果。
- 再检查空安全、语言版本和已移除 API。
- 然后处理静态分析、测试和原生插件构建。
- 最后验证真实设备上的交互与系统集成。
仍在 Dart 2 或更早版本的项目
这类项目不宜直接替换为 3.14 SDK,再逐项修复错误。更稳妥的路径是先建立 Dart 3 要求的空安全基线,再处理 3.14 的新增变化。
先检查 pubspec.yaml、锁文件以及所有直接和传递依赖。空安全迁移要求代码和依赖共同完成,不能只修改业务代码。迁移阶段可以先把 SDK 下界提高到 2.12,例如:
environment:
sdk: ">=2.12.0 <4.0.0"
迁移完成并确认所有依赖都支持健全空安全后,再收紧到实际使用的 Dart 版本:
environment:
sdk: ">=3.14.0 <4.0.0"
flutter: ">=3.50.0"
上述约束仅是应用项目的配置示例。实际取值应与 flutter --version、dart --version 的输出一致;如果项目不是应用,或者需要兼容更早的 Flutter,再按仓库策略调整。
随后处理 Dart 3 已经移除的 API、默认参数历史语法和 tear-off 要求。 可以先查看自动修复建议:
dart fix --dry-run
dart fix 只能作为辅助,不能代替人工审查。每项修改都应检查行为差异,尤其是空值处理、异步调用和平台边界代码。
旧语言版本标记需要单独搜索。可以按 // @dart= 在项目中查找,确认不再依赖 2.12 以前的语言行为,再删除或调整这些标记。
已经使用 Dart 3 的项目
已经使用 Dart 3 的项目不需要重复进行历史空安全迁移。此时应把注意力收窄到 Dart 3.14 的版本差异:新的分析诊断、核心库弃用项、运行时行为和工具链要求。
建议先保存升级前的静态分析基线:
flutter analyze
然后对照 Dart 3.14 发布说明逐条检查。直接依赖升级后,还要重新查看传递依赖,因为一个包的版本变化可能改变多个间接依赖的解析结果。包含原生代码的平台插件则要单独查看其最低 Flutter、Dart 版本和目标平台支持情况。
生成代码、代码生成器和平台脚本也值得单列。它们即使不在 lib/ 目录中,也可能使用已经废弃的 Dart API,不能只扫描业务代码。
升级前怎样确认版本、渠道和依赖状态
升级前应先产出可复现的环境基线,不能只记录一张写着“Flutter 3.50、Dart 3.14”的截图。
在项目根目录记录:
flutter --version
dart --version
flutter doctor -v
flutter pub deps --style=compact
git rev-parse HEAD
git status --short
这些命令用于确认 Flutter 及其渠道、实际执行的 Dart 版本、各平台开发工具状态、完整依赖树和当前代码基线。
需要特别检查终端与 IDE 是否使用了同一个 SDK。官方安装文档支持通过 VS Code 扩展安装 SDK,也可以手动安装并配置 PATH;如果二者指向不同目录,IDE 中的分析结果与命令行测试就可能不一致。
Flutter 有 stable、beta 和 master 三个发布渠道。除非项目明确需要验证尚未稳定的能力,否则升级应优先使用 stable。 团队还应记录 SDK 的精确版本和提交标识,不要只写一个模糊的大版本号。
依赖状态至少应保存:
- 原始
pubspec.yaml。 - 原始
pubspec.lock。 - 直接依赖与传递依赖清单。
- 升级前的分析、测试和构建结果。
- 当前使用的插件及其平台范围。
有了这些记录,后续才能区分“升级引入的问题”和“项目原本就存在的问题”。
新项目和存量项目分别从哪里开始
全新项目
全新项目没有历史依赖包袱,可以直接以目标稳定渠道建立基线。先安装团队选定的 Flutter 3.50 SDK,再用实际输出确认其中的 Dart 版本:
flutter --version
dart --version
创建项目并执行第一次基线检查:
flutter create project_name
cd project_name
flutter pub get
flutter analyze
flutter test
随后设置明确的 SDK 约束,提交 pubspec.lock,并为实际支持的目标平台建立构建任务。应用项目应提交锁文件;可复用包的锁文件策略则按仓库用途决定,但 CI 仍需要使用可复现的依赖解析结果。
已有项目
已有项目应先创建独立升级分支:
git switch -c chore/flutter-3.50-upgrade
git tag pre-flutter-3.50-baseline
git status --short
升级前要确认工作区没有未提交修改。锁文件、平台配置、生成代码和依赖声明都应保留在升级前基线中,不要在第一轮就混合格式化、重命名和依赖大版本升级。
建议至少设置两个可回退节点:
- 只切换 SDK、调整约束并完成依赖解析。
- 更新依赖、修改代码并完成测试与平台构建。
这样一旦第二步失败,可以保留第一轮的可运行状态,而不是把整个升级分支一起丢弃。
SDK、依赖和代码按什么顺序迁移
先切换到精确的 Flutter 3.50 SDK。若团队通过 Git 管理 Flutter SDK,可以检出对应标签或固定提交:
git -C "$FLUTTER_ROOT" fetch --tags
git -C "$FLUTTER_ROOT" checkout 3.50.0
flutter --version
dart --version
如果 SDK 通过压缩包安装,则替换为团队指定版本,并继续用实际输出确认。官方安装文档提供了切换发布渠道、升级 SDK 和下载历史版本的入口。
第二步是清理并重新解析依赖:
flutter clean
flutter pub get
这一步若失败,先解决 SDK 约束和依赖冲突,不要继续修改业务代码。
第三步是根据实际 Dart 输出调整 pubspec.yaml。不要为了“通过解析”无限放宽上界;约束应表达项目真正支持的版本范围。
第四步是查看依赖差距:
flutter pub outdated
先升级允许范围内的小版本,再分批处理需要修改调用代码的大版本。例如,把 package_name 替换为实际包名后执行:
flutter pub upgrade package_name
建议按风险分组更新,而不是一次升级所有依赖:
- 基础工具、序列化和状态管理依赖。
- 网络、存储及与业务模型耦合的依赖。
- 相机、定位、推送、支付等包含原生代码的插件。
- 测试、Mock、代码生成和开发环境工具。
每组升级后都重新执行 flutter pub get 和测试。一次升级全部包会让失败原因难以定位。
第五步是处理代码诊断:
dart fix --dry-run
flutter analyze
逐项审查自动修复建议,再重新运行分析。不要直接对整个仓库执行未经审查的批量替换。
第六步是执行自动化测试:
flutter test
测试通过后再执行目标平台构建。单元测试和 Widget 测试通过,只能证明已覆盖的逻辑没有回归,不能替代完整构建、签名流程和设备验证。
最后检查差异并提交:
git diff -- pubspec.yaml pubspec.lock
git add pubspec.yaml pubspec.lock
git commit -m "chore: upgrade Flutter and Dart SDK"
代码修改、生成文件和平台配置应单独审查后提交,不要用一次大提交掩盖升级过程中的问题。
本地通过后还要验证哪些平台和插件
多平台支持除了复用同一套 UI,还涉及输入交互、编译构建、无障碍、国际化以及特定平台的集成功能。 因此,本地测试通过后仍要重新验证项目实际支持的目标平台。
| 目标平台 | 建议执行的完整构建 | 重点验证 |
|---|---|---|
| Android | flutter build apk --debug、flutter build appbundle --release |
安装启动、权限、原生插件、后台任务和发布构建 |
| iOS | flutter build ios --release --no-codesign |
生命周期、文本输入、相机与推送等原生能力 |
| Web | flutter build web |
浏览器兼容、存储、网络访问和页面加载 |
| Windows | flutter build windows --release |
窗口、键盘、菜单、文件访问和桌面插件 |
| macOS | flutter build macos --release |
Apple 芯片与 Intel 环境、桌面交互和系统权限 |
| Linux | flutter build linux --release |
桌面构建、输入设备、文件与窗口集成 |
| 嵌入式设备 | 按项目现有构建脚本执行 | 目标板启动、输入输出、资源限制和设备稳定性 |
这些命令只适用于项目实际支持的平台,并应在具备对应平台工具链的环境中运行。--no-codesign 只能验证无签名构建,商店签名、上传和发布仍需单独测试。
插件检查应覆盖所有实际使用的原生能力。至少确认插件在当前 Flutter、Dart 和目标系统上能够解析、编译、启动并完成核心调用。还要回归无障碍语义、国际化文本、权限拒绝路径、网络异常和进程重启后的状态恢复。
性能变化也不应靠主观感受下结论。应使用升级前后的同配置构建或设备,对启动、渲染、内存和包体做对比。没有稳定测量结果时,不应把“更快”写入发布结论。
CI 和团队怎样避免版本漂移
CI 不应执行含义模糊的 flutter upgrade,因为它可能把团队带到与本地不同、也与上次成功构建不同的 SDK 版本。CI 应安装精确版本的 Flutter SDK,或检出固定提交,并在任务开始时记录实际版本。
基础校验脚本可以写成:
#!/usr/bin/env bash
set -euo pipefail
flutter --version
dart --version
flutter pub get --enforce-lockfile
flutter analyze
flutter test
flutter doctor -v 可以在安装阶段或诊断任务中执行,用来发现缺失的平台工具链;是否阻断构建,应根据项目实际目标平台决定。
团队还需要统一三项内容:
- SDK:固定 Flutter 精确版本、渠道和实际 Dart 输出。
- 依赖:提交并校验
pubspec.lock,CI 使用--enforce-lockfile防止静默改写。 - 缓存:缓存键同时包含 SDK 版本与锁文件摘要,两者任一变化都应重新建立缓存。
CI 应按项目支持的平台建立矩阵。每个平台至少执行依赖解析、静态分析、自动化测试、完整构建和安装后冒烟测试;包含原生插件的平台还需要执行插件核心流程测试。
发布流程宜分为开发分支、内部版本、测试环境和生产环境几个阶段。新 SDK 先在测试分支验证,确认稳定后再扩大使用范围。涉及应用商店发布的项目,还应为已经分发出去的旧版本准备独立的回退构建。
升级失败后怎样回退
升级失败后,先保留失败分支、CI 日志、SDK 输出和锁文件差异,不要立即删除现场。回退应同时处理 SDK、代码、依赖和构建产物。
第一步是切回团队记录的已知可用 SDK。官方安装文档提供了历史版本下载与渠道切换入口。 不要用“当前最新版本”代替原先的精确版本,否则回退结果不可复现。
第二步是回到升级前代码与锁文件。例如主分支名为 main 时:
git switch main
git restore --source main -- pubspec.yaml pubspec.lock
flutter clean
flutter pub get
flutter analyze
flutter test
如果失败发生在升级分支,应先把失败提交保留下来供分析,再选择回到基线分支,而不是直接覆盖工作区。
第三步是清理并重新生成构建产物:
flutter clean
flutter pub get
随后重新执行目标平台构建和设备冒烟测试。仅靠 Hot Reload 不足以证明 SDK 升级稳定,因为它无法覆盖完整编译、依赖解析、原生链接和安装后的运行行为。
第四步是单独处理已经发布的应用。代码仓库回退并不会自动撤回商店中的版本,因此需要准备使用旧 SDK 构建的回退包,并明确数据迁移是否可逆。
哪些项目适合马上升级
升级时机不应由版本热度决定,而应由插件适配情况、回归测试能力和业务风险决定。
| 项目情况 | 建议 |
|---|---|
| 需要新版性能、平台能力或工具链修复,关键插件已经验证 | 可以优先升级 |
| 已有稳定的单元测试、Widget 测试、集成测试和平台构建任务 | 适合进入升级流程 |
| 关键插件尚未声明兼容,只能解析但不能完成原生构建 | 暂缓生产升级 |
| 仍停留在 Dart 2 或尚未完成健全空安全迁移 | 先完成语言迁移 |
| 没有自动化回归测试,升级只能依靠人工点测 | 等测试补齐后再升级 |
| 正处于商店发布、支付切换或核心数据迁移窗口 | 等风险窗口结束后再升级 |
已经使用 Dart 3 的成熟项目通常更适合采用渐进升级:先升级框架和直接依赖,再处理插件与平台适配,最后扩大发布范围。仍在 Dart 2 的项目则应把空安全迁移作为独立阶段,不要把语言迁移、依赖大版本更新和框架升级压缩成一次不可诊断的变更。
升级完成的判据是:版本变化有记录,兼容结论经过验证,回退路径可以执行。仅替换 SDK 不能替代这些验证。
封面图:Google-flutter-logo,作者 google,Public domain,来自 Wikimedia Commons
[email protected]
。
我们承诺在核实信息后,将第一时间删除相关内容或断开链接。
























暂无评论内容