【老孟Flutter】Flutter 2的新功能

老孟导读:昨天期待已久的 Flutter 2.0 终于发布了, Flutter Web和Null安全性趋于稳定,Flutter桌面安全性逐渐转向Beta版!

原文链接:https://medium.com/flutter/whats-new-in-flutter-2-0-fe8e95ecc65

今天,我们很高兴地宣布Flutter 2的发布。距离Flutter 1.0的发布已经两年多了,但是在很短的时间内,我们已经关闭了24,541期,并合并了765个贡献者的17,039个PR。自9月Flutter 1.22发布以来,我们已经关闭了5807期并合并了298位贡献者的4091个PR。特别感谢我们的志愿者捐助者,他们慷慨地抽出时间来改进Flutter项目。Flutter 2 release 版本前几名志愿者贡献者是xubaolin46个PR,a14n32个PR,专注于使Flutter达到零安全,hamdikahloun具有20个PR,改善了Flutter插件的数量。但是,不仅仅是编码员为Flutter项目做出了贡献。一大批志愿者PR评审人员还负责评审1525个PR,包括hamdikahloun(再次!),CareFYazeedAlKhalaf(16个!)。Flutter确实是社区的一项工作,如果没有问题提出者,PR贡献者和代码审查者,我们就不可能进入第2版。此版本适用于所有人。

Flutter 2发行版中发生了很多令人兴奋的事情。有关Flutter 2和Dart 2.12的新功能以及我们的客户和合作伙伴如何使用Flutter 2的概述,请参阅宣布Flutter 2。有关Dart 2.12的详细信息,请参阅宣布Dart 2.12。有关建议在生产中使用的Flutter网站的最佳利用方法,请参阅Flutter网站支持达到稳定的里程碑

而且,要了解Flutter 2本身的新功能,请继续阅读!

Web

截止到今天,Flutter的Web支持已经从Beta过渡到稳定渠道。在此初始稳定版本中,Flutter在Web平台的支持下将代码的可重用性提高到另一个层次。因此,现在当您稳定地创建Flutter应用程序时,Web只是该应用程序的另一个设备目标。

通过利用Web平台的众多优势,Flutter为构建丰富的交互式Web应用程序奠定了基础。我们主要专注于性能和渲染保真度的改进。除了我们的HTML渲染器之外,我们还添加了一个新的基于CanvasKit的渲染器。我们还添加了特定于Web的功能,例如Link小部件,以确保在浏览器中运行的应用感觉像Web应用。

Flutter的Web支持博客文章中找到有关此稳定版本的更多详细信息。

Sound Null Safety

空安全性是Dart语言的重要补充,它通过区分可空类型和非可空类型进一步增强了类型系统。这使开发人员能够防止null错误崩溃,这是应用程序崩溃的常见原因。通过将空检查合并到类型系统中,可以在开发过程中捕获这些错误,从而防止生产崩溃。从Flutter 2开始,包含Dart 2.12的稳定版完全支持Null Safety。有关更多详细信息,请参见Dart 2.12博客文章

pub.dev软件包存储库已经发布了1,000多个空安全软件包,其中包括DartFlutterFirebaseMaterial团队的数百个软件包。如果您是软件包作者,请查看迁移指南并考虑立即进行迁移。

Desktop

在此版本中,我们很高兴地宣布,Flutter的桌面支持已在稳定频道中以早期版本的标志提供。这意味着我们已经准备好让您尝试一下它作为Flutter应用程序的部署目标:您可以将其视为“ beta快照”,以预览将于今年晚些时候发布的最终稳定版本。

为了使Flutter桌面达到这样的质量,从大小上进行了改进,从确保文本编辑像在每个受支持的平台上的本机体验一样开始,包括诸如文本选择枢轴点的基本功能以及能够进行文本编辑的能力。在处理完键盘事件后停止传播。在鼠标输入端,现在可以立即开始使用高精度定点设备进行拖动,而不必等待处理触摸输入时所需的延迟。此外,内置的上下文菜单已添加到MaterialCupertino设计语言的TextField和TextFormField小部件中。最后,添加了抓手 到ReorderableListView小部件。

