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 的次数。
举个例子,在我们的一个测试中,播放了一个 20 秒的 GIF 动画,GC 的次数从需要 400 次下降到只需 4 次。更少的主要 GC,意味着更少的涉及图像出现和消失的动画卡顿,更少的 CPU 和电量消耗。
Flutter 2.5 的另一项性能改进是优化了 iOS 上 Dart 和 Objective-C/Swift、Android 上 Dart 和 Java/Kotlin 之间相互通信的延迟。作为 调整消息通道 的一部分,我们从消息编解码器中移除了不必要的拷贝,在不同内容的大小和设备上减少了高达 50% 的延迟 (详见 #25988、#26331)。
更多详情,请你参阅 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 获得了上百个点赞,全屏选项包括向后倾斜、沉浸模式、粘性沉浸模式和边到边四种。这一变化还增加了一种方法用来监听其他模式下的全屏变化。例如,如果用户在使用应用时,改变了系统界面的全屏模式,开发者现在可以通过代码让应用重新变为全屏,或执行其他操作。
在这个版本中,我们继续建立对新的 Material You (又称 v3) 规范的支持,包括对悬浮按钮尺寸和主题的更新 (#86441),以及一个新的 MaterialState.scrolledUnder
状态,你可以通过 PR (#79999) 中的示例代码看到它的效果。
当我们讨论滚动时,另一个改进是增加了额外的滚动指标通知 (#85221、#85499),即使用户没有滚动,也会提供可滚动区域的通知。例如,如下示例展示了滚动条根据 ListView 的实际大小而适时出现或消失的效果。
在这种情况下,你不需要写任何代码,就可以捕获 ScrollMetricNotification 的变化。特别感谢社区贡献者 xu-baolin,他在这方面做了大量工作,并提出了一个很好的解决方案。
社区的另一杰出贡献是为 ScaffoldMessenger
增加了 Material 横幅的支持。在 Flutter 2.0 中新增的 ScaffoldMessenger
,它提供了一种强大的方式,在屏幕底部显示 SnackBars 以向用户提供通知。在 Flutter 2.5 中,现在你可以在 Scaffold 顶部添加一个横幅,在用户将其关闭之前,它将一直保持在原位。
横幅的 Material 指南 规定你的应用一次只能显示一个横幅,所以如果你的应用多次调用 showMaterialBanner
,ScaffoldMessenger
将持有一个队列,在前一个横幅被关闭时显示下一个新的横幅。感谢 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 贡献完成的。camera
和 image_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 可以检测到你因着色器编译而丢失的构建帧,以帮助你修复这个问题。如果你希望像首次运行应用一样,使用 flutter run
命令并加上 --purge-persistent-cache
这个标记。这将清除着色器的缓存,以确保你重现用户在「首次运行」或「重新打开」 (iOS) 应用时看到的效果。此功能仍在开发中,所以请将您发现的 问题或改进建议 提交给我们,以帮助发现和改进着色器编译工具。
此外,当你追踪应用中的 CPU 性能问题时,可能已经淹没在了来自 Dart 和 Flutter 库或引擎的原生代码的剖析数据中。如果你想关闭这些数据以专注自己的代码,那么你可以使用新的 CPU Profiler 功能 (#3236),使你能够隐藏来自任何这些源的 Profiler 信息。
对于你没有过滤掉的类别,它们现在已经用颜色进行了分类 (#3310、#3324),这样你就可以很清晰地看到 CPU 火焰图内容对应的部分。
性能可能并不是你唯一想要调试的内容。新版本的 DevTools 带有对 Widget Inspector 的更新,当你将鼠标悬停在 widget 上时,可以评估对象、查看属性、widget 状态等等。
而且当你选择一个 widget 时,它会在新的 Widget Inspector Console 自动弹出,在那里你可以*探索 widget 的属性。
当在断点处暂停时,你也可以在控制台执行表达式。
除了新功能,Widget Inspector 也进行了改头换面。为了使 DevTools 成为理解和调试 Flutter 应用的最佳工具,我们与芬兰的创意技术机构 Codemate 合作,进行了一些更新。
如上图所示,你可以看到以下变化:
- 更好地传达调试切换按钮的作用 —— 这些按钮有新的图标、面向任务的标签,以及丰富的工具提示 (用于描述它们的功能和何时使用它们)。每个工具提示都进一步链接到了该功能的详细文档。
- 更容易查找和定位感兴趣的 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()
功能。
要在您的项目中添加集成测试,请 遵循 flutter.dev 上的说明。要将测试与 IntelliJ 或 Android Studio 连接,请添加一个运行配置,启动集成测试,并连接一个设备供测试使用。运行配置可以让你在运行测试的同时,设置断点、步进等。
此外,Flutter 的最新 IntelliJ / Android Studio 系列插件允许您查看单元测试和集成测试运行的覆盖率信息。您可以通过「debug」按钮旁边的工具栏按钮来访问这个信息:
覆盖率信息将以红色和绿色的矩形显示在编辑窗口左侧的空隙中。在这个例子里,第 9 - 13 行被测试覆盖,但第 3 和 4 行没有被测试。
最新版本还包括预览来自 pub.dev 的 package 中使用的图标的新功能,这些 package 是围绕 TrueType 字体文件构建的 (#5504、#5595、#5677、#5704),正如 Material 和 Cupertino
图标支持预览一样。
要启用图标预览,你需要告诉该插件你正在使用哪些 package。在插件的设置 / 偏好页面有一个新的文本字段。
注意,这对定义为类中静态常量的图标有效,如屏幕截图中的示例代码所示。它不会对表达式起作用,例如 LineIcons.addressBook()
或 LineIcons.values[‘code‘]
。如果你是一个图标 package 的作者,而这个图标 package 并不适合这个功能,请 创建一个 Issue 进行反馈。
更多有关 Flutter 的 IntelliJ / Android Studio 插件的更新信息,请参阅下列发布说明:
- Flutter IntelliJ Plugin M57 发布
- Flutter IntelliJ Plugin M58 发布
- Flutter IntelliJ Plugin M59 发布
- Flutter IntelliJ Plugin M60 发布
Flutter 的 Visual Studio Code 插件在这个版本中也得到了改进,首先是两个新的命令「Dart: Add Dependency」和「Dart: Add Dev Dependency」 (#3306、#3474)。
这些命令提供的功能与已经提供了一段时间的 Jeroen Meijer 的 Pubspec Assist 插件 类似。这些新命令开箱即用,提供了一个从 pub.dev 定期获取的 package 的类型过滤列表。
你可能还对「Fix All」命令感兴趣 (#3445、#3469),该命令对 Dart 文件可用,可以在一个步骤中修复所有与 dart fix 相同的问题。
你也可以在 VS Code 中,通过在 editor.codeActionsOnSave
中添加 source.fixAll
来设置为保存时运行。
又或者如果你想尝试一下预览功能,你可以启用 dart.previewVsCodeTestRunner
设置,看到 Dart 和 Flutter 测试通过新的 Visual Studio Code 测试运行器运行。
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
新的 Skeleton 模板,可生成包含两页的列表视图 Flutter 应用 (带详细视图),并遵循社区最佳实践。它的开发经过了大量的内部和外部评审,以提供一个更好的基础来构建一个达到产品级品质的应用。它支持以下功能:
- 使用 ChangeNotifier 来协调多个小工具
- 默认情况下,使用 arb 文件生成本地化。
- 包括一个示例图像,并为图像资源建立了 1x、2x 和 3x 文件夹。
- 使用「功能优先」的文件夹组织方式
- 支持 shared_preference
- 支持浅色和深色主题设计
- 支持多页之间的导航
随着时间的推移和 Flutter 最佳实践的发展,希望这个新模板也能随之发展。
如果你正在开发一个插件而不是一个应用,你可能会对 Pigeon 1.0 版本感兴趣。Pigeon 是一个代码生成工具,用于生成 Flutter 和其宿主平台之间类型安全的交互代码。你可以定义插件的 API 描述,并为 Dart 与 Java / Objective-C / Kotlin / Swift 生成模板代码。
Pigeon 已经应用在 Flutter 团队的一些插件中。这个版本提供了更多有用的错误信息,增加了对泛型、原始数据类型作为参数和返回类型以及多参数的支持,在未来它会被更广泛地使用。如果你想在自己的插件或 add-to-app 的项目中使用 Pigeon,请查阅 pigeon 插件页面 找到更多信息。
以下是 Flutter 2.5 版本中的破坏性改动:
- 默认的设备拖动和滚动
- v2.2 版后删除了废弃的 API
- Package 介绍: flutter_lints
- ThemeData 的 accent 属性已被弃用
- 手势识别器清理
- 将 AnimationSheetBuilder.display 替换为 collate
- 使用 HTML 插槽在 Web 中渲染平台视图
- 将 LogicalKeySet 迁移至 SingleActivator
了解自 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 对本文的审校和贡献。