Rust UI 何以成为跨平台应用开发者的“香饽饽”?全栈开发者 Nico Burns 揭秘缘由...

8fbbf5a272735984f3089b61f300d3fa.gif

作者 | Annie Xu

责编 | 何苗

出品丨GOSIM 开源创新汇

Rust 虽然在 GUI 开发领域起步较晚,但凭借其强大的灵活性——能够满足开发者同时开发网页和原生应用的需求,Rust 正成为越来越多跨平台应用开发者心中的 Number One。‌

Nico Burns,一位全栈开发者,是 Taffy、Blitz 和 Servo 项目的核心贡献人员,致力于提升 Rust 生态系统的整体质量和应用开发体验。他亲自搭建起来的 Taffy 项目在 Github 上收获了 2k Star,他的实践干货分享也成为 GOSIM Europe 2024 大会系列视频中,收获最多 Yutube 点赞的精选内容。

今年 10 月 17 至 18 日,Nico 再次受邀出席 GOSIM CHINA 2024 (北京站),这是第三届 GOSIM 大会,延续了超强的国际化讲师阵容,还覆盖 Rust 编程语言、App 开发、AI 模型与基础设施、具身智能、下一代互联网、下一代媒体六大热点技术领域。欢迎您报名亲临现场,与多位行业大咖面对面交流!

1df0217964651203e7a0abf8f7b978ad.jpeg

本文摘录了 Nico Burns 在 GOSIM 2024 欧洲站 APP & WEB 论坛上深入分享的《Rust Ul 概况》核心内容,精彩观点如下:

  • 布局、输入处理和可访问性至关重要。尤其对商业应用而言,可访问性不容忽视。

  • Rust 相关教程和文档的缺失阻碍了开发者对其的了解和应用。他呼吁开发者为库和代码编写更多的文档,特别是针对用户和贡献者的文档。

  • WinIt 团队一贯坚持的原则是“只开发面向多平台的功能”。然而这种做法并不总是符合实际需求,Nico 希望 WinIt 能够添加即使不能跨平台但可以解决开发者迫切需要的功能,使其更加灵活。

  • 如今的 Rust 社区核心贡献者虽然仅有 10 人左右,但商业价值已经凸显,已有资金注入,正处于商业资助的早期阶段,未来可期。

以下是本次采访的主要内容:

0c3c8c0280e165f48e93b01a98a5f269.png

为什么开发者钟爱 Rust UI

传统的桌面应用 UI 通常通过的 Win32 或 WPF(Windows 平台)编写,iOS,macOS 使用 Cocoa 或 SwiftUI、Jetpack Compose,Linux 上的 Qt 或 GTK。虽然有一些框架支持跨平台开发,但这些框架在桌面环境中的表现未必能在移动设备上达到同样的效果。

  • React Native 和 Flutter 等现代 UI 框架在移动端表现良好,也可以用于桌面甚至网页开发。

  • Electron 和 Capacito 是基于网页的 UI 框架,前者应用于桌面端,后者为移动端。

想要开发桌面应用的商业公司或初创企业大多数会采用这些工具,它们也是 Rust UI 的竞品。可选项这么多,为什么开发者还要使用 Rust 来开发 UI? 

  • 开发者对 Rust 的偏爱是原因之一;

  • Rust 具有高性能和出色的类型系统,尤其在跨平台方面表现优异正是许多 UI 开发者所看重的。他们希望能够编写一次代码,在不同平台上运行;

  • Rust 也为替代底层部分提供了可能。像 Flutter、React Native 等现代跨平台框架,底层部分仍由 C 和 C++编写,在使用和维护上存在一些困难。如果整个系统能用 Rust 这样的单一语言编写,使用起来会更加方便;

  • Rust 还能满足开发者同时开发网页和原生应用的需求。Electron 已经实现了这一功能,但在网页修改上存在限制,而 React Native Web 在这方面的表现也并不理想,Rust 有很大的发展前景,有望率先突破。