作为开发人员,ReorderableListView总是很擅长移动项目,但是它要求用户长按才能启动拖动。这在移动设备上很有意义,但是很少有台式机用户会想到用鼠标长按某个项目来移动它,因此此版本包括适用于鼠标或触摸输入的抓握手柄。平台惯用功能的另一项改进是更新的滚动条该滚动条可以正确显示桌面形状因素。

此版本包括一个更新的Scrollbar小部件,该小部件在桌面环境中非常有效

滚动条小部件已更新,以提供桌面上预期的交互功能,包括拖动拇指,单击轨道以上下滚动页面以及在鼠标悬停在鼠标的任何部分上时显示轨道的功能。滚动条。此外,由于Scrollbar是使用新ScrollbarTheme类的主题,因此您可以设置其样式以使其与应用程序的外观和风格相匹配。

对于其他特定于桌面的功能,此版本还启用了Flutter应用程序的命令行参数处理功能,以便可以使用诸如Windows File Explorer中的数据文件双击之类的简单操作来打开应用程序中的文件。我们还努力使WindowsmacOS的调整大小更加流畅,并为国际用户启用IME(输入法编辑器)。

图片发布

Flutter桌面现在支持直观的IME输入

此外,我们还提供了更新的文档,介绍了开始准备将桌面应用程序部署到特定于操作系统的商店时需要执行的操作。试试看,如果我们错过了任何事情,请提供反馈。

在尝试使用Flutter桌面Beta时,您可以通过按预期方式切换到Beta通道并根据flutter.dev的指导为目标平台设置配置标志来访问它。此外,我们还制作了稳定通道上可用的beta比特的快照。如果您使用“ flutter config”启用某个桌面配置设置(例如enable-macos-desktop),则可以尝试桌面支持的beta功能,而不必经历漫长的过程才能转移到beta频道,删除Flutter SDK的所有最新Beta版,构建工具等。这非常适合尝试一下或将桌面支持用作简单的“ Flutter Emulator”。

但是,如果您选择停留在稳定的频道上以访问桌面Beta,则不会像切换到Beta或dev频道那样快地获得新功能或错误修复。因此,如果您正在积极地针对Windows,macOS或Linux,我们建议您切换到可更快提供更新的渠道。

当我们接近Flutter桌面的第一个完整的生产质量版本时,我们知道我们还有更多工作要做,包括对与本机顶级菜单集成的支持,更像各个平台的体验的文本编辑以及可访问性支持,以及常规的错误修复和性能增强。如果您认为在台式机达到生产质量之前还需要做其他事情,请确保提供您的反馈

平台自适应应用程序:Flutter Folio示例

现在,Flutter 支持生产应用三个平台(Android,iOS设备和Web)和三个测试版(在Windows,MacOS和Linux)的,一个自然的问题是:如何编写一个应用程序,适应本身以及多个不同尺寸(小,中和大屏幕),不同的输入模式(触摸,键盘和鼠标)和不同的习惯用法(移动,网络和台式机)?为了为我们自己以及世界各地的Flutter开发人员回答此问题,我们委托了Flutter Folio剪贴簿应用程序。

Folio只是一个简单的示例,您希望它可以从一个代码库在多个平台上很好地运行。所谓“好”,是指它在小屏幕,中屏幕和大屏幕上看起来都不错,它利用了触摸,键盘和鼠标输入的优势,并且对于平台的惯用语言也很好用(例如,通过使用网络上的链接和桌面上的菜单)。我们将这种应用称为“平台自适应”,因为它可以很好地适应所运行的任何平台。

如果您想了解如何使自己的应用程序平台具有适应性,可以查看Folio的源代码。将来,期望找到能够更深入地探讨该主题的文档和代码实验室。同时,请查看AloïsDeniel关于该主题的出色博客文章和视频

Google Mobile Ads to Beta

除了Flutter桌面版移至测试版,今天我们很高兴地宣布Flutter的Google移动广告SDK的公开测试版。这是一个全新的插件,除了现有的重叠式广告格式(重叠式横幅广告,非页内广告和奖励视频广告)外,还提供内嵌横幅广告和原生广告。该插件统一了对Ad Manager和Admob的支持,因此,无论您是什么规模的发布商,都可以根据自己的情况量身定制该插件。

