微信交流群

支持iOS 14和Android 11,新的i18n和l10n支持,可用于生产的Google Maps和WebView插件,新的App Size工具等等! 作者:Chris Sells

原文:https://medium.com/flutter/announcing-flutter-1-22-44f146009e5f

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

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

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

除了对新的移动操作系统版本的支持外,还有很多其他要分享的新闻,包括预览Android最重要的功能之一:状态恢复,新的“Material 风格按钮“,新的国际化和本地化支持(与热重载一起使用),一个新的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设备上会禁止运行debug应用程序,但实际开发debug除外
  • 针对本地调试的Flutter应用程序的有关网络安全的新策略使iOS 14显示一次性确认对话框(仅在开发过程中,不适用于已发布的Flutter应用程序)

如果您要通过Flutter应用定位iOS 14,我们强烈建议您使用Flutter 1.22对其进行重建,然后立即将其部署到App Store中,以确保您的iOS 14用户获得最佳体验。

有关使用Flutter适配iOS 14的更多详细信息,包括添加Flutter应用到原生应用,deep linking和通知注意事项,请参阅 flutter.dev上的iOS 14文档

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

其中一项功能是对iOS的新SF Symbols字体的更新支持,我们花一些时间更新了cupertino_icon程序包。将cupertino_icons依赖关系更新为新的1.0主要版本后,CupertinoIcons的现有用法将自动映射到新样式。如果您将cupertino_icons 1.0与Flutter 1.22结合使用,那么您还可以通过CupertinoIcons API访问约900个新图标。

您可以在cupertino_icons预览页面上看到图标的完整列表,在 flutter.dev上可以看到迁移详细信息页面

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

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

# Android 11

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

首先,Flutter现在支持多种屏幕适配(比如瀑布屏)。

通过使用MediaQuery和SafeArea API,您可以确保将活动的UI和交互式元素放置在设备显示屏的无障碍区域中。另外,您将要避免在瀑布边缘区域使用手势检测器,因为这可能会导致意外触摸。

其次,动画在显示软件键盘时与Android 11同步。

问题 #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-v2配置标记已删除,现在是默认行为
  • 仍在使用v1 API的旧版应用程序在构建过程中将显示弃用警告,该警告指向支持新的Android插件API文档

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

# 扩展的 Button 组件

现有的Flutter按钮看上去不错,但很难使用,尤其是在需要自定义主题时。此外,“Material”规范已扩展为包括具有新样式的新按钮。

为使Flutter保持与Material指南的最新水平,我们很高兴地宣布Flutter 1.22中的引入全新的按钮。

该PR并没有尝试就地开发现有的按钮类及其主题,而是引入了新的替换按钮小部件和主题。除了使我们摆脱现有类的向后兼容性迷宫之外,新名称还使Flutter与Material Design规范同步,后者使用按钮组件的新名称。

新主题遵循Flutter最近在新Material窗口小部件中采用的“规范化”模式。如果您想玩演示,DartPad上有一个很棒的演示。这并不是一个重大变化,因为FlatButton,OutlineButton,RaisedButton,ButtonBar,ButtonBarTheme和ButtonTheme的语义不会改变。您可以将旧按钮与新按钮混合使用。

# 新的国际化和本地化支持

自Flutter创立以来,Flutter已提供您的应用程序国际化(i18n)和本地化(l10n)所需的核心功能。但是,在此版本中,我们将最佳做法的意见纳入了我们的工具中,甚至在添加新的l10n信息时启用了热重装支持来更新您的应用。

如果您想了解有关Flutter对l10n的支持的更多详细信息,包括本地化消息,带有参数的消息,日期,数字和货币,请阅读Flutter Internationalization用户指南

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

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

# Google Maps和WebView插件准备投入生产

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

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

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

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

如果您以前在Flutter应用程序中使用过导航功能,则可能已经注意到核心数据结构(用户正在浏览的页面堆栈)对您而言是隐藏的。而是要对其进行管理,请调用Navigator.pop()或Navigator.push()。举例来说,假设您想在首页上显示一系列小部件,并允许用户点击一个小部件以转到专门针对该颜色的详细信息页面。

实现如下:

class ColorListScreen extends StatelessWidget {
 final List<Color> colors;
 final void Function(Color color) onTapped;
 ColorListScreen({this.colors, this.onTapped});
 
 
 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});
 
 
 Widget build(BuildContext context) => Scaffold(
       appBar: AppBar(title: Text('Color')),
       body: Container(color: color),
     );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

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

class _ColorAppState extends State<ColorApp> {
 List<Color> _colors = [Colors.red, Colors.green, Colors.blue];
 
 
 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)),
           ),
         ),
       ),
     );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

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

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

class _ColorAppState extends State<ColorApp> {
 Color _selectedColor;
 List<Color> _colors = [Colors.red, Colors.green, Colors.blue];
 
 
 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;
         },
       ),
     );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