在 Rust UI 领域,目前存在多种类似于 Flutter 的解决方案,这些框架采用自定义渲染方式。

另一类框架则类似于 React Native,它们依赖底层系统工具包来处理布局和界面生成,实际的渲染工作则交由系统平台库完成。Web 前端开发同样有多种框架供选择,例如 React、Angular 和 Vue 等。Rust UI 生态系统与以上有一定相似性,一些框架较为流行,而许多其他框架则属于“长尾”部分,因此开发人员拥有广泛的选择空间,社区中的竞争和交流都非常活跃。

另一方面,Rust UI 领域的模块化特性使开发更加灵活。传统的 UI 应用程序十分复杂,涉及的内容也很多,需要许多库和框架的配合,而模块化可以让开发者避免从零开始构建所有内容。一些 Rust 组件尽管是开源的,但缺乏使用说明和示例,这使得想要使用这些组件的人难以入手。Nico 希望在未来几个月里改善这种情况。

如今的 Rust 社区核心贡献者虽然仅有 10 人左右,但商业价值已经凸显,已有资金注入,正处于商业资助的早期阶段,未来可期。

3370cea46d701569ea014f28b7f1f678.png

如何用 Rust 构建应用程序?

接下来,Nico 详细分享了在使用 Rust 构建应用程序时涉及的各项功能及其开发进展。

1. 创建窗口应用:跨平台能力优先还是实际需求优先?

创建窗口应用程序的核心需求之一是能够跨平台运行,Rust 的 WinIt 库可以实现这一功能,在满足基本的功能需求的情况下,还能支持所有主流平台,在跨平台开发中非常实用。然而,WinIt 也存在局限性,它无法完全实现开发者想要的功能,在某些情况下甚至可能成为开发的障碍。

当前 WinIt 在逐步改进原有功能。最近发布的 WinIt 0.30 版本通过队列处理,实现了 API 的及时响应,开发者在实现新功能时将有更多的灵活性。这也表明 WinIt 团队逐渐开放的态度。

WinIt 团队一贯坚持的原则是“只开发面向多平台的功能”。然而这种做法并不总是符合实际需求,Nico 希望 WinIt 能够添加即使不能跨平台但可以解决开发者迫切需要的功能,使其更加灵活。首先允许在单个平台上优先实现某些功能,然后再考虑如何抽象出跨平台的解决方案。WinIt 团队也可以给有意拓展功能的开发者提供扩展点。

如果开发者想要将窗口嵌入到其他应用程序中,例如通过一个插件来控制音频制作应用,虽然这在 WinIt 中不能实现,但 BaseView 库和 nih-plug 包装库可以达成。遗憾的是,它们不能与 WinIt 混合使用,这给开发者带来了一定的不便。

尽管 WinIt 在满足基础需求方面表现良好,但随着开发者对更多功能需求的增加,改进和扩展将会成为未来的关键。Nico 期待看到更多工具和解决方案的出现,能帮助 Rust 开发者更轻松地实现复杂的 UI 功能。

2. 渲染与合成:四大渲染技术各展所长

有了窗口后,该如何绘制呢?Nico 介绍了四种主要的方式:软件渲染、OpenGL 渲染、Vulkan/Metal/DirectX 12,以及 WGPU。它们不仅仅适用于 Rust,也适用于跨平台。

虽然这些渲染方式在 Rust 中都可用,但开发者通常不想直接与这些底层 API 打交道。因此,有很多更高级的库可供选择,这些库提供了更直观的接口,例如绘制矩形、文字、图像等。然而,许多纯 Rust 库在功能上还有所欠缺,比如处理模糊效果、阴影和文字渲染等功能,未来还需进一步填补这些空白。

Nico 特别推荐了两个库:skia 和 webrender,分别应用于 Chrome 和 Firefox。skia-safe 是绑定了 C++版本的 skia。尽管构建过程较为繁琐,但它文档齐全,功能强大,许多开发者都在使用。webrender 由 Rust 编写,构建起来很容易,但文档较为混乱。开发者可以根据自己的需求选择合适的渲染技术。