我们一直在与一些早期客户一起在私人Beta版程序中试用此插件,其中许多人已成功使用这些新格式启动了他们的应用程序。例如,Sua Musica(最大的拉丁美洲音乐平台,面向拥有1.5万名经过验证的歌手和1000万MAU的独立歌手),使用适用于Flutter的Google移动广告SDK推出了其新的Flutter应用。他们发现印象数增加了350%,点击率增加了43%,eCPM增加了13%。

插件今天可供您使用。作为Flutter Engage的一部分,Andrew Brogdon和Zoey Fan做了一个关于“使用Flutter进行应用获利”的会议(可在Flutter Engage网站上找到),他们在其中讨论了使用Flutter构建的应用的获利策略,以及如何在自己的广告中加载广告Flutter应用。此外,我们在flutter.dev上创建了一个新的Ads页面,您可以在其中找到所有有用的资源,例如插件实施指南内嵌横幅和原生广告代码实验室,以及重叠横幅,非页内广告和奖励视频广告代码实验室。请确保将其签出!

新的iOS功能

仅仅因为我们正在继续提高对其他平台的支持质量,所以不要以为我们忘记了iOS。实际上,此版本带来了与iOS相关的178个PR合并,包括23495(将状态恢复带到iOS),67781(它满足了长期存在的直接从命令行构建IPA而无需打开Xcode的要求)的要求,以及69809,更新了CocoaPods版本以匹配最新工具。此外,Cupertino设计语言实现中还添加了一些iOS小部件。

新的CupertinoSearchTextField提供了iOS搜索栏UI。

图片发布

CupertinoFormSectionCupertinoFormRowCupertinoTextFormFieldRow部件更容易产生与iOS的分段式视觉美学验证表单字段。

图片发布

除了适用于iOS的功能外,在着色器和动画方面,我们还将继续总体上研究iOS和Flutter的性能改进。iOS仍然是Flutter的主要平台,我们将继续努力带来重要的新功能和性能改进。

新的小部件:自动完成和ScaffoldMessenger

此版本的Flutter附带了两个附加的新小部件,即AutocompleteCore和ScaffoldMessenger。AutocompleteCore表示将自动完成功能纳入Flutter应用程序所需的最小功能。

图片发布

自动完成是Flutter经常需要的功能,因此此版本开始提供此功能。您今天就可以使用它,但是如果您对完整功能的设计感到好奇,请查看自动完成设计文档

同样,创建ScaffoldMessenger来处理许多与SnackBar相关的问题,包括能够轻松创建SnackBar以响应AppBar动作,创建SnackBars以在Scaffold过渡之间持久存在的功能,以及能够在SnackBars完成时显示SnackBars的能力。即使用户已导航到具有其他Scaffold的页面,也将执行异步操作。

图片发布

所有这些优点可以从现在开始使用几行代码来显示SnackBars:

final messenger = ScaffoldMessenger.of(context);
messenger.showSnackBar(SnackBar(content: Text(‘I can fly.’)));

正如您可能想象的那样,还有更多的东西。有关详细信息,请在ScaffoldMessenger上观看Kate Lovett的精彩视频

具有Add-to-App的多个Flutter实例

从与许多Flutter开发人员的交谈中我们了解到,您中的许多人没有启动全新应用程序的奢侈心意,但您可以通过将Flutter添加到现有的iOS和Android应用程序中来利用Flutter。此功能称为Add-to-App,是在两个移动平台上重用Flutter代码同时仍保留现有本机代码库的绝佳方法。但是,对于您中的那些人,我们有时会听到,不清楚如何将第一个屏幕集成到Flutter中。将Flutter和本机屏幕交织在一起使导航状态难以维护,并且在视图级别集成多个Flutter会占用大量内存。

过去,其他Flutter实例的存储成本与第一个实例相同。在Flutter 2中,我们将创建额外的Flutter引擎的静态内存成本降低了约99%,每个实例约为180kB。

图片发布

支持此功能的新API可以在beta通道上预览,并在flutter.dev上进行记录,以及一系列演示此新模式的示例项目。通过此更改,我们不再犹豫建议在本机应用程序中创建Flutter引擎的多个实例。

Flutter修复

每当任何框架成熟并使用越来越多的代码库聚集用户时,随着时间的推移,趋势就是避免对框架API进行任何更改,以避免破坏越来越多的代码行。Flutter 2拥有超过500,000个Flutter开发人员,涉及的平台数量越来越多,因此它很快就属于这一类。但是,为了使我们能够随着时间的推移不断改进Flutter,我们希望能够对API进行重大更改。问题是,如何在不中断开发人员的情况下继续改进Flutter API?

