观摩!Flutter 1.22 正式发布

Flutter 1.22 正式发布!

继 9 月 23 号发布 Flutter Windows 内测版 之后刚过几天,Flutter 官方在昨夜凌晨正式发布了 Flutter 1.22。

本次版本的升级又带来了新一轮地功能发布,性能改进和问题修复。恰逢移动平台新版本(iOS 14/Android 11)的发布季,此次的版本更新保证了 Flutter 应用在 Android 11 和 iOS 14 上的兼容性,面向 iOS 14,本次更新包括了对 Xcode 12,新 Icon 的更新以及 App Clips 功能的预览。对于Android 11,此次更新包括了多种屏幕适配以及软键盘动画的流畅性优化。

距离上个版本发布刚刚两个月,此次版本的更新最为快速,但质量却依然没有下降,Github 数据显示此次更新共解决了 3,024 个 issue,合并了 197 个贡献者的 1,944 个PR,而在这些贡献者中有 114 位(58%)来自社区的支持,他们共提交了 271 个PR,贡献量最大的是 a14n,共提交了 20 个 PR,

除了对新平台的全力支持外,Flutter 的本次更新也迎来了很多值得分享的话题,包括社区讨论最为热烈的 Android 状态恢复,新的 Material 按钮组件以及国际化和本地化支持与热重载并用等功能。此次更新也包括了全新的导航器(Navigator),稳定版 Platform Views (支持 Google Maps 和 WebView 插件)以及高频率设备下滚动性能的优化,同时,开发工具的更新也迎来了另一番景象,具体读者们详见正文。

新平台适配

iOS 14

每当 Android/iOS 等平台推出系统的新版本时,Flutter 都会进行全面的整改来避免出现不兼容的现象。因此,iOS 14 的发布也推动了 Flutter 的新一轮更新,主要包括如下几点:

  • XCode 12 仅支持 iOS 9.0 以上的版本,因此 Flutter 项目已将默认支持的版本从 8.0 更新到了 9.0。
  • Flutter 1.22 修复了在 iOS 14 系统下的的闪退和字体渲染的问题。
  • 自 Flutter 1.20.4 起也已完全解决了部署到真机设备上出现的各种问题。
  • 当应用程序访问其剪贴板时,会导致 Flutter 应用程序弹出错误通知,该问题也已在 1.20.4 中解决。
  • iOS 14 上存在禁止在设备上运行 debug 应用程序的限制(实际开发调试过程除外)。
  • 考虑到网络安全性的问题,本地调试的 Flutter 应用程序会在 iOS 14 上显示一次性确认对话框(仅开发期间)。

如果你的 Flutter 应用程序需要运行在 iOS 14 系统上,我们强烈建议你将 Flutter 版本更新到 1.22 并立即部署到 App Store 中,这样可以确保你的 iOS 14 用户获得最佳体验。

有关 Flutter 如何适配 iOS 14 的更多信息,包括如何添加到原生应用、deep linking 等问题,可以参阅官网 iOS 14文档

我们的目标一直是希望开发者们能完全脱离所有工具和 SDK 的更新而者专注于应用本身的业务逻辑,这就要求我们需要充分支持 iOS 14 的各种新的特性。

本次,我们就针对 iOS 新发布的 SF Symbols 字体做了更新支持,对 cupertino_icon 库做了一系列的更新,现在只需要将 cupertino_icon 更新到最新的 1.0 版本,就能自动将 CupertinoIcons 映射成新样式的图标,Flutter 1.22 后,CupertinoIcons 也额外提供了 900 个新图标。

读者们可以在 cupertino_icons 预览页面上看到完整的图标列表,详情参见迁移详细信息页面

开发者可以在 iOS 14上 尝试使用 Flutter 的另一个功能就是 App Clips(轻应用),这是 iOS 14 推出的一项新功能,它支持 10MB 以下轻量级应用程序的快速,免安装打开,而在 1.22 版中,我们就可以试一下 Flutter 在 iOS 上支持的 App Clip 功能了。

