原文地址:openprivacy.ca/discreet-lo…
原文作者:
发布时间:2021年3月5日
欢迎来到Discreet Log! 这是一个两周一次的技术开发博客,深入介绍我们在Open Privacy从事的研究、项目和工具。在我们的第二篇文章中,Erin Atwater记录了为Cwtch开发的基于Flutter的新UI。
Cwtch库提供了一个用Go编写的后端,旨在为我们计划的其他一些使用Cwtch连接作为(元数据最小化的、经过验证的)传输层的应用程序提供支持。Sarah一直在为Tapir工作,所以后端在Rust中有一个开放的发展路径,但今天我们在这里聊的是另一个方面
目前,Cwtch alpha是我们的旗舰项目,用Qt 5编写,并为桌面操作系统和安卓系统编译,展示了基本的同行和群组消息,以及一些简单的表格演示,称为Lists和Bulletins。我们使用Qt与Go的绑定来完成这种配对。
虽然团队最初对我们能够使用这个堆栈快速地变出一个概念验证的应用程序印象深刻,但随着时间的推移和空间的发展,小摩擦经常发生。
在2020年,我们曾计划从阿尔法阶段转入测试阶段,并在应用商店投放一个特殊的 "稳定 "版本,但在发布前的几周,我们在安卓的arm64版本上发现了许多崩溃的错误,而这些错误在其他平台上是无法复制的。在进一步的调查中,我们了解到许多错误似乎是源于QML堆栈和像DropShadow这样的通用组件,而且很明显,如果不进行重大的返工,就不可能实现基于Qt的arm64安卓应用。
此外,考虑到Qt基金会和他们的开源产品的变化已经让我们的开发人员很不满意,我们决定在一月份用一周的时间来回答这个问题:用另一个框架的类似用户界面来取代我们基于Qt的用户界面需要多少工作?
在这一周的实验中,我们选择了Flutter的实施来降低风险。
为什么是Flutter?
一些读者会熟悉开放隐私团队对使用嵌入式浏览器框架(如Electron)编写的应用程序的普遍厌恶,因为很难防止因其热衷于加载远程资源而导致的隐私泄漏。这排除了许多现代UI框架。
Cwtch alpha是用自定义的QML编写的,以实现一个具有单一代码基础的响应式跨平台UI。我们不想放弃这一特性,我们发现Flutter的开发频道(很快就是Flutter 2)不仅支持Android和iOS应用程序,还支持桌面操作系统。
Flutter还具有其他一些我们开始欣赏的小奢侈品,如属性绑定和声明式部件语法。所有这些结合起来,Flutter在目前的队伍中脱颖而出,成为Cwtch用户界面的第二个可行的选择。
我们着手消除几个核心功能的风险:主题化、与我们现有的数据模型的整合、可访问性、本地化和移植我们现有的翻译,此外还有整体的调试和构建经验。
主题和不透明性
在创建Cwtch时,我们将我们的可重用部件和主题系统分离到一个单独的库中,我们命名为Opaque。Open Privacy's Awesome Qt-based User Experience library。当我们去年突然需要创建Lockbox时,这对我们有很大的帮助,因为我们能够在Open Privacy美学的基础上迅速开发出一个独立的、跨平台的应用程序,我们的员工设计师Marcia一直在为我们精心设计,与我们现有的翻译系统挂钩,甚至还有一些小的细节,如光明和黑暗的主题。
我们肯定会创建一个类似的库,以便在未来的基于Flutter的应用程序中保持这种能力。
然而,这种需求已经不那么迫切了。标准的Flutter抽象,如Flexes、Expanded、ShrinkWrap、Scrolling viewports和Navigators,减少了大量在QML中制作一个视觉上相同的响应式组件所需的模板。
数据模型和懒惰加载列表
Flutter为如何存储/访问/管理你的应用程序的状态提供了许多选择,这取决于你的需求和偏好。我们选择了Provider包,它允许我们创建 "ChangeNotified "状态对象,通过Provider传递给该状态的消费者。
Flutter的ListView也原生支持 "懒惰加载 "的概念,也就是说,只有在用户滚动到屏幕上的时候,才会访问列表条目所需的数据,而一旦他们滚动离开,就会丢弃这些数据。这在Qt中也可以做到,但理解和实现一个与我们的Go绑定兼容的强大抽象模型的时间并不短。
本地化
非常感谢我们的志愿者,Open Privacy使用Lokalise来翻译我们的软件。在QML中,字符串是这样引用的。
Qt工具lupdate和lrelease会梳理我们的QML文件,寻找字符串标识符的变化,并更新.TS文件,然后我们将其发送给Lokalise。对于Flutter,flutter_lokalise包能够下载已经存在的翻译,并将其转换为.arb文件,然后由自动生成的LocalizationDelegate类为我们进行解析。
这样做的一个好处是,输入错误的字符串ID现在可以被编译器捕捉到了!这是一个很好的例子。耶! 我们现在直接在Lokalise上管理我们的字符串,简化了我们的管道,从在获得翻译之前必须解析和上传字符串,到简单地下载翻译。它还允许我们创建像Opaque这样的模块,提供他们自己的LocalizationDelegates,而不是我们在Qt中不得不做的笨拙的.TS文件管理。
可访问性
我们在Qt中发现的另一个烦恼是必须为我们所有的自定义部件手动实现缩放和字体大小,使用高密度的屏幕分辨率API,我们发现这个API在不同的平台上是有问题的,而且不一致的。这体现在我们的设置窗格中的 "缩放 "控件上,它成为我们最经常报告的错误来源之一。
在Flutter中,我们没有这个头痛的问题,也没有这个控件,因为Material widgets已经尊重这些系统设置。)
调试工具的比较
我们使用Go/Qt绑定也使我们无法使用一些较好的Qt开发工具,如Qt Creator、其调试器、检查器和qmlscene。
在Flutter中使用FFI/Gomobile并不会以同样的方式破坏这些工具。
我们能够使用Android Studio来开发 "Flwtch",而且Flutter和Dart开发工具开箱即用,效果非常好。
在地平线上
现在,我们已经解决了大部分预期的困难,我们正在努力完成这个新的前端,以便我们可以发布它进行新一轮的Alpha测试。由于新的堆栈纠正了我们的应用程序商店的问题,我们也应该能够很快创建Play商店的构建,并有可能在不远处创建Windows应用程序商店的构建(手指交叉/敲击木头/向我们发送你最好的脱壳)。
Flutter应用程序的性能明显提高了,这既是由于我们坚持 "Flutterisms "的决心,也是由于我们在这一过程中获得的重要智慧。它看起来和感觉上都更具有平台原生性,并且符合安卓上的Material设计准则,这也是人们过去要求我们做的。我们很高兴能把它送到你的手中,无论是Beta版、稳定版还是更远的地方。