我们的答案是Flutter Fix

Flutter Fix是事物的组合。首先,dartCLI工具有一个新的命令行选项,名为dart fix,它知道在哪里可以查找已弃用的API列表以及如何使用这些API更新代码。其次,它是可用修补程序本身的列表,与版本2捆绑在一起。最后,它是针对VS Code,IntelliJ和Android Studio IDE的更新的Flutter扩展集,它们知道如何公开相同的内容。可用的修复程序列表,如带小灯泡的快速修复程序,可帮助您单击鼠标来更改代码。

举例来说,假设您的应用中包含以下代码行:

使用不推荐使用的参数创建Flutter小部件

由于不赞成使用此构造函数的参数,因此应将其替换为以下内容:

图片发布

图片发布

创建一个Flutter小部件,其中不推荐使用的参数已替换

即使您熟悉所有Flutter的弃用,您在代码中必须进行的更改数量也就越大,应用所有修补程序的难度就越大,并且更容易出错。人类在这类重复性任务上并不擅长。但是计算机是;通过执行以下命令,您可以看到我们知道如何在整个项目中进行的所有修复:

$ dart fix --dry-run

如果您想批量应用它们,可以轻松地这样做:

$ dart fix --apply

或者,如果您想在自己喜欢的IDE中以交互方式应用这些修补程序,也可以这样做。

图片发布

多年来,我们一直在将旧的API标记为已弃用,但是现在有了关于何时删除实际已弃用的API的政策,Flutter 2是我们第一次这样做。即使我们尚未捕获所有已弃用的API作为数据来提供Flutter Fix,我们仍将继续从先前已弃用的API中添加更多信息,并将在未来的重大更改中继续这样做。我们的目标是尽最大努力使Flutter的API达到最佳状态,同时还要使您的代码保持最新。

Flutter DevTools

为了清楚说明DevTools是用于调试Flutter应用程序的工具,我们在调试Flutter应用程序时将其重命名为Flutter DevTools。此外,我们还做了很多工作,以使其达到Flutter 2的生产质量。

一项即使在您启动DevTools之前也可以帮助您解决问题的新功能是,Android Studio,IntelliJ或Visual Studio Code能够在出现常见异常时发出通知,并提供将其引入DevTools中以帮助您调试的功能它。例如,以下内容显示您的应用程序中已引发溢出异常,该异常会在Visual Studio Code中弹出一个选项,用于调试DevTools中的问题。

图片发布

Flutter IDE扩展会在您的应用引发布局溢出异常时发出通知

按下该按钮可将您带到出现问题的小部件上的DevTools中的Flutter Inspector,因此您可以对其进行修复。今天,我们仅针对布局溢出异常执行此操作,但我们的计划是针对所有常见异常提供这种处理,DevTools可以解决这些异常。

一旦运行了DevTools,选项卡上的新错误标记将帮助您跟踪应用程序中的特定问题。

图片发布

DevTools中的红点可帮助您专注于出现错误的应用程序部分

DevTools的另一个新功能是能够轻松查看分辨率比显示的图像高的图像,这有助于跟踪过多的应用程序大小和内存使用情况。要启用此功能,请在Flutter Inspector中启用“反转超大图像”。

图片发布

启用“反转超大图像”选项,以突出显示比需要放大的图像大的图像。

现在,当您显示分辨率明显大于其显示尺寸的图像时,该图像将上下颠倒显示,以便在您的应用中轻松查找。

图片发布

实际应用中的“反转超大图像”选项

此外,根据大众的需求,除了在Flutter Inspector的“布局资源管理器”中显示有关灵活布局的详细信息外,我们还添加了显示固定布局的功能,使您能够调试各种布局。

图片发布

新的版式资源管理器显示了固定版式和弹性版式的版式详细信息