Flutter App Clip

有关如何使用 Flutter 构建 App Clip 的更多详细信息,参见官方文档,也可以参考这个简单的示例项目

Android 11

Flutter 的此次更新也同样同步了本月发布的 Android 11。为了支持 Android 11 中引入的两个新功能,Flutter 框架层和引擎层都已做了相应的更新。首先,Flutter 现在已经支持多种全新 Android 屏幕的适配,如下图:

通过使用 MediaQuerySafeArea 这两个组件,开发者就可以确保将展示的 UI 和交互式组件放置在设备显示屏的无障碍区域中。另外,目前我们需要尽量避免在瀑布屏边缘区域使用手势检测器,因为这些手势检测器可能会导致意外触摸。

其次,显示软件键盘时的动画也已经与 Android 11 同步。

此前, Flutter 一直存在 #19279 这个问题,其中系统键盘的显示/隐藏动画与 Flutter 并不同步,这个问题也已经在此次更新中被修复。

关于 Android 插件 API。去年,Flutter 1.12 退出了一套全新的 Flutter 插件 API,我们开发了 v2 API 使开发者们能够更好的将 Flutter 嵌入到已有的原生应用中。据我们统计,到目前为止已经有超过 80% 的 Android 插件使用了新的 Android API 了,因此,从本次发布 1.22 开后,我们便不再维护旧的 v1 API。

如果仍在使用 Android v1 API,可能会导致如下问题:

  • 无法使用新开发的插件
  • Flutter工具的 —no-enable-android-embedding-v2config 标志已被默认删除
  • 仍在使用 v1 API 的旧版应用程序在构建期间会显示弃用警告,并指向支持新的Android插件API文档

同时,如果你仍然有基于 v1 Android API 的 Flutter 应用程序,它虽然能够正常运行,但是很可能会使用遇到仅支持 v2 API 的新插件,而这些插件不能被 v1 Android API 使用。更多详细信息,请参见重大更改文档

全新的 Button 组件

之前的版本中,Flutter 已经有了一套完备的按钮组件,但使用起来却很麻烦,Material 规范也增加了多个新样式的按钮。所以,为了使 Flutter 保持与 Material 的同步,我们正式地宣布 Flutter 1.22 将引入全新的 “Button” 按钮。

新的 Button 组件的命名规范也与 Material Design 规范,如下。

DartPad 上有一个非常好的在线演示示例,同时,之前的 FlatButtonOutlineButtonRaisedButtonButtonBarButtonBarTheme 并不会被弃用,开发者可以按照需求混合使用旧按钮与新按钮。

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

自 Flutter 发布以来,已经为应用提供了较好的国际化(i18n)和本地化(l10n)所需的核心功能的支持,而在此次的新版本中,我们也将该功能的最佳实践纳入了我们的开发工具中,并且,在添加新的 l10n 信息时启用了热重装支持来直接更新应用程序。

如果你想了解有关 Flutter l10n 的更多信息,包括本地化消息,带有参数,日期,数字和货币的消息,请参见 Flutter Internationalization 用户指南

此外,如果你对 i18n 和 l10n 感兴趣,你可能还对那些字符串不包含在普通 ASCII 字符的字符串,例如 Unicode 和 emoji 的问题比较惯性。本次,Dart 团队也发布了 characters 软件包可以帮助开发人员处理 Unicode(扩展)字符簇。该库可以帮助开发者们解决诸如如何正确地将字符串(如“ A 🇬🇧 text in English”)缩写为前 15 个字符的问题,使用 String 类,该字符串可以缩写为 “ A 🇬🇧 text in”,它仅是 12 个用户可感知的字符。另一方面,使用 characters 也可以生成 “A 🇬🇧 text in Eng” 的正确缩写。

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

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

