Flutter 1.22正式发布

2,904 阅读20分钟

作者:Chris Sells

译者:heqingbao

原文:medium.com/flutter/ann…

阅读此文大概需要17分钟

Google 在 10 月 1 号发布了 Flutter 1.22 版本,支持 iOS 14 和 Android 11 ,新的 i18n和 l10n 支持,可用于生产项目的 Google Maps 和 WebView 插件, 新的 App Size 工具等等。

我们很高兴地但是好多们最新的 Flutter 版本,它对 iOS 14 和 Android 11 提供了广泛的支持。Flutter 1.22 在以前版本的基础上构建,使开发人员能够从单个代码库为多个平台构建快速、美观的用户体验。我们的季度稳定版本包含最新的功能、性能改进和错误修复,适合广泛的生产环境使用。

由于这是新的移动操作系统版本的发布季节,因此此发行版侧重于确保 Android 11 和 iOS 14 与 Flutter 兼容。这两个操作系统的更新都包括大量的幕后工作,以符合最新的 SDK 并确保所有内容都通过我们广泛的测试套件。对于iOS 14,此版本包括对新 Xcode 12,新图标的支持以及对新 iOS 14 App Clips 功能的预览支持。对于Android 11,此更新支持新类型的显示切口以及在调出软键盘时更流畅的动画。

该版本发布于我们的 1.20 发布两个月之后,因此比大多数版本都短。即使在这么短的时间内,我们也关闭了 3024 个 issues,合并了 197 个贡献者的 1944 个 PR。在这些贡献者中,有 114 位(58%)来自整个社区,他们贡献了271 个 PR。最大的单一贡献者是 a14n,它再次以 20 个 PR 成为我们的最佳贡献者列表,其中大部分是作为支持 Flutter 中的零安全性工作的一部分而完成的(更多内容即将推出)。

除了对新的移动操作系统版本的支持外,还有很多其他要分享的新闻,包括预览 Android 最重要的功能之一:状态恢复、新的 Material 按钮“ Universe”、新的国际化和本地化支持(与热重载一起使用)、一个新的 Navigator、一个稳定的 Platform Views 版本(Google Maps 和 WebView 插件的基础)以及一个开关,您可以在其中添加代码以改善在具有高频率显示的设备上的滚动。我们还提供了一个用于剖析应用程序大小并确保所构建的插件仅支持要支持的平台的新工具。

支持 iOS 14

每当发布新版本的移动操作系统时,我们都会对其进行彻底测试,以查找影响Flutter及其工具的不兼容性或更改。

对于 iOS 14,我们对Flutter进行了很多更改,以确保它可以按照开发人员的方式工作:

  • Xcode 12 需要 iOS 9.0 或更高版本,因此我们的默认模板将其默认值从 8.0 增加到 9.0
  • iOS 14 特定崩溃和字体渲染问题已在 Flutter 1.22 中修复
  • 从 Flutter 1.20.4 起,已解决了部署到物理设备的问题
  • 一种新的策略,当应用程序访问其剪贴板时显示使用通知,从而在 Flutter 应用程序中导致虚假通知,该策略已在 Flutter 1.20.4 中修复
  • 限制会禁止在 iOS 14 设备上运行调试应用程序,但作为调试过程的一部分除外
  • 针对本地调试的 Flutter 应用程序的有关网络安全的新策略使 iOS 14 显示一次性确认对话框(仅在开发过程中,不适用于已发布的 Flutter 应用程序)

底线(Bottom line):如果您的 Flutter 应用面向 iOS 14,我们强烈建议您使用 Flutter 1.22 对其进行重建并将其立即部署到 App Store 中,以确保您的 iOS 14 用户获得最佳体验。

有关使用 Flutter 定位 iOS 14 的更多详细信息,包括一些“添加到应用”,深层链接和通知注意事项,请参阅flutter.dev上的iOS 14文档

希望所有有关工具和SDK支持的工作都可以让您专注于自己关心的编码-利用iOS 14的新功能。

