桌面软件开发框架大赏
本篇文章全部源自作者的亲身经历,不是官网随便搬来的。
Qt
几乎是C++领域最流行的跨平台桌面端软件开发框架了,
这个框架是两个挪威人在1995年创建的,发展至今可以说历史相当悠久,稳定性也很有保障。
很多大公司都在用它做界面比如金山的WPS。
它内置了自绘引擎,也就是说界面上的一个按钮,一个文本框,都是Qt的引擎自己画的,这保证了基于Qt开发的软件界面在不同操作系统上看起来是一模一样的。
它提供了大量的与界面无关但与软件开发息息相关的API,比如、网络、文件系统、剪切板等,而且让这些API在不同的操作系统下都有效,这极大的节省了开发人员的时间。
但它也有一些缺点,比如在处理一些特殊需求上很不方便,比如:目前Qt有没有比较好解决高分屏下缩放显示的方案?,Qt没有真正完美的无边框解决方案吗?等,
在一些组件的渲染上也会出一些隐藏的较深的问题(QListItem),一旦遇到,就很难解决。
Qt近年来不太专一,qml,qtquick等,搞了很多,而且这些新玩意儿一直不温不火,有些模块做了又废弃了,比如:qt script,搞来搞去,搞的模块繁多且复杂,用起来不是很舒服。
Qt有界面描述语言(XML描述界面),可以通过设计器拖拽空间设计界面,编译期界面描述语言被转义成C++代码,性能上没啥损失。
Qt商业授权不太友好,开发商业应用一定要谨慎,之前听说有公司为此付出了高额的版权费。个人开发者可以免费使用。
Qt的免费版本不允许静态链接,会有版权上的限制,但开发者还是可以通过一些特殊的编译方法静态连接Qt的库的。
除了使用C++开发Qt应用外,开发者还可以使用其他语言开发Qt应用,
最流行的就是使用Python基于PyQt做Qt应用了,其他语言的绑定不是很成熟,但PyQt仍然有版权的问题。
GTK
GTK是1997年创建的,也非常成熟稳定,
是C语言开发的,但有很多语言的绑定,比如官方支持的JavaScript、Rust等,当然用C++语言操作GTK也很方便,
它也有自绘引擎(Cairo),也提供了大量系统相关的API,
商业授权也非常友好,基于GTK开发商业软件不用担心收到律师函的问题,
虽然它是一个跨平台桌面软件,但它似乎只在Linux操作系统领域流行,有非常多的Linux桌面软件都是基于GTK开发的。
这也直接导致GTK的维护者很重视Linux领域的发展,而忽视Windows和Mac领域。
这个框架提供的很多API,只在Linux下有,Windows和Mac下没有。这样的API数量众多。
甚至在Windows下编译一下GTK的源码都要比Linux下难很多。
而且GTK的渲染引擎在Windows下性能表现也不如在Linux下好。
GTK在Windows上也没办法静态连接,倒不是因为版权的问题,而是它依赖了MSYS2的一些库,这个库用于在Windows上模拟Linux环境,这也是为什么GTK在Windows上表现不佳的原因之一。
另外,由于GTK是C语言开发的,所以开发风格也很C语言化,这对于部分开发者来说可能觉得繁琐。
wxWidgets
wxWidgets是1992年英国的一个大学教授开创的跨平台GUI软件,也非常成熟稳定,商业授权非常友好。
它没有自绘引擎,而是对不同平台下的界面API做了整合和封装,
这样开发者在Windows下开发的软件看起来就是Windows窗口风格、Linux开发的软件看起来就是Linux窗口风格,
这对于某些软件来说,正是他们想要的,但要想搞一些花哨的特效就没那么容易了。它同样也提供了大量的系统相关的API供开发者使用。
它是C++开发的,所以对C++开发者非常友好,
除此之外它还支持静态连接,也就是说开发个应用不用分发给用户一大堆dll。
它会有些小问题,比如我之前提的:wxEVT_NOTIFICATION_MESSAGE_DISMISSED event emit twice,但总体来说还是非常稳的。
除了开发的界面比较死板外,没啥大的问题。
FLTK
FLTK是1998年创建的跨平台开源GUI框架,历史悠久,商业授权友好,而且C++之父也用它,
它非常轻量级,支持静态连接,一个简单的应用编译后只有500K左右,非常赞,
它有自己的自绘引擎,用的是OpenGL,
但它的重绘机制是按区域重绘的,如果组件A所在的区域上存在组件B,那么A组件重绘时,会把B组件的给重绘掉,开发者必须自己写代码处理这种情况。
想象一下,如果你想实现一个A组件fade out的同时B组件fade in的效果,就会非常麻烦。
FLTK提供的一些组件样式都比较刻板,绘图API也比较少,
你想实现一个漂亮一点的圆角按钮(它内置圆角按钮的圆角大小是不能改的),必须自己画,而且还得借助一些非常奇葩的手段才行(如果你想知道,可以联系我)
它是C++开发的,但API不够现代,用起来总体还算舒服的,
它有Rust绑定:fltk-rs。它提供了一些与界面无关的操作系统API,但非常少,几乎可以忽略。
Duilib
是2010年国内一个开发者开发的GUI开发框架,
因为底层基于DirectUI开发,所以只支持Windows平台,不支持跨平台,
开源协议友好,商用没有任何问题(需要附加Lincence文件),
国内有很多大厂基于这个技术做桌面端应用,比如网易、腾讯、百度,
这个框架是基于C++开发的,对C++开发者友好。
但框架本身还有一些问题,比如对高分屏支持不佳、特殊控件绘制上也有一些小问题,
除了界面相关的API外,几乎没有提供系统级的API,作者纯粹是用爱发电来开发这个框架,所以更新不是很及时。
相对来说网易基于Duilib开发的分支更完善一些:NIM_Duilib_Framework,添加了高分屏支持、多国语言、整合了多线程处理的支持,
但环境搭建相对比较麻烦。如果开发者要用这个框架,一定要用develop分支下的代码,master分支下的代码问题很多,这个框架看上去也是作者一个人努力的成果。
Sciter
Sciter是2006年创建的跨平台闭源GUI框架,足够稳定,
它商业授权不友好,但个人开发者可以随便用(只能用动态链接库),一旦公司规模超过3人,就得买版权了(也就有权静态连接了)。
它内部封了一个浏览器核心,但对这个浏览器核心做了大量的精简,不像Electron和NW.js动辄上百兆的体积,它只要6M左右就够了。底层的绘制引擎我记得是谷歌的skia,
开发者可以使用HTML,CSS,JS来创建界面,当然由于底层是一个阉割版的浏览器核心,这也意味着有些浏览器特性它是不支持的,
比如CSS3的flex布局,它就不支持(但它提供了自己的flex布局实现方式)。
以前它使用自研的一个脚本语言(和JavaScript很像),自从集成了Fabrice Bellard大神的QuickJs之后,就全面支持JavaScript了。
另外,它还对一些特殊的场景做了内置的支持,比如渲染大列表。
它使用C++开发,对C++开发者很友好,有Rust、go、Python等语言的绑定,但都是社区提供的,质量堪忧。
有很多知名厂商都用这个库做界面,比如360、teamviewer、赛门铁克等。
另一个库RmlUi和Sciter很像,可以看成Sciter的替代框架,
但RmlUi这个项目有三届作者,一个一个的弃坑不知道新任作者会不会弃坑,目前还不是很成熟,比如我正在尝试帮作者解决的CJK输入法的问题,目前还不推荐大家使用这个框架。
CEF
CEF是2008年创立的,基于Chromium的跨平台GUI框架,稳定且商业授权友好,
国内很多大厂都用的CEF:比如微信桌面端、网易云音乐桌面端(Win)、QQ桌面端、微信桌面端、MATLAB、FoxMail、OBS Studio,装机量破亿(过于保守)。
由于它几乎封了一个完整的Chromium,所以体积非常大,但它支持所有的HTML\CSS\JS特性,
它几乎不提供任何与操作系统相关的API,创建个托盘图标、读写个文件啥的,都要开发者自己完成,
它是C/C++开发完成的,对C++用户非常友好,它有go\python\java等语言的绑定,但都是社区提供的,质量值得担忧。
它对Chromium封装的很好,避免了开发者直接与Blink、V8、Chromium等复杂的代码打交道,
很多功能都有默认实现方式,遵从约定由于配置原则,有经验的C++开发者可以很轻松的驾驭CEF框架。
由于Chromium是版本弟,所以CEF版本发布也非常频繁,很多被标记为稳定的版本,还是会出一些莫名其妙的问题,选一个好的版本非常重要。
与Electron一样,它也是分主进程和渲染进程的,所以开发者要非常娴熟的运用跨进程通信的技术,
虽然CEF提供了跨进程相关的API,但复杂度还是有点高的,使用的时候要认真细心。
这是我在掘金写的关于CEF的系列课程:https://juejin.cn/book/7075387142121193502
MAUI
这是微软的跨平台GUI框架,不仅仅支持桌面端,还支持移动端,但官方并不支持Linux的桌面端(黑人问号,感觉与微软近些年向开放、开源的大方针相悖),
这个框架新的狠,至今还没发布稳定版。
它是.NET平台下的GUI框架,有自绘引擎,对C#开发者很友好,界面依然是用XAML描述的,可能很多人一听到XAML就直接弃坑了。
XAML表现力确实弱一些,我觉得WPF没火起来跟XAML有直接关系。
这是我个人的观点,也是相对来说吧(比HTML/CSS弱)。很多人觉得XAML挺好,也很有道理的。我无意与大家争论,也不想改我的原文,关于这方面的问题,请大家不要评论了。
使用这个框架开发桌面应用得封一个.NET框架给用户,当然有了.NET框架应用程序访问一般的系统级API也就不成问题了。
Compose Multiplatform
这是JetBrains搞的跨平台GUI框架,也非常新,前段时间刚刚推出1.0.0版本,
但这个版本还不是很稳,至少比Flutter Desktop的第一个稳定版要差很多。几乎没什么人用。
它的自绘引擎用的是Google的skia,这个自绘引擎稳的很,Chrome和Flutter都是用的它,
所以绘制、渲染之类的工作不太会出问题。比Java生态圈里的Swing和JavaFx要好很多。
JetBrains的东西当然对Kotlin开发者友好啦,Java生态下的很多东西你都能用,访问系统级API也没啥大问题,同样也得考虑封一个JRE给用户。
flutter-desktop
这是谷歌的跨平台开发框架,开源、免费、文档齐全、投入力度大且持久,
桌面端同样也新的很,Windows版本刚刚发稳定版,Mac版本还没稳定。
如果你完全没搞过移动端的flutter,想用这个框架开发桌面应用,那么意味着你要学的东西还挺多的。好在dart和flutter入门都不是很难,学习曲线比较平缓。
由于flutter在移动端积累了很多年,所以界面上的一些东西在desktop端都比较稳(skia自绘引擎),
与操作系统相关的东西还不成熟,生态也不太好,
比如你想订制一下窗口的标题栏,想访问一下注册表这类工作可能得自己想办法。
不过它有类似FFI的支持,跟C/C++语言打交道很方便。
开发者直接使用Dart语言描述界面,这会导致众多大括号嵌套在一起的问题,可能很多开发者不习惯。
使用flutter-desktop开发的应用程序打包后体积还比较大
webview2
这是微软Edge浏览器团队推出的跨平台GUI引擎,是闭源的,
目前只支持Windows,对C#和C++开发者友好,
如果使用C#开发,就得考虑把.NET运行时分发给用户,
如果使用C++开发,就得自己处理系统级API的操作,webview2本身是不对系统级API做封装的。
这个框架推出有一小段时间了,但很多API也还不稳定,
更值得担忧的是这个团队,他们前不久刚刚放弃了自己的浏览器核心转而使用Chromium浏览器核心,不知道他们会不会放弃webview2这个框架。
它的优势是可以复用系统当中已存在的webview2二进制资源,
也就是说它虽然封了一个Chromium浏览器核心,但如果你可以确定客户电脑已经存在了基于webview2开发的应用,你的安装包体积可以足够小。
它也是多进程架构,甚至比Electron还要多一个进程(为了复用二进制资源),资源占用比较多。
更详细的介绍可以看我这篇文章:https://zhuanlan.zhihu.com/p/428560381
webview
这个库使用操作系统的浏览器引擎来达到减小安装包体积的问题,
Mac上使用Cocoa/WebKit,Linux上使用gtk-webkit2,Windows 10上使用Edge(也就是上一个小节里提到的webview2),
它是不支持Win7的。由于不同的OS会用不同的浏览器核心,所以开发者使用它开发跨平台应用时要考虑前端代码浏览器兼容的问题。
开源且免费(MIT)有go、Rust、Python等语言的绑定,不过官方支持的是go语言,C和C++,
操作浏览器的API非常少,不支持自定义scheme,更别提系统级API了。
TAURI
采用的技术方案与webview类似,所以安装包也足够小,非常新,还没发布稳定版,开源免费。webview框架碰到的问题TAURI都有,
使用Rust开发,将来会支持Deno,作者说将来会直接使用webview的技术来支持多平台,
NW.js
NW.js最早把Chromium和Node绑定到一起,用前端知识做界面,用Node技术访问操作系统,
最早叫node-webkit,在2012年创建。
NW.js基于MIT开源,可以无忧使用。
微信小程序开发工具好像是用NW.js开发的(几年前调研过)。作者是英特尔的员工,英特尔的一些工具也是用NW.js开发的。
除了Chromium和Node的能力外,NW.js自己也封装了一些系统级API,类似托盘图标、剪切板、系统菜单这种,但数量明显比Electron要少。
NW.js可以在多个窗口间共享同一个Node.js上下文,而且还可以通过配置让Node的上下文和Dom上下文混合,这给开发者带来了很多便利。心智负担减少很多。
不像Electron要时刻想着进程间通信,哪些模块当前进程不能用这类问题。
NW.js虽然起步早,但奈何没有杀手级应用,周边的生态和工具链没发展起来。
用的人越来越少,维护的投入也不如Electron大,再加上Chromium更新非常频繁,导致NW.js的有些API也不是很稳,恶性循环加剧。
Electron
Electron的作者曾经在NW.js团队工作过(NW.js项目贡献第二多的人就是Electron的作者),
后来辗转到了github公司,于2013年在创建了Electron,
也是个开源免费的产品。由于VSCode、slak等国际型产品都选择了Electron,所以从者甚众,
生态和周边工具链也完善的多。虽然开发方式上有点蹩脚的地方(多进程架构及模块归属进程),但瑕不掩瑜。
Electron每创建一个窗口都会多一个进程,这使Electron创建窗口的效率不高(秒级),
NW.js有复用进程的机制,即使新窗口加载完全不同域的页面也不会创建新的进程(毫秒级)。
这也是为什么很多基于Electron开发的应用都使用Dom模拟弹窗的原因。
无论是浏览器相关的API,还是系统级API,Electron提供的都比NW.js多。
ImGui
https://github.com/ocornut/imgui
这个GUI框架的实现原理和开发方式可谓独树一帜
它在一个无限循环里不断的重绘整个界面,
别的GUI框架都是哪里更新了重绘哪里,它是无论有没有更新,一股脑全部重绘,而且一直在重绘,
这样做对于一些不支持GPU的客户端来说CPU消耗会略高一些,不过总起来说还算好
它对游戏开发者很友好,很多游戏都集成它来做用户交互(游戏内的一些设置界面、聊天界面之类的)
它支持很多种绘制引擎比如OpenGL,Directx,Vulkan等
打包后体积很小,也就几百K的样子
也有一些小问题,比如:要用很蛋疼的方法在界面内使用同一种字体的不同的字号
你如果打算使用这个库,我建议你不要选master分支,而选docking分支(这个分支下有很多amazing的特性)
与这个框架类似的还有:https://github.com/Immediate-Mode-UI/Nuklear
总结
我们介绍了这么多框架,可以说各有各的特点,有的成熟稳定,有的运行高效,还有一些框架单凭业务表达能力取胜,开发者在做技术选型时往往会难以抉择。
这里我总结了三个判断桌面软件开发框架是否优秀的底层逻辑,这可以帮助我们开发者认清真相,做出最优选择。
第一,是否具备独立的界面描述语言( UI DSL )。
这非常重要,是一个框架表达业务的重要能力。
类似 WPF 的 XAML、qt ui 文件里的 XML、 HTML + CSS 都属于界面描述语言,这都属于一种通过特化的 XML 来描述界面的方式;
还有一种通过代码来描述界面的方式,flutter、qml 和 Compose Multiplatform 都以类似这样的界面描述语言来描述界面的。
如下伪代码是 Compose Multiplatform 的界面描述形式:
panel {
row {
checkBox(...)
row {
textField(...)
}
}
}
但无论如何,显而易见的是,没有任何一个界面描述语言能比得上 HTML + CSS 组合。
想想看:HTML 里各种五花八门的语义化标签和 Dom 操作技巧、CSS 里的布局方式、伪元素、动画描述等,就会明白这一点。
第二,是否拥有强大的事件处理机制。
作为一个 GUI 应用,与用户的交互、与设备的交互必不可少,
这就涉及到形形色色的事件,比如,与设备有关的鼠标事件、键盘事件、触屏事件、网络状态变更事件等,
与界面元素状态有关的界面加载完成事件、媒体播放结束事件、元素大小改变事件等。
另外,能接收这些事件还远远不够,还得处理事件冒泡、事件捕获、事件分发,等等。
我认为 JavaScirpt 与浏览器核心的结合来处理各种各样的事件也是表现出众。
而且经历了数十年的发展,这套组合的事件系统也相当成熟稳定。
第三,是否拥有强大的异步、并行处理机制。
开发者不能在处理用户业务逻辑的时候,让界面渲染工作阻塞,
这就需要一个强大的异步、并行处理机制,
如果让开发者自己去创建线程并完成这些工作,无疑是又麻烦又会增加开发者的心智负担。
JavaScirpt 虽然是单线程执行的语言,但浏览器核心是多线程的(还是多进程的),
所以 JavaScript 与浏览器核心结合后,开发者既不用为开发多线程应用而苦恼,又不用为没有多线程的支持而手足无措。
从以上三方面的技术需求来看,在桌面 GUI 应用里封装一个浏览器核心还是非常有价值的,
这样开发者就可以用 HTML + CSS 强大的能力来描述界面,
用 JavaScript 强大的事件处理机制和异步处理机制来完成用户交互。
web相关的技术之所以胜出,并不是这些技术的设计者有多厉害,而是这20多年间,有大量的人涌入了这个领域,前赴后继的推动着它前进。
其他任何一个领域都没有这么热火朝天的景象。推荐大家看看我的另一个回答:
用Web相关的技术做GUI应用的优势是,让开发者可以把大部分精力投注在业务本身上,而不是处理与GUI相关的技术细节。
实际上所有的框架,都应该是这个目的,比如ORM框架,目的应该是让开发者把大部分精力投注在业务与数据之间的关系上,而不是管理关系型数据的技术细节。
当然这肯定是有损耗的,在性能、稳定性、资源消耗上,都会有所削减。
而且,因为有框架的存在,开发者很难深入到框架内部做一些特殊的事情。
比如,我们该如何修改HTML的排版渲染机制呢?
所以,有些框架注重性能,有些框架注重开发效率,开发者做选择题的时候也应该衡量这两个问题,你的应用对哪些方面要求多一些呢?
你如果要开发一个视频监控系统,没多少业务功能,但要24小时不间断的记录视频数据,随时调取某一段时间的视频数据,这种应用可能Qt是最好的选择。
你如果要开发一个类似飞书的团队协作应用,业务逻辑复杂的一塌糊涂,
而且要在短时间内满足更多用户的需求,占领更多的市场,
那么Electron可能是更好的选择(目前飞书已经不再用Electron了,他们自己编译了Chromium核心,自己封了一个类似CEF的框架)
目前微软、谷歌、JetBrains等公司都非常重视桌面端开发框架,也在推各自的框架产品,说明桌面应用领域并没有没落,反而应该更加受到重视。
虽然移动端应用大行其道,但我认为,只有生活、社交、轻娱乐等方向上的应用在移动端有较好的发展。
文档协作、大型游戏、开发工具、专业管控软件等应用还是在PC端发展的更好一些,毕竟PC端有更多样的输入输出设备、更广阔的显示和交互的空间,更强的存储和计算能力。
希望桌面软件开发领域的从业者都能获得幸福。
满屏荒唐言,一把辛酸泪,一把辛酸泪,一把辛酸泪...