另一个库 Velo 使用了计算着色器,而非更传统的内置渲染管线,理论上性能更强,但目前还不太成熟,如果开发者愿意尝试新技术,Velo 是一个不错的选择

关于文本渲染功能,渲染单个字形(例如字母、连字或表情符号)和确定要渲染哪些字形及其位置是两个独立的过程。字形渲染基本上是将字体文件转换为图像,具体有以下几种选择。

  • 如果对精确匹配的需求较高,可选择 WebRender。它利用 Mac OS、Windows 和 Linux 的底层系统库来渲染字形,使其与系统中的其他应用程序保持一致。但使用这种方法需要与系统 API 交互,过程较为复杂。

  • 比较常用的是纯 Rust 编写的 Swash。它执行缩放和提示,即将字体文件转换为特定字体大小的精确矢量路径,并通过通用的矢量渲染器进行渲染。comsmic-text、femtovg 都使用了 swash。

  • 由 Rust 编写的 Scripher 能够兼容不同系统也是不错的选择,它与 Swash 非常相似,都是高质量的字形渲染技术。

将文字渲染成图像之后,接下来就需要系统合成器将多个图像层叠加在一起。面对不同进程且互不通信的窗口时,需要将其组合起来。利用系统提供的合成器可以极大地提高效率。如通过滚动操作,可以直接渲染到纹理上,然后让操作系统负责上下移动,而不需要每帧重新渲染所有内容。

许多应用场景都涉及到将来自应用程序外部的内容渲染到窗口中,比如视频、网页视图或操作系统控件,它对于高效的 UI 渲染至关重要,目前专门从事系统合成器的开发的人不多,未来还需要更多人参与其中。

3. 窗口布局:三种处理模型的优势与局限

合成完成后,开发者可以使用内置的布局方法(如网页上的 Flexbox 和 CSS Grid)或自己的布局算法。内置方法虽然方便,但可能无法满足一些高级需求。自己的布局算法可能会很慢,但也不一定像内置的那么好。

如果采用 box 布局,所有内容都以部件树的形式呈现,通常有三种处理模型:

Web 类

  • 优点:熟悉、富有表现力,条理清晰;

  • 缺点:性能不佳。

第一种模型是直接使用网页布局,其好处在于它与网页布局完全相同或非常接近,对于熟悉网页开发的人来说更容易上手。但这种方法的时间复杂度可能会呈指数级上升,如果追求极致性能,可能会遇到挑战。有些人对所使用的 API 感到困惑,对此,Nico 表示,他参与开发的 Taffy 布局引擎在基准测试中的表现优于 React Native 使用的 Yoga 布局引擎。

简化版

  • 性能更强,更简单;

  • 通过 Morphorm crate 提供。

第二种模型,拥有伸缩和填充能力。你可以指定一个固定大小的部件布局,另外两个部件各自占据剩余可用空间的一半。这种布局方式可以根据窗口大小等因素动态调整。

基于约束

  • 最具有表现力;

  • 性能不佳。

第三种模型类似苹果平台内置的方式,将内容彼此对齐。除了 TUI 框架 Ratatui,大多数 Rust 的 UI 框架尚未实现复杂的布局功能。

文本布局方面,Nico 提到目前 Rust 生态系统中的富文本支持还存在一定的局限。一些基本的文本布局可以实现,但内联图像、小部件、区域排除、浮动图像或引用块等复杂功能目前还无法实现。Cosmic Text 和 Parley 是两个比较常见的库,前者在等宽字体的虚拟化优化上表现出色,而后者在多字号支持上表现良好。

此外,输入方面挑也存在挑战。虽然 Rust 可以处理基本的鼠标和键盘输入,但对于更复杂的输入法编辑器(IME)等输入系统的支持仍然有限。IME 对处理字符重音、表情符号输入、中文和日文等语言的输入非常重要,是 Rust 生态系统中急需改进的部分。

