作者 / Tim Sneath, Product Manager for Flutter and Dart, Google
众所周知,在开发 Flutter 时,我们希望通过单一代码库支持 Flutter 在各类设备 (包括 iOS、Android、Windows、Linux、macOS 和 Web) 上的应用,并实现原生编译和游戏级别的视觉效果。Flutter 也已经在 Google 内部广泛用于 Assistant、Stadia、Cloud Search 以及 Blogger 等项目。在 Google 之外,字节跳动、Grab、Nubank 以及 MGM Resorts 等公司也都已采用 Flutter,并通过 Flutter 提升了生产力和灵活性。
很多人都想了解 Flutter 在桌面操作系统 (包括 Windows、macOS 和 Linux) 上的进展: 据调查和 GitHub 数据显示,Flutter 的桌面支持一直是最受期待的新功能之一。未来数周内,我们将为大家带来更多这方面的进展;同时,我们认为有必要先展示来自各个产品功能团队的成果 (这些成果最终会整合进完整的项目中),并搜集大家的反馈。虽然桌面支持目前已推出技术预览版本,但我们仍然有大量工作需要完成。
发布模式
继 macOS 之后,我们还为 Flutter 增加了 Windows 和 Linux 系统的 Profile Mode (性能模式) 和 Release Mode (发布模式) 。例如,如果您运行的是最新版 Flutter,现在可以使用 flutter build windows 命令,将 Flutter 应用编译为 Windows 可执行文件。此操作使用我们在生产环境中的 AOT 编译器来创建原生 x64 机器代码,而这些代码可分发至那些未安装 Flutter 的设备上。
桌面级体验
无论您要构建的是独立可执行文件还是 Web 应用,桌面级体验都有其独特的属性: 桌面窗口通常采用横屏模式并可以调整大小、输入通常由物理键盘和鼠标完成,而不是通过屏幕键盘和触摸操作,同时,控件也是基于不同的屏幕内容密度进行的优化。
外部函数接口
Dart 团队一直在努力完善外部函数接口 (Foreign Function Interface, FFI) ,以加速平台集成的进程。对于基于 C 语言的 API,dart:ffi 库提供了一种直接绑定到原生代码的机制;Dart 运行时则提供了在 Dart 对象支持的堆上分配内存并调用动态链接库的功能。
typedef MessageBoxNative = Int32 Function(
IntPtr hWnd, Pointer<Utf16> lpText, Pointer<Utf16> lpCaption, Int32 uType);
typedef MessageBoxDart = int Function(
int hWnd, Pointer<Utf16> lpText, Pointer<Utf16> lpCaption, int uType);
final user32 = DynamicLibrary.open('user32.dll');
final win32MessageBox =
user32.lookupFunction<MessageBoxNative, MessageBoxDart>('MessageBoxW');
void showMessageBox(String message, String caption) => win32MessageBox(
0, // No owner window
Utf16.toUtf16(message), // Message
Utf16.toUtf16(caption), // Window title
0 // OK button only
);
…
showMessageBox('Test Message', 'Window Caption'); // call just like any other Dart function
在上例中,我们通过两个 typedef 分别体现了方法的原生和 Dart 版本形式。完成这些定义后,我们便可通过 lookupFunction() 方法加载 Windows 动态链接库 (DLL),lookupFunction() 负责将方法签名映射到底层的原生入口,DLL 则负责提供方法的实现。最后,我们可以选择添加一个简单的惯用包装器,使其便于从其他 Dart 代码进行访问,运行结果如下:
当然,您不必亲自完成这项工作: 有人很可能已经处理好了您要使用的 API。您可以阅读我们的官方文档,详细了解如何在 Flutter 中使用 FFI。
访问常用 Win32 API 的 Dart 库
https://pub.flutter-io.cn/packages/win32
官方文档: 使用 dart:ffi 调用原生代码
https://flutter.cn/docs/development/platform-integration/c-interop
更新插件模型
从设计上说,Flutter 本身的核心很小。Flutter 并没有在框架中提供海量内容,而是通过插件和 package (无论是直接来自 Flutter 团队还是来自更广泛的生态系统中的贡献者) 来实现与底层操作系统的集成。
但是,随着 Flutter 对移动设备、Web 和桌面端的支持日益增多,为每个目标平台开发插件也变得越来越具有挑战性。更可能出现的情况是: 一个插件需要多个掌握各自平台专业知识的作者通力合作,才能完成开发。
一个可行的做法是,在核心插件中定义出通用接口,并在各个平台上独立完成具体的实现。因此,正如近期一篇关于现代插件开发的博文所述,我们最近对插件的架构进行了调整,使多个作者能够更加轻松地合作完成各个平台的开发。基于目前的进展,插件现在可以明确地声明其所支持的具体平台。
我们已经开始使用此模型来构建一些核心插件,您也可以在 flutter/plugins repo 中找到一些基于这个联合开发模型的早期示例。
在 Windows 上运行: Win32 和 UWP
在 Windows 上进行开发有一个很有趣的点在于,我们会试验各种架构方法。在任何平台上,Flutter 应用其实都是内嵌于一个很小的容器应用 (即 "embedder") 中的,这种做法类似 Unity 等游戏引擎。这种特定于平台的容器应用负责提供入口,与底层操作系统进行协调以使用表面渲染、无障碍功能和输入等服务,并管理消息事件循环。
Windows 提供了两种不同的方法来创建这个容器应用。第一个是使用成熟的 Win32 编程模型来创建 Flutter 内容的入口;这为 Windows 7 等平台提供了最大的向后兼容性,同时能构建出符合诸多开发者预期的标准 EXE 文件。第二个则是现代 UWP 应用模型,推荐在 Windows 10 上使用。这种方法拥有更广阔的想象空间,比如能够帮助开发者将 Flutter 支持扩展至 Xbox 等设备或即将推出的 Windows 10X 操作系统。
我们一直与多位社区贡献者一起探讨本文所述的不同解决方案。同时我们很期待与微软紧密合作,共同完成高质量的解决方案。Surface 系列设备正不断扩展,现在其产品已涵盖 Android 和 Windows。我们认为 Flutter 可为微软提供非常有吸引力的平台,横跨其全部产品阵容并提供卓越的原生体验。
尽情探索桌面体验
C:\flutter> flutter config --enable-windows-desktop
enable-macos-desktop flutter config --
enable-linux-desktop flutter config --
一些积极探索的开发者已经 "尝鲜",在桌面环境中利用 Flutter 创建应用。我们见证的首批 Flutter macOS 桌面应用便包括 Sharezone,这是一款针对德国教育市场的学生管理应用,最初创建的是移动应用版本,但最近增加了网页和桌面版本。
△ Sharezone Schulplan: 一款面向学生、教育工作者和家长的应用,用于跟踪家庭作业、学习小组和课程表等情况
Sharezone
在接下来的数周里,我们将分享更多关于桌面支持的信息;同时,我们也期待着听到您的反馈。如果您是插件作者,我们建议您开始评估将自己的插件适配至即将到来的这些桌面平台所需要的开发工作;如果您已发布应用,不妨尝试将应用作为桌面应用运行,并告诉我们您的运行情况。
您是否愿意体验 Flutter 的桌面应用?欢迎在下方评论区说出您的想法。
推荐阅读