这样的功能之一就是对 iOS 的新 SF Symbols 字体的更新支持,这启发了我们花一些时间对 cupertino_icon package 进行刷新。CupertinoIcons 将 cupertino_icons 依赖关系更新为新的 1.0 主要版本后,现有的使用将自动映射到新样式。如果您将 cupertino_icons 1.0 与 Flutter 1.22 结合使用,则还可以通过 CupertinoIcons API 访问约 900 个新图标。 1.png 您可以在 cupertino_icons 预览页面上看到完整的图标列表,在 flutter.dev 上可以看到迁移详细信息页面

您可以在 iOS 14 上尝试使用 Flutter 的另一个功能是 App Clips,这是 iOS 14 的一项新功能,它支持 10MB 以下轻量级应用程序的快速,无安装应用程序执行。在 Flutter 1.22 版中,我们预览了使用Flutter构建的 App Clip 目标。 2.png A Flutter-powered App Clip experience

有关如何使用Flutter构建应用剪辑的更多详细信息,请查看 flutter.dev上的文档。您也可以参考这个简单的示例项目

支持 Android 11

Flutter 的这个版本也与本月 Android 11 的发布相吻合。Flutter 框架和引擎已更新,以支持最新版本的 Android 中引入的两个新功能。

首先,Flutter 对 Android 凹口,切口和瀑布显示做了支持。 3.png 通过使用 MediaQuerySafeArea API,您可以确保将活动的 UI 和交互式元素放置在设备显示屏的无障碍区域中。另外,您将要避免在瀑布边缘区域使用手势检测器,因为这可能会导致意外触摸。

其次,动画在显示软件键盘时与 Android 11 同步。 4.gif Issue #19279 是一个长期存在的问题,其中系统键盘的显示/隐藏动画与 Flutter 的插图不同步。这在Android 11中已修复。

关于 Android 嵌入 API 的一项说明。去年,随着 Flutter 1.12 版的推出,我们推出了一套适用于 Android 的新Flutter 引擎和 Flutter 插件 API 。我们创建了这些 v2 API,以更好地支持 Android 上的应用程序添加用户。一年后,超过 80% 的 Android 插件使用了新的 Android API。从 1.22 开始,我们不再使用较旧的 v1 API。

如果您仍在使用 Android v1 API,那么这对您意味着:

  • 新创建的插件将不再针对 v1 API
  • Flutter工具的 -no-enable-android-embedding-v2config 标志已被删除,现在是默认行为
  • 仍在使用v1 API的旧版应用程序在构建过程中将显示弃用警告,该警告指向支持新的 Android 插件 API 文档

同时,如果您仍然有基于 v1 Android API 的 Flutter 应用程序,它将继续运行。但是,您可能会开始遇到仅针对 v2 API 的新插件,而这些插件不能被 v1 Android API 使用。有关更多详细信息,请参见重大更改文档

拆分Button(Expanding the Button “universe”)

现有的颤振按钮看起来不错,但可能很难使用,尤其是当你需要自定义主题化。此外,Material 规范已扩展为包括具有新样式的新按钮。

为了使 Flutter 保持与 Material 指南的最新状态,我们很高兴地宣布 Flutter 1.22 中的按钮具有全新的“universe”。

该PR 并没有尝试就地开发现有的按钮类及其主题,而是引入了新的替换按钮小部件和主题。除了使我们摆脱现有类的向后兼容性迷宫之外,新名称还使 Flutter 与 Material Design 规范同步,后者使用了按钮组件的新名称。 5.png A new universe of Material Design buttons 6.png 新主题遵循 Flutter 最近在新 Material 窗口小部件中采用的“规范化”模式。如果您想玩演示,DartPad上有一个很棒的演示。这不是因为语义重大更改 FlatButton,OutlineButton,RaisedButton,ButtonBar,ButtonBarTheme,并且 ButtonTheme 不会改变。您可以根据你的喜欢将旧按钮与新按钮混合使用。

新的国际化和本地化支持

