Flutter Web 支持现已进入稳定版
作者 / Mariam Hasnany, Product Manager, Flutter
我们对 Flutter 的愿景是成为一个可移植的 UI 框架,在全平台上构建精美的应用体验。做为 Flutter 2 发布内容的一部分,Flutter 的 web 支持已经抵达稳定版里程碑。
Flutter 的首个版本支持 iOS 和 Android,开发者们已经用它在移动应用商店发布了超过 15 万个应用。现在,随着 web 支持的加入,这些应用可以触达更广泛的受众,同时也开辟了在 web 上建立交互体验的新途径。
渐进式 web 应用 (Progressive web apps, PWA),兼具 web 的高覆盖面与桌面应用的强大功能。
单页应用 (Single page apps, SPA),只需一次加载,并与互联网服务动态互传数据。
将现有 Flutter 移动应用拓展到 web,在两个平台共享代码。
iRobot Education https://edu.irobot.com/the-latest/building-a-coding-experience-for-all iRobot Coding 应用 https://code.irobot.com/
Web 之旅
如今的 web 平台比以往任何时候都要丰富多彩,开发者可以使用的工具包括: 硬件加速的 2D 和 3D 图形,离线功能和安装体验,以及对底层操作系统和硬件的访问等。在 web 这个底层平台上已经建立起了种类繁多的框架,因此,开发者在创建 web 应用时拥有极大的灵活性。
WebGL: 用于 web 的 2D 和 3D 图形
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
PWA
https://web.dev/progressive-web-apps/
对底层操作系统和硬件的访问
https://web.dev/fugu-status/
种类繁多的框架
https://vuejs.org/
https://angular.io/
https://flask.palletsprojects.com/
https://reactjs.org/
Dart
https://dart.cn/
框架,用于为 widget、动画和手势等常见的习惯用法提供抽象 引擎,使用公开的系统 API 在目标设备上进行渲染
技术概览: 层结构 https://flutter.cn/docs/resources/technical-overview#layer-cakes-are-delicious
框架本身采用 Dart 编写,大约 70 万行 Flutter 框架核心代码在所有平台上相同: 包括移动端、桌面端和现在的 web 端。对于您的代码来说也是这样,我们使用 Dart 开发编译器 (dartdevc) 或 Dart 部署编译器 (dart2js) 将您的代码编译成 JavaScript,这些 JavaScript 代码可以托管在服务器上。
dartdevc 命令 https://dart.cn/tools/dartdevc dart2js 命令 https://dart.cn/tools/dart2js
由于 Dart 拥有将 Flutter 框架 (以及开发者的应用代码) 编译成 JavaScript 的能力,我们对 web 的支持工作就变成了用映射 web 平台 API 的代码来取代移动应用所使用的底层 C++ 渲染引擎。Flutter 并不会简单地将 widget 移植为 HTML 里的等价组件,Flutter 的 web 引擎为开发者提供了两种渲染器: 一个是针对尺寸和兼容性进行优化的 HTML 渲染器,另一个则是使用 WebAssembly 和 WebGL 通过 Skia 绘图命令向浏览器画布进行渲染的 CanvasKit 渲染器。
我们对 Flutter 的要求是,提供一种针对 web 平台进行开发的新方式,在现有基础上提供新见解,为所有人提供更棒的 web 体验。
发布生产环境可用的稳定版本
自从 web 支持的测试版在一年前发布以来,我们已经了解了很多早期采用者的使用情况,并已与部分客户合作,他们现在已经将自己的 Flutter web 应用投入生产。
在此期间,我们对架构进行了重大改进,增加了一些功能,以便扩展和优化 Flutter 的 web 支持,新增内容主要集中在四个方面: 性能、web 专属功能、桌面硬件适配,以及插件。
自推出早期版本至今,性能是提升最显著的。在开发过程中,我们对 web 上各种渲染技术的性能和准确性特征有了更深入的了解。
我们最早的工作是基于 DOM 的 HTML。在这种渲染模式中,Flutter 的 web 引擎会将每个生成的 Flutter 场景转换为 HTML、CSS 或 Canvas,并以 HTML 元素树的形式在页面上渲染为一帧。虽然 HTML 渲染器能够最大限度地兼容各种浏览器,且其代码体积较小,但 HTML 渲染器的重绘性能不太适合 Rive (使用 Flutter 构建而成,用于创建动态图像的协作工具) 这种图形密集型应用。
Rive https://rive.app/
为了提供高效渲染密集图形所需的保真度,我们开始尝试使用 CanvasKit,它可使用 WebAssembly 和 WebGL 通过 Skia 绘制命令在浏览器中进行渲染。我们发现 CanvasKit 渲染器的性能、保真度和准确度都更加理想,请看 Flutter 社区中才华横溢的德国开发者 Felix Blaschke 的 Flutter Plasma 演示——用 CanvasKit 创造的惊艳特效。
CanvasKit https://skia.org/user/modules/canvaskit WebAssembly https://webassembly.org/ WebGL https://www.khronos.org/webgl/ Felix Blaschke https://github.com/felixblaschke Flutter Plasma https://flutterplasma.dev/
HTML 渲染器: 结合了 HTML 元素、CSS、Canvas 和 SVG。该渲染模式的下载文件体积较小。 CanvasKit 渲染器: 渲染效果与 Flutter 移动和桌面端完全一致,性能更好,widget 密度更高,但增加了约 2MB 的下载文件体积。
官方文档: Web 渲染器 https://flutter.cn/docs/development/tools/web-renderers
在 web 上自定义 URL https://flutter.cn/docs/development/ui/navigation/url-strategies
url_stategy https://pub.flutter-io.cn/packages/url_strategy
当用户在 web 上导航时,超链接也至关重要。url_launcher package 中的一个新的 link widget 使用户能够通过深链接直达您应用内的锚点或外部网站。您可以在相关的 widget 上使用 link,包括按钮、内联文本、图像,并指定链接是在同一个标签页还是新标签页中打开。
Link https://pub.flutter-io.cn/documentation/url_launcher/latest/link/Link-class.html
对于任何应用来说,文本渲染都是不可或缺的。开发文本布局系统,是构建 Flutter web 支持所面临的重大挑战之一。由于 web 缺乏直接文本布局 API,Flutter 必须通过触发 layout() 来对 Parapraph 执行各种测量操作。有时,这些测量的代价相当高昂,所以我们添加了基于 Canvas 的文本测量,此测量方式可同时支持纯文本与富文本。现在,Flutter 可以在 web 上高效地完成精细测量,进而完成正确的绘制任务,比如正确地高亮显示所选文本。
layout()
https://api.flutter.cn/flutter/dart-ui/Paragraph/layout.html
Paragraph
https://api.flutter.cn/flutter/dart-ui/Paragraph-class.html
基于 Canvas 的文本测量
https://github.com/flutter/flutter/issues/33523
与文本进行交互同样重要,其重要性不亚于快速准确地渲染文本。通过 SelectableText 和 EditableText widget,您不仅可以选中 Flutter web 应用中的文本,还可以执行复制粘贴操作。此外,表单文本字段现已支持自动填充,浏览器能够存储数据以便将来填充使用。
自动填充 AutofillGroup
https://api.flutter.cn/flutter/widgets/AutofillGroup-class.html
Project Fugu
https://web.dev/fugu-status/
Invoice Ninja https://www.invoiceninja.com/
在创建 Flutter Web 应用时,我们会提供 PWA web 清单文件,以及用来设置 service worker (工作线程) 的代码。清单文件提供了关于应用应该如何运行的元数据,包括图标和应用标题等信息。Service workers 可以实现资源的缓存和应用的离线运行。当您在浏览器中以 PWA 的形式运行 Flutter 应用时,您可以将其作为移动或桌面应用安装到您的设备上。
清单文件 https://developer.mozilla.org/en-US/docs/Web/Manifest Service workers https://developers.google.cn/web/ilt/pwa/introduction-to-service-worker
适配各类桌面设备
尽管浏览器的形态大小各异,我们都希望提供美好的 Flutter web 体验。由于 Flutter 最初是为移动应用设计而成,因此 Flutter web 应用已经对移动浏览器的手势和滚动物理效果提供了很好的支持。但桌面浏览器 UI 的呈现和使用有所不同,所以我们对 Flutter 进行了相应的更新。
比如,用户希望应用在桌面浏览器中运行时能够显示滚动条,以便通过鼠标或键盘进行控制。我们为桌面设备添加了可自定义的交互式滚动条,这意味着我们可为滚动条使用主题,显示滚动条轨道,而且还可以拖动滑块。我们还扩展了 PrimaryScrollController,便于用户使用键盘快捷键进行滚动,也省去了您使用自定义滚动视图的工作。
滚动条更新 https://files.flutter-io.cn/sources/flutter-design-docs/Updating_Scrollbars_(PUBLICLY_SHARED).docx 主题 https://api.flutter.cn/flutter/material/ScrollbarTheme-class.html PrimaryScrollController https://api.flutter.cn/flutter/widgets/PrimaryScrollController-class.html 滚动方式 https://files.flutter-io.cn/sources/flutter-design-docs/Fallback_ScrollAction_(PUBLICLY_SHARED).docx
Spica Technologies https://spicatech.co.uk/ Zurich Insurance https://www.zurich.com/
此外,由于鼠标指针能进行互动的内容密度大于触摸设备,我们提升了默认内容密度。我们还在框架中添加了支持各种平台的系统鼠标光标合集。
默认内容密度
https://github.com/flutter/flutter/issues/43350
系统鼠标光标
https://github.com/flutter/flutter/issues/60641
RenderObject https://api.flutter.dev/flutter/rendering/RenderObject-class.html SemanticNode https://api.flutter.dev/flutter/semantics/SemanticsNode-class.html ARIA 属性 https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA Narrator https://support.microsoft.com/en-us/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1 VoiceOver https://www.apple.com/accessibility/vision/ TalkBack https://support.google.com/accessibility/android/answer/6007100?hl=en ChromeVox https://support.google.com/chromebook/answer/7031755?hl=en#:~:text=You%20can%20turn%20ChromeVox%20on,then%20ChromeVox%20will%20start%20speaking.
Flutter web 对插件的支持
最后,我们为那些最常用的插件带来了 web 支持,使您能够将自己的 Flutter 应用带到 web 平台。借助 Flutter 插件,您的代码可与所运行平台的原生开发库进行互操作。在 web 上运行 Flutter 应用时,您可以通过插件访问现有的 JavaScript 库。
Flutter 插件 https://pub.flutter-io.cn/
image_picker https://pub.flutter-io.cn/packages/image_picker_for_web
google_maps https://pub.flutter-io.cn/packages/google_maps firebase_analytics https://pub.flutter-io.cn/packages/firebase_analytics firebase_storage https://pub.flutter-io.cn/packages/firebase_storage connectivity https://pub.flutter-io.cn/packages/experimental_connectivity_web cloud_firestore https://pub.flutter-io.cn/packages/cloud_firestore cloud_functions https://pub.flutter-io.cn/packages/cloud_functions cross_file https://pub.flutter-io.cn/packages/cross_file
展望未来
几年前,我们还没办法在 web 上以可接受的质量和性能提供 Flutter。然而,web 新技术的出现和平台的不断进步,使我们得以尽情释放底层设备的潜力。在支持 web 之后,Flutter 得以涵盖互联网上的每一台设备,让用户在所有现代浏览器和设备上都能获得一致的体验。
这个版本的相当一部分内容来自早期 web 用户的反馈信息和社区提交的 issue,这里我们要再次感谢大家的贡献!今后,我们的首要目标是快速处理大家的反馈,并及时解决 issue,以便大家专注于在所有目标平台上发布高质量的 Flutter 应用。
Moi Mobiili https://www.moi.fi/
性能的提升永无止境。我们的目标是减少代码体积,提高帧率表现 (fps)。如今,每个 Flutter web 应用都只会下载它必需的引擎代码。我们正在研究缓存部分逻辑的可能性,以减少启动时间和下载文件体积。我们最近在 Flutter Gallery 演示应用中尝试使用延迟库来减少代码体积,相信很快就能同大家分享我们的进展。
虽然 CanvasKit 很稳定,但还有一些边界用例存在问题,比如特殊字符的字体回退,以及对跨域资源共享 (CORS) 图像的相应支持等。
PWA 目前只缓存了资源的一个子集,完全的离线支持仍然需要额外的手动步骤,才能正常适配 CanvasKit。
文本渲染和功能,比如对样式设置较为复杂的文本的选取,仍是我们要继续努力解决的功能之一。
我们也会继续努力改善插件生态系统,让 Google 发布的 package 在移动端和 web 端更加统一。
字体回退 https://github.com/flutter/flutter/issues/74741 跨域资源共享 (CORS) https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS 缓存资源 https://github.com/flutter/flutter/issues/75861 额外的步骤 https://github.com/flutter/flutter/issues/70101
Simplebet
https://simplebet.io/
即刻开始使用 Flutter web
稳定渠道 https://github.com/flutter/flutter/wiki/Flutter-build-release-channels#stable 编写您的第一个 Flutter web 应用 https://flutter.cn/docs/get-started/codelab-web web 演讲 https://www.bilibili.com/video/BV1Jv411h7x6 提交 issue https://goo.gle/flutter_web_issue
推荐阅读