008daba64ec6fa3d5ebec320308211ea.png

可优化空间与辅助工具的重要性

如何使应用程序被屏幕阅读器等辅助工具使用?可访问性至关重要。例如,屏幕阅读器应能够读取应用内容、感知内容更新,这样才能并实现一定的交互。AccessKit 库为 Rust 应用提供了这方面的支持,不过该库仍有改进的空间。 

在 Rust UI 开发中,系统菜单和剪贴板等功能已具备,但实现布局的实时呈现、网络请求、能否自我驱动等功能有待开发者进一步探索。 

Nico 还特别强调了辅助文档的重要性:目前,Rust UI 生态系统中的文档质量参差不齐,许多开发者并不知道如何使用这些工具,他希望未来能有更多的教程和文档来指导如何使用屏幕阅读器和其他可访问性工具,也呼吁开发者为库和代码编写更多的文档,特别是针对用户和贡献者的文档。

此外关于编译时间。尽管大部分编译时间问题可以通过编译器优化来解决,但热重载功能十分重要——可以避免频繁重新编译。如 Dioxus、Leptos 和 Bevy 都支持这一功能,Nico 希望未来更多的库能加入这一行列。

c2e4452d4b636aa445499fc1f8908eb0.png

为了 Rust 更好的明天,改进

Rust 语言存在哪些问题?又通过什么方式进行改进呢?Nico 在最后总结了 Rust 在 UI 开发方面需要改进的内容,并提出了几点建议。

1. 自动克隆:UI 框架中经常需要使用到 Rc (引用计数)和 Arc(原子引用计数)。开发者期望的调用方式是能够实现隐式克隆。目前,一些 UI 框架通过宏来隐藏这一过程。未来,希望能够开发出一种围绕 Rc 或 Arc 的新类型,以实现自动克隆的功能。

2. 字段借用:有时开发者希望在结构体上同时拥有多个可变方法,同时借用不同字段。虽然逻辑上行得通,但在 Rust 编译器中较难实现。跟踪借用的机制是可行的,但是需要设置特定的语法,以便开发者可以同时对结构体的不同字段进行操作。

3. 默认值支持:在 Rust 中,如果你为一个结构体实现了一个 trait,通常需要为所有字段提供默认值。然而,在很多情况下,只有部分字段拥有合理的默认值,而其余字段则需要在创建时明确设置。目前,使用构建器模式是解决这一问题的方法,但这会使代码变得冗长且生成大量模板代码。对于底层代码而言,涉及的类型较为严格且配置选项有限,这种影响较小;但在高级代码中,这种影响则更为显著。希望未来能有一种机制,允许开发者只为部分字段提供默认值。

4. 改进孤儿规则:当前的孤儿规则限制了外部 crate 之间的相互操作性。

5. 采用特化机制:有助于构建模块化的生态系统,并且提供更经济性的 API。例如,使用特定类型时可以直接走特殊路径,作为 API 的消费者,甚至不需要花时间去了解。

6. 外部构建系统/代码生成:有助于减少编译时间、定制个性化 crate。

最后,Nico 再次强调了布局、输入处理和可访问性的重要性。对商业应用而言,可访问性的重要性不容忽视。改进 Winit 以增强对系统功能的访问同样重要,这需要更多成熟的组件和文档支持。长远来看,这些改进将有助于提升 Rust 生态系统的整体质量和应用开发体验。

eefda7a8ca4a9482ffc2f08fb7674cdf.gif

10 月 17 - 18 日,GOSIM CHINA 2024 (北京站)

60 + 海内外资深专家

1000 + 一线开源开发者

6 场主题技术论坛

100 +优质内容

2 场黑客松大赛

……

大咖云集,精彩纷呈

期待您的加入

扫描下方二维码或点击阅读全文

早鸟观众票数量有限,先到先得!

欢迎您报名亲临现场

与多位开源领域资深大咖面对面交流!

a9b2fe09c53c7f3cd840915906bc20dd.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值