自Flutter创立以来,Flutter提供了您的应用程序国际化(i18n)和本地化(l10n)所需的核心功能。但是,在此版本中,我们将最佳做法的意见纳入了我们的工具中,甚至在添加新的l10n信息时启用了热重装支持来更新您的应用程序。 7.gif 如果您想了解有关Flutter对l10n的支持的更多详细信息,包括本地化消息,带有参数,日期,数字和货币的消息,请阅读 Flutter Internationalization 用户指南

此外,如果您对 i18n 和 l10n 感兴趣,那么您可能也对那些字符串不适合普通的旧ASCII的字符串(例如 Unicode 和emoji)感兴趣。最近,Dart团队发布了该 characters package,该软件包可帮助开发人员处理 Unicode(扩展)字形簇。该软件包有助于解决诸如如何正确地将字符串(如“ A 🇬🇧 text in English”)缩写为前15个字符的问题。使用 String 类,该缩写为“ A 🇬🇧 text in”,它仅是12个用户可感知的字符。另一方面,使用该 characters package 会产生“ A 🇬🇧 text in Eng”的正确缩写。

借助此 PR,Flutter 使用字符包来正确处理这些复杂字符。例如,当使用 TextField 带 maxLength 限制时,像👨‍👩‍👦这样的字符现在可以正确地算作单个字符。同样,使用 此 PR,在 Flutter 所在的项目中,字符包均可自动在项目中使用,而无需手动添加。希望这使得处理来自所有语言环境的各种字符串变得更加容易。有关character包的更多详细信息,请查看出色的文章,正确完成Dart字符串操作👉

Google Maps 和 WebView 插件已准备就绪

在 Flutter 团队中,我们通常会谨慎地将某些标签标记为“生产准备就绪”,直到我们对自己进行彻底测试为止。对于google_maps_flutterwebview_flutter 插件,选通因素(gating factor)一直是底层的 Platform Views 实现,该实现允许将 Android 和 iOS 的本机 UI 组件托管在 Flutter 应用中。在此 Flutter 版本中,我们很高兴地宣布,我们对框架进行了强化,足以将这两个插件都声明为可以投入生产。

8 (1).gif webview_flutter plugin hosting flutter.dev