这还不是全部。这只是Flutter DevTools 2中更多新功能的摘要:

  • 在Flutter框架图中添加了平均FPS信息并提高了可用性
  • 用红色错误标签在网络事件探查器中调出失败的网络请求
  • 新的内存视图图表更快,更小且更易于使用,其中包括用于描述特定时间活动的新悬浮卡。
  • 将搜索和过滤添加到“日志记录”选项卡
  • 在启动DevTools之前跟踪日志,因此启动时可以查看完整的日志历史记录
  • 将“性能”视图重命名为“ CPU Profiler”,以使其更清楚地提供什么功能
  • 向CPU Profiler火焰图添加了时序网格
  • 将“时间轴”视图重命名为“性能”,以便更清楚地了解其提供的功能

而这并非全部。对于全套更改,我建议以下公告:

Android Studio / IntelliJ扩展

用于IntelliJ系列IDE的Flutter插件也为Flutter 2获得了许多新功能。首先,有一个新的项目向导,它与IntelliJ中的新向导样式匹配。

图片发布

图片发布

另外,如果您正在Linux上使用IntelliJ或Android Studio对从Snap Store安装Flutter SDK进行编程,则Flutter快照路径已添加到已知SDK路径列表中。这使Flutter快照的用户可以更轻松地在“设置”中配置Flutter SDK。感谢MarcusTomlinson @的贡献!

图片发布

通过Snap安装的Flutter SDK,可以更轻松地使用Linux上的Android Studio。

您可以在公告中阅读更多有关最新更新的内容:

  • IntelliJ插件M51
  • IntelliJ插件M52
  • IntelliJ插件M53
  • IntelliJ插件M54

Visual Studio代码扩展

Visual Studio Code的Flutter扩展也对Flutter 2进行了改进,从许多测试增强功能开始,包括重新运行仅失败的测试的功能。

图片发布

经过两年的开发,对Dart的LSP(语言服务器协议)支持现已作为默认方式提供给Dart分析器,以将其集成到Flutter扩展的Visual Studio Code中。LSP支持对Flutter开发进行了许多改进,包括能够在当前Dart文件中应用某种类型的所有修复程序,并使代码完成生成完整的函数调用(包括括号和必需的参数)的功能。

图片发布

图片发布

LSP的支持不仅限于Dart。它还支持pubspec.yamlanalysis_options.yaml文件中的代码完成。

图片发布

这些只是Flutter的Visual Studio Code扩展最近获得的一些更新。您可以在以下公告中阅读完整列表:

  • Visual Studio代码插件v3.16
  • Visual Studio代码插件v3.17
  • Visual Studio代码插件v3.18
  • Visual Studio代码插件v3.19
  • Visual Studio代码插件v3.20

DartPad已更新为支持Flutter 2

如果不提及DartPad,则该工具更新列表将不完整,而DartPad已更新为支持Flutter 2。

图片发布

DartPad已针对Flutter 2更新

现在,您可以尝试使用Flutter的新的空安全版本,而无需离开自己喜欢的浏览器。

生态系统更新

Flutter的开发经验不仅包含框架和工具,还包括其他内容。它还包括适用于Flutter应用程序的各种软件包和插件。自上一次Flutter稳定版本发布以来,该领域也发生了很多事情。例如,在摄像机和video_player插件之间,已合并了将近30个PR,以大大提高两者的质量。如果您以前在使用这两种方法时遇到麻烦,则应该再看一遍;我们认为您会发现它们更加强大。

另外,如果你是一个火力地堡的用户,我们很高兴地宣布,最流行的插件已被带到生产质量,包括空安全的支持,以及全套的参考文档和常见的使用教程使用Android,iOS,网页,和macOS。这些插件包括:

  • 验证
  • 云消防站
  • 云功能
  • 云消息传递
  • 云储存
  • 速溶药

另外,如果您正在寻找应用程序的崩溃报告,则可能需要考虑Sentry,该公司已经发布了适用于Flutter应用程序的新SDK

图片发布

Sentry崩溃报告工具现在支持Flutter

借助Sentry的Flutter SDK,您可以实时收到在Android,iOS或本机平台上发生的错误的通知。您可以在Sentry文档中查看详细信息。

此外,如果您还没有看到Flutter Community的“ plus”插件,则需要将其签出。他们分叉了Flutter团队最初开发的许多受欢迎的插件,并添加了null安全支持,对其他平台的支持和一整套全新的文档,以及开始修复flutter / plugins存储库中的适当问题。该插件包括以下内容:

  • Android闹钟+
  • Android Intent +
  • 电池+
  • 连通性+
  • 设备信息+
  • 网络信息+
  • 套餐信息+
  • 传感器+
  • 分享+