Flutter 团队通常会经过仔细考虑后才会将某些标签标记为 “production ready”,在此之前,我们通常都会对其进行了全面测试。对于google_maps_flutterwebview_flutter 这两个插件底层都是使用 Platform Views 实现,从而允许将 Android 和 iOS 的原生 UI 组件嵌入在 Flutter 应用程序中。在此次的 Flutter 版本中,我们欣然宣布,我们已经对框架层进行了强化,完全能够将这两个插件都声明为可投入生产(即 “production ready”)。

在 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 的改进中受益。如果你想使用平台视图在 iOS 或 Android 上嵌入自己的原生 UI 组件,可以参阅 Hosting native Android and iOS views in your Flutter app with Platform Views

如果你之前在 Flutter 应用程序中使用过 Navigator,则可能已经注意到核心数据结构(用户正在浏览的页面路由栈)对你是不可见的。每次要进行管理时,需要调用 Navigator.pop()Navigator.push()。例如,假设你要在主页上显示一系列组件,并允许用户点击一个组件以进入该颜色的详细信息页面,如下图。

我们可以使用下面这种方式实现这两个简单的 UI 页面:

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() ,即可在第一个页面打开第二个页面,从而在路由栈中创建两个页面的实例,但是,和在 ColorListScreen 中的 build 方法中显式地创建 Containers 列表不同,该路由栈并不可见,因此很难管理一些特殊情况,如处理由原生嵌入提供的初始路由的 deep linking,或者来自 Web 的 URL 或来自 Android 的 intent,管理同一页面的不同顺序之间的嵌套路由也极其困难。

Navigator 2.0 通过使页面堆栈可见解决了这些问题,甚至更多。下面这段代码是在 ColorListScreenColorScreen 之间的另一个版本 :

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 顶部创建一个 ColorScreen 页面。

你可以在 OnPopPage 回调函数中更新返回的状态,例如,如果用户回退,则表示他们 “取消选择” 了当前颜色,从而 _selectedColor = null 表示不再希望显示该页面。

Navigator 2.0 看起来像 Flutter 的其余部分,那正是她的意图,它是声明性的,与 Navigator 1.0 势在必行,这个想法是要在导航和Flutter 的其余部分之间统一模型,同时解决许多问题并添加功能。实际上,这个小例子几乎还不涉及 Navigator 2.0 的内容。有关详细信息,推荐阅读 Declarative navigation and routing in Flutter

另外,Navigator 1.0 依然可以继续使用,短期内也不会失效,如果你已经喜欢这种路由模式,完全可以继续使用它。但是,如果你尝试使用 Navigator 2.0,我们认为你会喜欢的。

预览功能

Android 的状态还原

在此次的新版本中还能够试用的新功能是 对Android的状态还原的 支持。这是我们在 Github 上最受欢迎的功能之一,拥有 217 个点赞!

考虑到读者们可能不熟悉状态还原这个需求。移动操作系统可能会杀死后台的应用程序,以回收前台应用程序的资源。发生这种情况时,操作系统会通知该应用已经被终止,这样开发者就可以快速保存当前 UI 状态,以便在用户再次回到该应用时可以将其恢复。如果该功能完善,就可以为用户提供无缝的体验了,同时也可以更好地利用设备的资源。目前,Flutter 还病不支持状态还原,如果没有框架层的支持,也很难自行地进行状态地还原,因此,在 Flutter 1.22 中我们也宣布推出该功能的基础实现。

下面是一个用于恢复默认 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* 可以储任何类型的数据,如RestorableIntRestorableStringRestorableTextEditingController(等等)都将可以被恢复。

如果系统内置没有涵盖你要还原的数据类型,也可以通过 RestorableProperty<T> 创建自己的类型 。

为了实现状态恢复的自动测试,我们也向 WidgetTester 增加了全新的 restartAndRestore API。如果想要手动测试,最简单的方法就是在 Android 设备上打开已经启用状态恢复的 Flutter 应用,在 Android 开发人员设置中启用“不要保留活动”(如下图),然后运行 Flutter 应用,将其置于后台,之后再返回。此时,Android 系统就会先终止再恢复你的应用程序了,你可以查看一切是否按预期工作。