在Flutter 1.22中,我们添加了一个替代的 Platform Views 实现,该实现修复了所有已知的键盘以及Android视图的可访问性问题。此外,它还适用于 19 级及以上的 Android API(以前要求 20 级)。我们还在 iOS 上进行了线程改进,使平台视图更高效,更可靠(并且不再需要您将io.flutter.embedded_views_preview标志添加到iOS中Info.plist

webview_flutter插件支持新的 Android Platform Views 模式,但当前需要手动启用。一旦在更广泛的社区中得到更多使用,我们将默认在将来的版本中启用它。

Google Maps 和 WebView 插件已经从 Platform Views 的改进中受益。如果您想使用 Platform Views 在 iOS 或 Android 上托管您自己的本机 UI 组件,则可以了解如何在 Flutter 上使用 Platform Views 托管 Native Android 和 iOS view

Navigator 2.0

如果您以前在 Flutter 应用程序中使用过 导航,则可能已经注意到核心数据结构(用户正在浏览的页面堆栈)对您而言是隐藏的。相反,要进行管理,请调用Navigator.pop()_ _或Navigator.push()。例如,假设您要在主页上显示一个 Widget 列表,并允许用户点击一个 Widget 以进入专门用于该颜色的详细信息页面。 9.png 这两个屏幕可以像这样实现:

class ColorListScreen extends StatelessWidget {
 final List<Color> colors;
 final void Function(Color color) onTapped;
 ColorListScreen({this.colors, this.onTapped});
 
 @override
 Widget build(BuildContext context) => Scaffold(
       appBar: AppBar(title: Text('Colors')),
       body: Column(
         children: [
           // you can see and decide on every color in this list
           for (final color in colors)
             Expanded(
               child: GestureDetector(
                 child: Container(color: color),
                 onTap: () => onTapped(color),
               ),
             )
         ],
       ),
     );
}
 
class ColorScreen extends StatelessWidget {
 final Color color;
 const ColorScreen({this.color});
 
 @override
 Widget build(BuildContext context) => Scaffold(
       appBar: AppBar(title: Text('Color')),
       body: Container(color: color),
     );
}

使用最简单的 Navigator 1.0 样式,您可以以看起来非常简单的方式在这两个屏幕之间导航:

class _ColorAppState extends State<ColorApp> {
 List<Color> _colors = [Colors.red, Colors.green, Colors.blue];
 
 @override
 Widget build(BuildContext context) => MaterialApp(
       title: 'Color App',
       home: Builder(
         builder: (context) => ColorListScreen(
           colors: _colors,
           // the Navigator manages the list of pages itself; you can only push and pop
           onTapped: (color) => Navigator.push(
             context,
             MaterialPageRoute(builder: (context) => ColorScreen(color: color)),
           ),
         ),
       ),
     );
}

只需 Navigator.push() 进行调用,即可在第一个页面的顶部 push 一个新的页面,从而创建两页的堆栈。但是,与ColorListScreen 页面 Containers 中的 build 方法中创建的列表 Widget 不同,该堆栈对您是隐藏的。而且由于它是隐藏的,因此很难管理,例如处理由本机嵌入提供的初始路由的深层链接,或者来自 Web 的 URL 或来自Android 的 Intent 。管理同一页面的不同排列之间的嵌套路由也极其困难。

Navigator 2.0 通过使页面堆栈可见而解决了这些问题,甚至更多。下面是在 ColorListScreen 和 ColorScreen 之间导航的更新示例:

class _ColorAppState extends State<ColorApp> {
 Color _selectedColor;
 List<Color> _colors = [Colors.red, Colors.green, Colors.blue];
 
 @override
 Widget build(BuildContext context) => MaterialApp(
       title: 'Color App',
       home: Navigator(
           // you can see and decide on every page in this list
         pages: [
           MaterialPage(
             child: ColorListScreen(
               colors: _colors,
               onTapped: (color) => setState(() => _selectedColor = color),
             ),
           ),
           if (_selectedColor != null) MaterialPage(child: ColorScreen(color: _selectedColor)),
         ],
         onPopPage: (route, result) {
           if (!route.didPop(result)) return false;
           setState(() => _selectedColor = null);
           return true;
         },
       ),
     );
}

该应用程序显式创建一个 Navigator,并为其提供代表完整堆栈的页面列表。我们创建一个空 _selectedColor 来指示尚未选择任何颜色,因此我们不显示 ColorScreen 最初的颜色。当用户选择一种颜色时,我们将 setState() 正常调用以向 Flutter 表示您希望 build() 再次调用该方法,该方法现在会 ColorScreen 在顶部创建一个堆栈。 您可以在 OnPopPage 回调中更新状态,例如,如果用户弹出,则表示他们已“取消选择”当前颜色,因此我们不再希望显示该页面。

如果 Navigator 2.0 看起来像 Flutter 的其余部分,那就是意图——它是声明性的,而 Navigator 1.0 是imperative。这个想法是要在导航和 Flutter 的其余部分之间统一模型,同时解决许多问题并添加功能。实际上,这个小例子几乎不涉及 Navigator 2.0 的内容。有关详细信息,我强烈推荐有关 Flutter 中的声明式导航和路由的文章。

另外,您对 Navigator 1.0 的现有使用将像今天一样继续使用,并且不会在短期内被删除。如果您喜欢该模型,则可以继续使用它。但是,如果您尝试使用Navigator 2.0,我们认为您会喜欢的。

预览版:Android的状态恢复

在此版本中可供您试用的新功能是对 Android 的状态恢复的支持。这是我们最受欢迎的功能之一,拥有 217 个点赞!

对于不熟悉状态恢复需求的用户,移动操作系统可能会杀死后台的应用程序,以回收前台应用程序的资源。发生这种情况时,操作系统会通知该应用被终止以快速保存任何 UI 状态,以便在用户循环回到该应用时可以将其恢复。如果正确实施,则可以为用户提供无缝的体验,同时可以更好地利用设备的资源。直到现在,Flutter 还不支持状态还原,如果没有框架的支持,很难正确地进行状态还原。这就是为什么我们很高兴能够为 Android 提供此功能的基础实现。

这是一个用于恢复默认 Flutter Counter 应用状态的非常简单的示例

class CounterState extends State<RestorableCounter> with RestorationMixin {
  @override
  String get restorationId => widget.restorationId;

  RestorableInt _counter = RestorableInt(0);

  @override
  void restoreState(RestorationBucket oldBucket) => registerForRestoration(_counter, 'count');

  void _incrementCounter() => setState(() => _counter.value++);

  @override
  Widget build(BuildContext context) => Scaffold(
      body: Center(child: Text('${_counter.value}')),
      floatingActionButton: FloatingActionButton(onPressed: _incrementCounter),
    );
}

简要地说,每个小部件都有一个存储桶(storage bucket),并 RestorationMixin 使用唯一 ID 向其注册。通过使用一种 RestorableProperty 类型(如此处使用的类型 RestorableInt)来存储特定于 UI 的数据,并使用状态恢复功能注册该数据,该数据将在 Android 终止该应用程序之前自动进行存储,并在其恢复正常运行时恢复。就是这样。一个储存在一个任何数据 Restoration* 类型,如 RestorableInt,RestorableString 和 RestorableTextEditingController(我们有一堆)将被恢复。而且,如果我们没有涵盖您要还原的所有类型,则可以通过扩展创建自己的类型 RestorableProperty。 10.png 为了自动测试状态恢复,我们向 WidgetTester 添加了新的 restartAndRestore API。要进行手动测试,最简单的方法是在Android设备上启动启用了状态恢复功能的Flutter应用,在Android开发人员设置中启用“不保留活动(Dont't keep activities)”,运行 Flutter 应用,将其置于后台,然后然后回到它。此时,Android 将终止并恢复您的应用程序,因此您可以查看一切是否按预期工作。

虽然我们很高兴将状态恢复的预览版放到您的手中,但还有更多工作要做。例如,状态恢复不仅适用于 Android, iOS 应用程序也可以受益。此外,我们正忙于更新自己的窗口小部件,以在恢复过程中保持其状态。我们已经在Scrollable 类例如 ListView 和 SingleChildScrollView(记住用户的滚动位置)和 TextFields(恢复用户输入的文本)等类中提供了支持,并且我们计划将其扩展到其他小部件。

但是,我们尚未添加的关键恢复支持以及使它成为预览版的原因是 navigation(1.0或2.0)。这意味着您的用户在应用中的位置将不会恢复。该功能即将在 Beta 中发布,并在 Flutter 的下一个稳定版本中发布。

预览版:平滑滚动以提供不匹配的输入和显示频率

当输入和显示频率不同时,Flutter 团队与 Google 内部合作伙伴合作,极大地提高了滚动性能。例如,Pixel 4 输入的运行频率为 120hz,而显示屏的运行频率为 90hz。滚动时,这种不匹配会导致性能下降。使用新的resamplingEnabled 标志,您可以利用我们在 Flutter 中完成的性能工作来解决此问题:

void main() {
  GestureBinding.instance.resamplingEnabled = true;
  run(MyApp());
}

根据所涉及的频率差异,启用此标志可以使滚动时的颤动减少多达 97%。当我们确定这是最好的体验时,我们计划在以后的版本中默认启用此标志。

新的统一Dart开发人员工具

与往常一样,对 Flutter 的更新不仅意味着引擎和框架,还包括工具。Flutter 1.22 包括 Dart(2.10)的新版本,还有一个新的 dart CLI 工具,您可能也会发现它有用。

Dart 历史上有许多较小的开发人员工具(例如 dartfmt 用于格式化和 dartanalyzer 代码分析)。Dart 2.10中的新增功能是 dart 与该 flutter 工具非常相似的统一开发人员工具。 11.png 从今天的 Flutter 1.22 SDK 开始,您将发现该 /bin 文件夹(您可能在其中 PATH)同时包含 flutter 和 dart 命令。有关更多详细信息,请参见 Dart 2.10 博客文章

App size 分析工具

作为 Flutter 1.22 的一部分发布的工具包括一个新的输出大小分析实用程序。此工具可帮助诊断 Flutter,您的应用大小细分是否随时间变化。

您可以通过将 --analyze-size 标志传递给以下任何命令来使用该工具收集分析所需的数据:

  • flutter build apk
  • flutter build appbundle
  • flutter build ios
  • flutter build linux
  • flutter build macos
  • flutter build windows

在构建 Flutter 输出工件时使用此标志可打印工件尺寸和组成的摘要。这包括 native代码、assets、甚至是已编译 的包级细分(package-level breakdown)的 Dart 代码。 12.png Example breakdown of the Flutter Gallery’s release APK

此摘要有助于快速识别应用程序的程序包大小用法中的热点。此外,收集的数据也可以作为 JSON 文件提供在 DevTools 中使用,它允许您进一步探索您的应用内容,定位大小的问题,看到两个不同的 JSON 文件之间的变化通过以下对 flutter.dev 的说明。加载JSON文件后,您将拥有一个界面,该界面为您提供应用大小的树状图。 13.png An example APK breakdown in Dart DevTools

有关您可以使用“应用大小”工具执行的操作的更多详细信息,请阅读 flutter.dev上的 使用 app size 工具的文档

预览版:DevTools中更新的网络页面

此版本中的另一个 DevTools 预览功能是能够在“网络”选项卡中查看 HTTP 和 HTTPs 响应 Body。 14.png 要启用此功能,请确保您通过 flutter channel dev 和 flutter channel upgrade 进入 Flutter 开发者渠道 。

此外,对于具有大量网络流量的应用程序,我们提供了搜索和过滤功能。 15.png 有关“网络”选项卡的文档,请参阅在 flutter.dev 上使用网络视图

IntelliJ 中的托管 DevTools 检查器选项卡

一段时间以来,我们一直在维护某些 Flutter 工具的两个副本,例如 IntelliJ 中的 Inspector 窗格和 Dart DevTools 中的 Inspector 选项卡。这不仅使我们放慢了速度,因为我们必须维护两个代码库,而且某些功能尚未纳入 IntelliJ 插件中,例如 Layout Explorer。因此,为了解决这两个问题,我们启用了直接从 IntelliJ 内部的 Dart DevTools 托管 Inspector 选项卡的功能。 16.png 注意添加了 Layout Explorer,您可以在代码旁边使用它。要启用此选项,请转至 Perferences > Languages & Frameworks > Flutter > Enable embedded DevTools inspector

改进了 Visual Studio Code 中的输出链接

Flutter 开发人员所面临的常规活动是从终端或堆栈跟踪中的错误输出中进行。在适用于 Visual Studio Code 的Flutter 扩展的最新版本中,现在可以正确解析这些链接,以使您可以直接从输出中启用链接。 17.png 看来这是一件小事,但是对于此功能的初步反馈已经非常积极。

与往常一样,此处的工具更改列表太多,但是我建议以下公告以了解详细信息:

焦点顾客: EasyA

EasyA是一款订阅应用程序,旨在使适龄学生通过即时消息与出色的导师联系,并使用 Flutter 编写。最近,它被Apple推荐为“每日应用”。 18.png

“当学校在今年初开始上网时,我们知道我们需要快速启动辅导应用程序来帮助学生。Flutter的惊人发展速度意味着我们能够为iOS和Android实施屡获殊荣的设计,并且还可以发布到Web上—及时锁定!通常,这实际上是不可能的。但是,由于Flutter允许我们同时针对所有三个平台,因此我们能够高效地共享代码,并充分利用我们的小型开发人员团队。”

— > EasyA联合创始人Phil Kwok

重大变化

与往常一样,我们试图将重大更改的数量保持在最少。这是 Flutter 1.22 发行版中的列表。

总结

Flutter 1.22 稳定版虽然在之前的版本之后很快问世,但是其中包含很多好东西,本篇文章不能一一列举。我们希望此版本可以帮助您为 iOS 和 Android 开发出色的应用程序,我们迫不及待想看看您的商店中有什么!感谢您的支持——我们为您打造Flutter。


image.png