此时,与Flutter兼容的软件包和插件集的数量超过15,000,这使得很难找到您应该首先考虑的软件包和插件。因此,我们会发布发布点数(静态分析得分),受欢迎程度,喜欢度,并且,对于特别高的质量,会发布那些特别标记为Flutter Favorite的包装。为了及时应对Flutter 2,我们在收藏夹列表中添加了几个新软件包:

  • animation_text_kit
  • bottom_navy_bar
  • 斩波器
  • font_awesome_flutter
  • flutter_local_notifications
  • just_audio

恭喜这些软件包的作者!如果您尚未签出它们,或者尚未列出列表中的其余软件包,则应该这样做。

最后但并非最不重要的一点是,对于对软件包的最新版本是否适用于Flutter的最新版本感兴趣的软件包作者或软件包用户,您将需要访问Codemagic的新pub.green网站。

图片发布

Codemagic的新pub.green网站显示了最新Flutter版本与顶级软件包的兼容性

pub.green网站测试了pub.dev上可用的Flutter和Dart软件包与不同Flutter版本的兼容性。将其视为Flutter的“我可以使用”。有关更多详细信息,我建议CodeMagic团队发布公告博客

重大变化

我们对Flutter 2进行了以下重大更改,其中许多可以使用dart fix命令或所选IDE中的快速修复程序自动缓解:

  • 61366继续剪辑行为更改
  • 66700默认FittedBox的clipBehavior为无
  • 68905从Cupertino颜色分辨率API删除nullOk参数
  • 69808从Scaffold.of和ScaffoldMessenger.of删除nullOk,为两者创建
  • 68910从Router.of中删除nullOk参数,并使其返回不可为空的值
  • 68911添加maybeLocaleOf到本地化
  • 68736在Media.queryOf删除nullOK
  • 68917从Focus.of,FocusTraversalOrder.of和FocusTraversalGroup.of中删除nullOk参数
  • 68921从Shortcuts.of,Actions.find和Actions.handler中删除nullOk参数
  • 68925从AnimatedList.of和SliverAnimatedList.of中删除nullOk参数
  • 69620从BuildContex中删除不赞成使用的方法
  • 70726从Navigator.of中删除nullOk参数,并添加Navigator.maybeOft
  • 72017删除不推荐使用的CupertinoTextThemeData.brightness
  • 72395.HoverEvent中删除不建议使用的[PointerEnterEvent,PointerExitEvent]。
  • 72532删除不建议使用的showDialog.child
  • 72890删除不推荐使用的Scaffold.resizeToAvoidBottomPadding
  • 72893删除不赞成使用的WidgetsBinding。[deferFirstFrameReport,allowFirstFrameReport]
  • 72901删除不推荐使用的StatefulElement.inheritFromElement
  • 72903删除不推荐使用的Element方法
  • 73604删除不建议使用的CupertinoDialog
  • 73745从库比蒂诺[Sliver] NavigationBar删除不赞成使用的actionForegroundColor
  • 73746删除不赞成使用的ButtonTheme.bar
  • 73747删除跨度弃用
  • 73748删除弃用的RenderView.scheduleInitialFrame
  • 73749删除不赞成使用的Layer.findAll
  • 75657从Localizations.localeOf删除残留的nullOk参数
  • 74680Actions.invoke删除nullOk,添加Actions.maybeInvoke

概括

最后,我们在Google Flutter团队的所有成员中,我们要说-谢谢。感谢×150,000,在过去两年中,社区中推出了超过150,000个Flutter应用程序。万一您错过了它,我们会在Flutter Engage主题演讲的开幕式中播放针对社区的Mashup Video,其中汇集了一些我们最喜欢的Flutter应用程序。

没有您对我们所有人正在创造的东西的持续支持和激动,就不可能成为世界上最具活力的全球开发者社区之一。我们迫不及待想看看您接下来将要做什么。

交流

老孟Flutter博客(330个控件用法+实战入门系列文章):http://laomengit.com

添加微信或者公众号领取 《330个控件大全》和 《Flutter 实战》PDF。

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

posted on 2021-03-07 22:56  老孟Flutter  阅读(1508)  评论(2编辑  收藏  举报

导航