图片发布

虽然我们已经推出了状态恢复的预览版,但还有很多其他的工作要做。例如,状态恢复不仅需要适用于 Android,iOS 应用程序也应当及时同步。此外,我们也正着手优化自己的内置组件,以在恢复过程中默认保持其状态。我们已经在 ListViewSingleChildScrollView(记住用户的滚动位置)和 TextFields (恢复他们输入的文本)类中提供了该功能支持,我们也正计划将其扩展到其他组件中。

然而,由于 navigation(1.0 或 2.0)的原因,该功能目前也才出狱预览版,,也就是说,你的用户还不能体验该功能,我们即将会在 Beta 中发布,并在 Flutter 的下一个稳定版本中正式发布。

滚动性能优化

由于存在输入和显示频率不同步的情况,Flutter 团队也与 Google 内核部门合作,极大地提高了页面滚动性能。例如,Pixel 4 输入的运行频率为 120hz,而显示屏的运行频率为 90hz,滚动时,这种不匹配会导致性能下降。使用新的 resamplingEnabled 标志,你就可以解决此问题,如下:

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 tool 类似。

“dart help”输出的屏幕截图。

从 Flutter 1.22 SDK 开始,你就会发现 / bin 文件夹会同时包含 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 输出 artifact 时可以打印 artifact 尺寸和组成的信息,包括本机原生代码,资源,甚至是已编译 Dart 代码的程序包级的细分。

Flutter Gallery realse APK 包大小分析

该信息有助于快速识别应用程序的程序包大小使用中的关键点。此外,收集的数据也可以作为使用 JSON 文件中 Dart DevTools,这允许你能够进一步探索应用的内容,解决包大小大小的问题,如下,通过 flutter.dev 的说明,可以观察两个不同的 JSON 文件之间的变化。加载 JSON 文件后,你将看到一个界面,该界面会提供应用大小的树状图。

Dart DevTools 中的 APK 故障示例

关于“应用大小”工具执行的操作的更多详细信息,可以阅读 the Using the app size tool docs

DevTools - 网络页面

此版本中的另一个 DevTools 更新是能够将 HTTP 和 HTTPS 的响应(Response)主体作为 “网络“ tab 中的一部分。

图片发布

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

图片发布

有关该 “网络” tab 的文档,可以参阅 Using the Network View

DevTools - Inspector

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

图片发布

值得关注的是这里添加了 Layout Explorer,你可以在代码旁边即刻使用它。要开启此功能,可以选择菜单 Preferences > Languages & Frameworks > Flutter > Enable embedded DevTools inspector

Visual Studio Code

所有 Flutter 开发人员都需要面临的一个场景是从终端或堆栈跟踪中查找错误输出。在 Visual Studio Code 的 Flutter 最新版扩展程序中,现在可以正确解析这些链接,你可以直接从输出中打开链接。

虽然看着这是一件小事,但我们已经收到了很多积极的反馈。

与往常一样,此处的工具更改项太多,可以从以下公告中了解详细信息:

优秀案例:EasyA

EasyA 是一款可订阅应用,旨在帮助适龄学生通过即时消息与优秀的导师联系,该应用使用 Flutter 开发,最近,它被 Apple 推荐为了 their App of the Day

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

EasyA 联合创始人 Phil Kwok

重大更新

与往常一样,我们会尽量保有较少的重大更新。这是 Flutter 1.22 发行版中的列表。

概要

Flutter 1.22 稳定版会很快推出,其中真的包含了很多值得我们学习的东西,这篇文章也并不能一一列举。我们希望此版本可以帮助你在 iOS 和 Android 平台上开发更出色的应用!感谢你的支持。

延伸阅读

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

我的博客:https://meandni.com/2020/09/28/d206/

关注公众号「Meandni」,及时阅读移动开发技术和最新技术动态。

扫一扫,Meandni

文章作者: Joker
文章链接: https://meandni.com/2020/10/02/d81/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Joker's Blog
支付宝打赏
微信打赏