Flutter 2.5 正式版已发布!

1,922 阅读22分钟

Flutter 2.5 正式版已于上周正式发布!这是一次重要的版本更新,也是 Flutter 发布历史上各项统计数据排名第二的版本。我们关闭了 4600 个 Issue,合并了 3932 个 PR,它们分别来自 252 个贡献者和 216 个审核者。回顾去年 -- 我们收到来自 1337 个贡献者提交的 21072 个 PR,其中有 15172 个被合并。在详述本次更新的内容之前,我们想强调,Flutter 的首要工作始终是高质量交付开发者们所需要功能。

Flutter 2.5 带来了一些重要的性能和工具改进,以帮助开发者们追踪应用中的性能问题。同时,加入了一些新的功能,包括对 Android 的全屏支持、 对 Material You (也称 v3) 的更多支持、对文本编辑的更新以支持切换键盘快捷键、在 Widget Inspector 中查看 widget 详情、在 Visual Studio Code 项目中添加依赖关系的新支持、从 IntelliJ / Android Studio 的测试运行中获得测试覆盖率信息的新支持,以及一个更贴近 Flutter 应用在真实的使用场景下的应用模板等。这个版本充满了令人兴奋的新更新,让我们开始介绍吧!

该版本进行了一些性能上的改进:首先是一项用于从离线训练运行中连接 Metal 着色器预编译的 PR (#25644),这将最坏情况下的光栅化时间减少了 2/3 (如我们的基准测试所示),将第 99 百分位的帧时间减少了一半。我们在减少 iOS 卡顿方面取得了持续性的进展,这也是在这条道路上迈出的另一步。然而,着色器预热只是卡顿的一个来源。在该版本以前,处理来自网络、文件系统、插件或其他 isolate 的异步事件可能导致动画中断,这是另一个卡顿的来源。在该版本中我们对 UI Isolate 的事件循环的调度策略 (#25789) 进行了改进,现在帧处理优先于其他异步事件的处理,在我们的测试中,其导致的卡顿已经被消除。

调整前后处理异步事件造成的帧构建滞后时间

另一个原因是垃圾回收 (GC) 会暂停 UI 线程来回收内存。在该版本以前,一些图像的内存只能在 Dart VM 执行 GC 时以较慢的速度进行回收。在早期版本中,常用的做法是 Flutter 引擎会向 Dart VM 提示图像内存可以通过 GC 回收,理论上可以让内存回收更为及时。不幸的是,在实践中这造成了过多的回收,而且内存有时仍然不能被快速回收,导致无法避免在内存有限的设备上出现低内存的情况。在现在的版本中,未使用的图像的内存会尽可能快速地进行回收 (#26219#82883#84740),这大大减少了 GC 的次数。

修复前和修复后的 GC 次数,以尽快回收未使用的大图像内存

举个例子,在我们的一个测试中,播放了一个 20 秒的 GIF 动画,GC 的次数从需要 400 次下降到只需 4 次。更少的主要 GC,意味着更少的涉及图像出现和消失的动画卡顿,更少的 CPU 和电量消耗。

Flutter 2.5 的另一项性能改进是优化了 iOS 上 Dart 和 Objective-C/Swift、Android 上 Dart 和 Java/Kotlin 之间相互通信的延迟。作为 调整消息通道 的一部分,我们从消息编解码器中移除了不必要的拷贝,在不同内容的大小和设备上减少了高达 50% 的延迟 (详见 #25988#26331)。

调整前后的 iOS 消息延迟

更多详情,请你参阅 Aaron Clarke 的文章:提高 Flutter 中的平台通道性能

如果你要构建 iOS 应用,我们还有最后一项性能更新:在该版本中,使用 Apple Silicon M1 Mac 构建的 Flutter 应用可以直接在 ARM 架构的 iOS 模拟器 (#pull/85642) 上运行。这意味着无需使用 Rosetta 对 Intel x86_64 指令和 ARM 进行转换,这提升了 iOS 应用测试的性能,并规避了一些微妙的 Rosetta 问题 (#74970#79641)。这是 Flutter 在全面支持 Apple Silicon 的路程上迈出的又一步,敬请继续关注。

当然,没有 Dart 语言和它的运行时环境,就不会有现在的 Flutter,它建立在 Dart 语言和 runtime 之上。Flutter 2.5 同时带来了 Dart 2.14。新发布的 Dart 版本 不仅带来了新的格式化使 级联 操作更加清晰,还带来了支持忽略文件的新 pub 命令工具,以及新的语言功能 (包括传说中的无符号右移操作符的回归)。此外,这个版本带来了一套新的 Dart 和 Flutter 项目之间共享的标准代码规范提示,开箱即用,这也是 Dart 2.14 最精彩的部分。

flutter create 开箱即有一个 analysis_options.yaml 文件,预先使用了推荐的 Flutter lint。

当你创建一个新的 Dart 或 Flutter 项目时,你不仅可以使用这些规范,而且 只需要几个步骤 就可以将这种相同的分析添加到你现有的应用中。关于这些规范的细节、新的语言功能和更多内容,请查阅:Dart 2.14 发布

Flutter 2.5 版本对框架进行了一些修复和改进。我们修复了关于 Android 全屏模式的一系列相关问题,该 Issue 获得了上百个点赞,全屏选项包括向后倾斜、沉浸模式、粘性沉浸模式和边到边四种。这一变化还增加了一种方法用来监听其他模式下的全屏变化。例如,如果用户在使用应用时,改变了系统界面的全屏模式,开发者现在可以通过代码让应用重新变为全屏,或执行其他操作。

新的 Android 边到边模式:正常模式 (左),边到边模式 (中),带有自定义 SystemUIOverlayStyle 的边到边 (右)

在这个版本中,我们继续建立对新的 Material You (又称 v3) 规范的支持,包括对悬浮按钮尺寸和主题的更新 (#86441),以及一个新的 MaterialState.scrolledUnder 状态,你可以通过 PR (#79999) 中的示例代码看到它的效果。

Material You 中新的 FAB 尺寸

新的 MaterialState.scrolledUnder 状态

当我们讨论滚动时,另一个改进是增加了额外的滚动指标通知 (#85221#85499),即使用户没有滚动,也会提供可滚动区域的通知。例如,如下示例展示了滚动条根据 ListView 的实际大小而适时出现或消失的效果。

新的滚动指标通知,使滚动条自动出现和消失。

在这种情况下,你不需要写任何代码,就可以捕获 ScrollMetricNotification 的变化。特别感谢社区贡献者 xu-baolin,他在这方面做了大量工作,并提出了一个很好的解决方案。

社区的另一杰出贡献是为 ScaffoldMessenger 增加了 Material 横幅的支持。在 Flutter 2.0 中新增的 ScaffoldMessenger,它提供了一种强大的方式,在屏幕底部显示 SnackBars 以向用户提供通知。在 Flutter 2.5 中,现在你可以在 Scaffold 顶部添加一个横幅,在用户将其关闭之前,它将一直保持在原位。

你可以通过调用 ScaffoldMessenger 的 showMaterialBanner 方法触发这种行为

横幅的 Material 指南 规定你的应用一次只能显示一个横幅,所以如果你的应用多次调用 showMaterialBannerScaffoldMessenger 将持有一个队列,在前一个横幅被关闭时显示下一个新的横幅。感谢 Calamity210 为 Flutter 的 Material 支持提供了有力补充。

在 Flutter 2.0 及其新文本编辑功能的基础上,我们在这个版本中添加了如文本选择器、拦截覆写任何键盘事件,以及覆写文本编辑的键盘快捷方式的能力 (#85381)。如果你想让 Ctrl - A 做一些自定义操作,而不是选择所有文本,你可以自行定义。DefaultTextEditingShortcuts 类包含了 Flutter 在每个平台上支持的每个键盘快捷方式的列表。如果你想覆写其中的关联,请使用 Flutter 现有的 Shortcuts widget,将任一快捷键重新映射到现有或自定义的意图,您可以将该 widget 放置在你想要覆写的地方。示例请参阅:API 文档

另一个得到大量改进的插件是 camera 插件

  • 3795 [camera] android-rework 第 1 部分:支持 Android 相机功能的基础类
  • 3796 [camera] android-rework 第 2 部分:Android 自动对焦功能
  • 3797 [camera] android-rework 第 3 部分:Android 曝光相关功能
  • 3798 [camera] android-rework 第 4 部分:Android 闪光灯和变焦功能
  • 3799 [camera] android-rework 第 5 部分:Android FPS 范围、分辨率和传感器方向功能
  • 4039 [camera] android-rework 第 6 部分:Android 曝光和对焦点功能
  • 4052 [camera] android-rework 第 7 部分:Android 降噪功能
  • 4054 [camera] android-rework 第 8 部分:最终实现的支持模块
  • 4010 [camera] 在 iOS 上不触发平放时的设备方向
  • 4158 [camera] 修复 iOS 上设置焦点和曝光点的坐标旋转
  • 4197 [camera] 修复相机预览在设备方向改变时不总是重建的问题
  • 3992 [camera] 防止在设置不支持的 FocusMode 时崩溃
  • 4151 [camera] 引入 camera_web package

image_picker 插件 上也做了很多工作,专注于端到端的相机体验。

  • 3898 [image_picker] 图像采集器修复相机设备
  • 3956 [image_picker] 在 Android 中将相机捕捉的存储位置改为内部缓存,以符合新的 Google Play 存储要求
  • 4001 [image_picker] 删除了多余的相机权限请求
  • 4019 [image_picker] 修复当相机作为源时的旋转问题

这些工作改善了 Android 的相机和 image_picker 插件的功能和健壮性。此外,你也许会注意到 camera 插件 的 Web 功能已处于预览阶段 (#4151)。这个预览版提供了对查看相机预览、拍摄照片、使用闪光灯和变焦控制的基本支持,所有这些都可以在 Web 上进行。它目前不是一个 被认可的联合插件,因此在配置中,你需要明确这个插件仅能够在 Web 应用中 添加使用

最初的 Android 相机重构工作是由 acoutts 贡献完成的。cameraimage_picker 的工作是由 Baseflow 完成的,这是一家专门从事 Flutter 的咨询公司,因其 在 pub.dev 上的 package 而闻名。camera_web 的工作主要由 Very Good Ventures 完成,这是一家位于美国的 Flutter 咨询公司。非常感谢你们对 Flutter 社区的贡献!

另一个有价值的社区贡献是由 fluttercommunity.dev 组织做出的,他们的代表作是 plus 系列插件。随着新的 Flutter 版本发布,之前由 Flutter 官方团队维护的插件现在 “交接” 给了 fluttercommunity.dev 组织,在每个插件下方都会有下面类似的提示:

此外,由于这些插件不再积极维护,所以我们已取消了它们的 Flutter Favorite 标记。如果你还没有迁移到 plus 系列插件,我们建议你按照以下的表格进行对照迁移。

Flutter 2.5 对 Flutter DevTools 进行了大量的改进。首先是在 DevTools 中增加了对引擎更新的支持 (#26205#26233#26237#26970#27074#26617)。其中一组更新使 Flutter 能够更好地将跟踪事件与特定的帧联系起来,这有助于开发人员确定一个帧可能会超出预算的原因。你可以在 DevTools 框架图中看到这一点,该图表重构之后已经支持了实时展示;当你的应用正在渲染时,它们的数据会被填入该图中。从这个图表中选择一个构建帧,就可以跳转到该帧的时间线事件。

Flutter 引擎现在也能识别时间线中的着色器编译事件。Flutter DevTools 使用这些事件来帮助您诊断应用中的着色器编译缺陷。

DevTools 检测到因着色器编译而丢失的构建帧

有了这个新功能,DevTools 可以检测到你因着色器编译而丢失的构建帧,以帮助你修复这个问题。如果你希望像首次运行应用一样,使用 flutter run 命令并加上 --purge-persistent-cache 这个标记。这将清除着色器的缓存,以确保你重现用户在「首次运行」或「重新打开」 (iOS) 应用时看到的效果。此功能仍在开发中,所以请将您发现的 问题或改进建议 提交给我们,以帮助发现和改进着色器编译工具。

此外,当你追踪应用中的 CPU 性能问题时,可能已经淹没在了来自 Dart 和 Flutter 库或引擎的原生代码的剖析数据中。如果你想关闭这些数据以专注自己的代码,那么你可以使用新的 CPU Profiler 功能 (#3236),使你能够隐藏来自任何这些源的 Profiler 信息。

对于你没有过滤掉的类别,它们现在已经用颜色进行了分类 (#3310#3324),这样你就可以很清晰地看到 CPU 火焰图内容对应的部分。

彩色的火焰图,识别应用中的应用 vs. 原生 vs. Dart vs. Flutter 代码活动

性能可能并不是你唯一想要调试的内容。新版本的 DevTools 带有对 Widget Inspector 的更新,当你将鼠标悬停在 widget 上时,可以评估对象、查看属性、widget 状态等等。

而且当你选择一个 widget 时,它会在新的 Widget Inspector Console 自动弹出,在那里你可以自由探索 widget 的属性。

当在断点处暂停时,你也可以在控制台执行表达式。

除了新功能,Widget Inspector 也进行了改头换面。为了使 DevTools 成为理解和调试 Flutter 应用的最佳工具,我们与芬兰的创意技术机构 Codemate 合作,进行了一些更新。

DevTools 调整后提供了更易于使用的用户体验

如上图所示,你可以看到以下变化:

  • 更好地传达调试切换按钮的作用 —— 这些按钮有新的图标、面向任务的标签,以及丰富的工具提示 (用于描述它们的功能和何时使用它们)。每个工具提示都进一步链接到了该功能的详细文档。
  • 更容易查找和定位感兴趣的 widget —— Flutter 框架中经常使用的 widget 现在已在 Inspector 左侧的 widget 树视图中作为图标常驻。它们已经根据其类别使用颜色进行了分类。例如,布局 widget 显示为蓝色,内容 widget 显示为绿色。此外,每个文本 widget 现在会显示其内容预览。
  • 更一致的 Layout Explorer 和 widget 树的颜色方案 —— 从 Layout Explorer 和 widget 树中识别出相同 widget 变得更容易了。例如,如上图所示中的「Column」widget 在 Layout Explorer 中是蓝色背景,在 widget 树视图中也有一个蓝色图标。

我们很乐意听到你对这些更新产生的任何 问题和改进建议 以确保 DevTools 高效地运行。这些亮点仅是开始。关于 DevTools 在 Flutter 这个版本中的全部新内容,请查阅以下版本说明:

IntelliJ / Android Studio 的 Flutter 插件在这个版本中也有一些改进,首先改进是运行集成测试的能力 (#5459)。集成测试是在设备上运行的整个应用测试,在 integration_test 目录下运行,并使用与 widget 单元测试相同的 testWidgets() 功能。

在 IntelliJ / Android Studio 中对 Flutter 应用进行集成测试

要在您的项目中添加集成测试,请 遵循 Flutter 文档网站上的说明。要将测试与 IntelliJ 或 Android Studio 连接,请添加一个运行配置,启动集成测试,并连接一个设备供测试使用。运行配置可以让你在运行测试的同时,设置断点、步进等。

此外,Flutter 的最新 IntelliJ / Android Studio 系列插件允许您查看单元测试和集成测试运行的覆盖率信息。您可以通过「debug」按钮旁边的工具栏按钮来访问这个信息:

覆盖率信息将以红色和绿色的矩形显示在编辑窗口左侧的空隙中。在这个例子里,第 9 - 13 行被测试覆盖,但第 3 和 4 行没有被测试。

最新版本还包括预览来自 pub.dev 的 package 中使用的图标的新功能,这些 package 是围绕 TrueType 字体文件构建的 (#5504#5595#5677#5704),正如 Material 和 Cupertino 图标支持预览一样。

IntelliJ / Android Studio 中的图标预览

要启用图标预览,你需要告诉该插件你正在使用哪些 package。在插件的设置 / 偏好页面有一个新的文本字段。

注意,这对定义为类中静态常量的图标有效,如屏幕截图中的示例代码所示。它不会对表达式起作用,例如 LineIcons.addressBook()LineIcons.values['code']。如果你是一个图标 package 的作者,而这个图标 package 并不适合这个功能,请 创建一个 Issue 进行反馈。

更多有关 Flutter 的 IntelliJ / Android Studio 插件的更新信息,请参阅下列发布说明:

Flutter 的 Visual Studio Code 插件在这个版本中也得到了改进,首先是两个新的命令「Dart: Add Dependency」和「Dart: Add Dev Dependency」 (#3306#3474)。

在 Visual Studio Code 中添加 Dart 依赖

这些命令提供的功能与已经提供了一段时间的 Jeroen Meijer 的 Pubspec Assist 插件 类似。这些新命令开箱即用,提供了一个从 pub.dev 定期获取的 package 的类型过滤列表。

你可能还对「Fix All」命令感兴趣 (#3445#3469),该命令对 Dart 文件可用,可以在一个步骤中修复所有与 dart fix 相同的问题。

使用 Flutter Fix 规则来修复您代码中的所有已知问题

你也可以在 VS Code 中,通过在 editor.codeActionsOnSave 中添加 source.fixAll 来设置为保存时运行。

又或者如果你想尝试一下预览功能,你可以启用 dart.previewVsCodeTestRunner 设置,看到 Dart 和 Flutter 测试通过新的 Visual Studio Code 测试运行器运行。

使用新的 Visual Studio Code 测试运行器测试你的 Dart 和 Flutter 代码

Visual Studio Code 测试运行器看起来与当前的 Dart 和 Flutter 测试运行器有些不同,它会在不同的会话中显示结果。Visual Studio Code 测试运行器还在编辑界面的左侧增加了新的间距图标 (Gutter icon),显示测试的执行结果状态,可以点击它来运行测试 (或右键点击上下文菜单)。

在之后的版本,现有的 Dart 和 Flutter 测试运行器将被移除,而采用新的 Visual Studio Code 测试运行器。

而这仅仅是 Visual Studio Code 插件新功能和修正的冰山一角。所有详情,请查阅下列发布说明:

  • v3.26 VS Code Test Runner 集成,Flutter 创建设置,...
  • v3.25 额外的依赖性管理改进,在文件 / 保存时修复所有,...
  • v3.24 依赖关系树的改进,更容易启动配置,编辑器的改进
  • v3.23 配置文件模式的改进,改进依赖关系树,改进 LSP

在以前的 Flutter 版本中,你可能会被那些你不希望处理的异常所困扰,你可能希望它们触发调试器并找出它们的源头,但却发现 Flutter 框架没有让异常通过来触发调试器中的「未处理的异常」处理程序。在这个版本中,调试器现在可以正确地中断未处理的异常,而以前这些异常只是被框架捕获 (#17007)。这改善了调试的体验,调试器现在可以直接指向异常在代码中的抛出行,而不是指向框架深处的一个随机位置。与之相关的一个新功能是你能够决定 FutureBuilder 是否应该重新抛出或隐藏错误 (#84308)。这应该会给你提供更多的异常,以帮助你追踪 Flutter 应用中的问题。

自从 Flutter 诞生以来,就有了 Counter 应用模板,它有很多优点:它展示了 Dart 语言的很多特性,演示了几个关键的 Flutter 概念,而且它足够小,即使有很多解释性的注释,也能装进一个文件。然而,它并未对 Flutter 应用的实际使用场景提供一个特别好的展示。在这个版本中,你可以通过以下命令创建一个新的模板 (#83530)。

$ flutter create -t skeleton my_app

新的 Flutter Skeleton 模板演示

新的 Skeleton 模板,可生成包含两页的列表视图 Flutter 应用 (带详细视图),并遵循社区最佳实践。它的开发经过了大量的内部和外部评审,以提供一个更好的基础来构建一个达到产品级品质的应用。它支持以下功能:

  • 使用 ChangeNotifier 来协调多个小工具
  • 默认情况下,使用 arb 文件生成本地化。
  • 包括一个示例图像,并为图像资源建立了 1x、2x 和 3x 文件夹。
  • 使用「功能优先」的文件夹组织方式
  • 支持 shared_preference
  • 支持浅色和深色主题设计
  • 支持多页之间的导航

随着时间的推移和 Flutter 最佳实践的发展,希望这个新模板也能随之发展。

如果你正在开发一个插件而不是一个应用,你可能会对 Pigeon 1.0 版本感兴趣。Pigeon 是一个代码生成工具,用于生成 Flutter 和其宿主平台之间类型安全的交互代码。你可以定义插件的 API 描述,并为 Dart 与 Java / Objective-C / Kotlin / Swift 生成模板代码。

Pigeon 生成的示例代码

Pigeon 已经应用在 Flutter 团队的一些插件中。这个版本提供了更多有用的错误信息,增加了对泛型、原始数据类型作为参数和返回类型以及多参数的支持,在未来它会被更广泛地使用。如果你想在自己的插件或 add-to-app 的项目中使用 Pigeon,请查阅 pigeon 插件页面 找到更多信息。

以下是 Flutter 2.5 版本中的破坏性改动:

了解自 1.17 版本以来完整的破坏性改动列表,请参阅:Flutter 文档网站

随着我们继续更新 Flutter Fix (可在 IDE 中使用,也可通过 dart fix 命令使用),我们总共应用了 157 条规则,来迁移受破坏性改动以及任何弃用影响的代码。一如既往,我们非常感谢社区 提供的测试,帮助我们识别了这些破坏性改动。如需了解更多,请查阅: Flutter 破坏性改动政策

另外,随着 Flutter 2.5 的发布,我们将放弃对 iOS 8 的支持,正如 2020 年 9 月宣布 的那样。放弃对市场份额不足 1% 的 iOS 8 的支持,使 Flutter 团队能够专注于使用范围更广的新平台。弃用意味着这些平台可能可以正常使用 Flutter,但我们不会在这些平台上测试新版本的 Flutter 或插件。您可以在 Flutter 文档网站 上看到 目前 Flutter 支持的平台列表

最后,一如既往地感谢世界各地的 Flutter 社区组织和社区成员们,是社区让这一切成为可能。在本次更新中贡献和审核了 1000 多个 PR 的数百位开发者们,因为有你们每个人的努力才成就了本次的成果。让我们携手共同努力,为世界各地的开发者共同转变应用的开发流程,让开发者们可以从一个代码库中交付更多应用、更快开发、部署到更多你所关心的平台。

敬请关注 Flutter 团队的更多更新,这一年还没有结束,请拭目以待!

感谢 flutter.cn 社区成员 (@AlexV525、@Vadaski、@MeandNi) 以及 Yuan 和 Lynn 对本文的审校和贡献。