该应用程序显式创建一个导航器,并为其提供代表完整堆栈的页面列表。我们创建一个空的_selectedColor,以指示尚未选择任何颜色,因此我们最初不显示ColorScreen。当用户选择一种颜色时,我们通常会调用setState()来向Flutter表示您希望再次调用build()方法,该方法现在会创建一个堆栈,其顶部是ColorScreen。

您可以在OnPopPage回调中更新状态,例如,如果用户弹出,则表示他们已“取消选择”当前颜色,因此我们不再希望显示该页面。

如果Navigator 2.0看起来像Flutter的其余部分,那就是意图-它是声明性的,而Navigator 1.0则是必须的。这个想法是要在导航和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 {
  
  String get restorationId => widget.restorationId;

  RestorableInt _counter = RestorableInt(0);

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

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

  
  Widget build(BuildContext context) => Scaffold(
      body: Center(child: Text('${_counter.value}')),
      floatingActionButton: FloatingActionButton(onPressed: _incrementCounter),
    );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

简要地说,每个小部件都有一个 storage bucket,该storage bucket使用唯一的ID向RestorationMixin注册。通过使用RestorableProperty类型(如此处使用的RestorableInt)来存储特定于UI的数据,并通过State Restoration功能注册该数据,该数据将在Android杀死该应用之前自动存储,并在其恢复正常运行时恢复。就是这样。所有以Restoration *类型存储的数据,例如RestorableInt,RestoableString和RestorableTextEditingController(我们都有很多)都将被还原。而且,如果我们没有涵盖您要还原的所有类型,则可以通过扩展RestorableProperty创建自己的类型。

为了自动测试状态恢复,我们向WidgetTester添加了新的restartAndRestore API。要进行手动测试,最简单的方法是在Android设备上启动启用了状态恢复功能的Flutter应用,在Android开发人员设置中启用“不要保留活动”,运行Flutter应用,将其置于后台,然后然后回到它。此时,Android将终止并恢复您的应用程序,因此您可以查看一切是否按预期工作。

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

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

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

void main() {
  GestureBinding.instance.resamplingEnabled = true;
  run(MyApp());
}
1
2
3
4

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

# 新的统一的Dart开发人员工具

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

Dart历史上有许多较小的开发人员工具(例如,用于格式化的dartfmt和用于代码分析的dartanalyzer)。 Dart 2.10中的新增功能是一个与Flutter工具非常相似的统一的Dart开发人员工具。

从今天的Flutter 1.22 SDK开始,您会发现/ bin文件夹(您可能在PATH中包含该文件夹)同时包含flutter和dart命令。有关更多详细信息,请参见Dart 2.10博客文章

# 应用程式大小分析工具

作为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输出工件时使用此标志将打印工件尺寸和组成的摘要。这包括本机代码,资产,甚至是已编译Dart代码的程序包级细分。

此摘要有助于快速识别应用程序的程序包大小用法中的热点。此外,收集到的数据还可以作为JSON文件使用,供Dart DevTools使用,它使您可以按照flutter.dev上的说明进一步浏览应用程序的内容,查明大小问题并查看两个不同JSON文件之间的更改。加载JSON文件后,您将拥有一个界面,该界面为您提供应用大小的树状图。

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

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

此版本中的另一个DevTools预览功能是能够在“网络”选项卡中查看HTTP和HTTPs响应主体。

要启用此功能,请通过flutter通道dev和flutter通道升级确保您位于Flutter dev通道上。

此外,对于具有大量网络流量的应用,我们提供了搜索和过滤功能。

有关“网络”选项卡的文档,请参阅在flutter.dev上使用网络视图

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

一段时间以来,我们一直在维护某些Flutter工具的两个副本,例如IntelliJ中的Inspector窗格和Dart DevTools中的Inspector选项卡。这不仅会减慢我们的速度,因为我们必须维护两个代码库,而且某些功能尚未纳入IntelliJ插件中,例如布局资源管理器。因此,为了解决这两个问题,我们启用了直接从IntelliJ内部的Dart DevTools托管“检查器”选项卡的功能。

注意添加了Layout Explorer,您可以在代码旁边使用它。要启用此选项,请转至 Preferences > Languages & Frameworks > Flutter > Enable embedded DevTools inspector

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

Flutter开发人员所面临的常规活动是从终端或堆栈跟踪中的错误输出中进行。在适用于Visual Studio Code的Flutter扩展的最新版本中,现在可以正确解析这些链接,以使您可以直接从输出中启用链接。

看来这是一件小事,但是对于此功能的初步反馈已经非常积极。

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

# 客户关注点:EasyA

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

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

EasyA联合创始人Phil Kwok

# 重大变化

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

# 概要

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