Local Native 2021 SoC 计划 Blog

使用iced实现LocalNative的跨平台桌面GUI,大致上要实现electron版本的基本功能,总结如下:

  • 支持搜索、查阅note
  • 支持tag显示,并可以点击tag进行查询
  • 支持tag数量显示,并且可以通过点击tag的数量进行查询
  • 支持多语言(仅需要考虑中英文)
  • 支持通过sqlite3文件进行同步
  • 支持扫描二维码进行同步
  • 支持输入目标ip地址进行同步
  • 支持note生成对应url二维码分享内容
  • 支持通过时间段过滤搜索note

除了以上electron版本已经支持的功能,可能还会支持以下功能:

  • 支持明暗主题切换
  • 支持多个渲染后端选择

目前大部分代码已经完成了,还有少部分的todo需要完成或者舍弃,除了上述todo以外,我更想和大家分享在iceddruid之间,为什么最后选择了iced,这部分没有太多涉及到技术层面的东西,更多是对使用体验上的一些考量。

druidiced是Rust社区中较为知名的GUI框架,其中iced更是以其好用的api从而俘获了大部分开发者的青睐(从Github的star数量上就可见一斑)。二者之间也有一定的关系,在介绍关系之前会大致介绍一下二者是在什么样的情况下被设计出来的。

先谈druid吧,正如druid的Github项目主页上Readme所言,目前驱动druid开发下去的主要动力是runebender,一个字体编辑工具,依托druid的跨平台能力,该编辑器在不同平台上有着较好的体验。同时如果体验一下这个字体编辑工具,能够感受到druid足以完成大部分图形界面客户端开发中的难点,也就是说druid有足够的能力去实现一个跨平台的复杂图形用户界面。目前druid的渲染后端是pietdruid的作者自己有意愿将wgpu作为druid的可选后端,但是希望wgpu能够足以胜任这份工作时才会去做出这种改变。pietwgpu的优缺点在于piet更轻量,在低性能设备上运行的时候,目前来说体验上是要比wgpu要好的,wgpu更像是一个游戏渲染后端,需要gpu有一定的支持,同时由于当前wgpu对OpenGL的支持并不是很好,从某种角度上来说Wgpu对老的设备并不是很友好(新版本的wgpu已经对OpenGL有了初步支持)。

iced的初衷就更简单了,作者本身有一个游戏引擎需要用到GUI工具,因此自己手动写了一个,谁想到游戏引擎没火,iced却火了起来,关于iced开发上限可以看看Project Showcase,其中较为出名的一定是这个:Cryptowatch Desktop,相对于druid的渲染后端pieticed则在一开始就选择了wgpu作为自己的渲染后端,当然iced自己宣称是渲染器无关的GUI工具,在后续官方确实也添加了对OpenGL的支持(直接通过glutin,一个Rust的OpenGL绑定,而不是通过wgpu)。

理解了两者开发初衷上的不同之后,你就能够感受到两者对一些理念上有着明显的不同,比如就成熟度而言,druidiced更像是一个完整的GUI方案,你能想到的大部分功能都有了足够的解决方案,虽然有些还在完成中,但是你已经能直接能用到很多简单好用的API了,相对于iced是一个游戏GUI框架的考量,你能在编译之后的程序体验上,感受到druid真的像是一个为了各个平台而设计的GUI工具,说的具体点,iced到目前还没有一个支持各个平台的菜单控件(对,你没看错,居然连菜单控件这种很常用的东西都没有),而durid已经完全对各个平台有了不同的,完全绑定平台原生的菜单控件,并且 API设计上也十分好用。druid已经有了一个可用的多语言支持(切换语言还没有实现,不过已经很快就会实现了),而iced甚至连解决在输入框里打中文,输入法文本悬浮框会飘出应用程序的PR还没有合并。

那说了这么多,全是druid的优点,那为啥最后还是选择了iced呢?

因为iced更简单,这是最重要的,这次SoC的计划除了实现那个GUI之外,其实还有一个更重要的事,就是实现一个项目实践的教程,最为教程的最佳选择,iced绝对当仁不让,你能从这次项目实践教程中体验到Rust开发如此有趣,在初步掌握了iced之后,你便能够将你的所有想象力轻易表达出来。

不仅仅是简单这么个有点,在一定程度上由于iced的渲染后端现在是wgpu,而druidpiet的原因,在一些场景下性能是iced的最大优势,你会感受到你的App是如此的丝滑(虽然iced还没有动画支持😀)。同时iced和异步框架的深度融合,在开发中会让你更为舒适。

总结下来就是以下三点,让我最后选择了iced,而不是druid

  1. iced更简单
  2. iced渲染后端是wgpu
  3. iced足够完成当前的需求

既然提到了事件处理,我还是要夸一下iced的,如果你看过iced的示例代码,会发现在iced的update逻辑里要求你返回一个Command枚举,这个Command你可以将你想要执行的异步操作直接给它调用,就能够得到一个性能还算不错的应用程序。而druid的这部分代码要怎么处理呢?如果你熟悉并发中channel的概念,你在使用druid的事件处理时会理所当然的想到,这不就是channel么,通过一个类似channel的形式,将信息传递到一个集中处理该信息的地方,使用起来实在是不太优雅。

在灵活性上,iced让你写起来完全像是在写elm(果然不愧是受到elm启发),而druidLens概念足够把很多人给劝退了,所以单单是在这些方面,就足以让我为了接下来的教程,而选择iced,而不是durid

好了既然说到教程,就把教程的整体放在这里:

  • 序,从localnative_core获取GUI需要用到的数据
  • 第一部分,实现展示一个完整的note
  • 第二部分,手动实现一个wrap控件
  • 第三部分,手动实现一个timeline控件
  • 第四部分,如何打包

大概的内容就这么多,其中在序这部分会着重讲一下开发环境的搭建,其中最为冗长的是第一部分,实现一个完成的note,这里又需要划分为三个部分来讲,最后一个打包部分只会讲到windows平台的,因为我没有mac,所以mac打包还需要各位自行尝试。大概内容就是这些,更新速度的话,其实代码写到这里,除了第三部分的timeline控件没写,基本功能都实现了,都是一些小问题需要去解决。

最后,说点我个人的感想吧,这次SoC我个人还是十分珍惜这个机会的,我很喜欢Rust,但是现在的Rust工作环境大概七成是区块链,剩下的三成还有不少是搞分布式、数据库的,所以相对于这些而言,居然有一个GUI开发的Rust实习机会,对我来说实在是太令人高兴了,再加上还是一个开源项目,又着实令人兴奋一把。从接触Rust至今,已经快两年半的时间了,但正是因为Rust十分有趣,坚持到现在已经是一种享受的姿态,这次教程的受众主要还是那些对Rust感兴趣,想要动手写点小工具之类的人,只需要知道语法是在表达什么就够了,所有权生存期这些东西交给编译器去锤炼你吧,希望大家喜欢会喜欢这个系列。