# Why, What and How
这篇文章主要用于回答关于产品的常见灵魂三问。
# 为什么?
相信会有不少朋友看到 LarkSDK,第一反应都是“您们为什么要做这个产品”?
“为什么”是我们在开发 LarkSDK 的过程中被问到的最普遍的问题。在当下基于 Web 构建跨平台用户界面的相关技术正在蒸蒸日上的条件下,为什么还要“吃力不讨好”的去做这么一款基于 C++ 的,直接和底层 API 对接的,直接面向操作系统原生的图形界面开发框架?
上面一句话其实已经初步回答了 What 的问题:LarkSDK 是直接和操作系统底层图形相关 API,或者说窗口系统(Win32、Linux/X11、Linux/Wayland) 对接的。它永远不会涉及任何“中间商”(Qt、Gtk、甚至 SDL、GLFW),这是我们在立项之初就明确决定的第一件“吃力不讨好”的设计。这么做的目的也很简单:我们希望在最大程度上减少项目的外部依赖。这是我们面向自研这一原初理念作出的郑重承诺。这是我们对于 Why 的第一个回答:因为我们想要实现真正意义上的纯自研(当然我们在这里的纯自研是指在图形应用软件开发这个层面),同时通过控制第三方依赖也可以尽可能控制开发工具的尺寸大小。
另一个 Why 说起来就比较“情怀”了:我们是真的想从头开始实现一款这样的产品。几乎我们的所有客户,在过去的项目中,对于国产化、车载场景、机载场景、手持场景、运行效率、部署难易度等指标都有较高要求,在这样的要求下还要想高效率开发图形界面,基于 Web(BS 架构)、Electron、C#、Java 等或传统或时髦的方案都或多或少的存在缺陷和硬伤,而 Qt 就几乎成了唯一的选择(据调查,超过九成的客户项目均或多或少在代码中引用了 Qt)。
作为曾经深度使用过 Qt 进行开发的团队,我们在项目实时过程中积累了大量的开发经验和客户反馈。对于不少客户来说,Qt 甚至是都称不上一个“选择”,而是“不得不用”的无奈。然而,Qt 臃肿的开发端和部署端体积、不太“现代”的界面构建代码风格、针对大规模图元场景的优化不足存在性能瓶颈问题等,都使得客户在使用基于 Qt 开发的应用软件的过程中积累了大量抱怨点。而这些框架本身存在的问题,在框架提供方为国外厂商的情况下(甚至更进一步,对于版本更新和技术支持存在断供风险 (opens new window)的情形下),是几乎不可能从框架的层面获得任何支持的。
因此,我们从客户的具体需求出发,结合团队现有的图形用户界面开发经验,萌生了“自己做一套”的完整想法。
# 是什么?
一言以蔽之,LarkSDK 是一款跨平台、纯自研、超轻量的图形界面 C++ 开发框架。
让我们直白点说,在保留式 GUI (opens new window) 这一领域,Qt 仍然是一个占据统治地位的产品,无论是从市场保有量还是产品成熟度,都是一堵几乎不可逾越的高墙。基于团队已有的开发经验,我们在框架的架构和 API 设计上也的确深度参考了 Qt 的设计理念,同时把 LarkSDK 设计得更轻量、更简单、更年轻,也更懂国产生态。我们并不奢望取代 Qt,我们仅仅是希望为业界提供另一个选择。
必须说明的是,我们知道 Qt 指代的是一整个产品矩阵,而 LarkSDK 目前阶段对标的实质上是 Qt Framework (opens new window)。和它类似,LarkSDK 在设计之初就是致力于跨平台的,它封装了不同操作平台的特性和底层调用,隐藏了各个操作系统平台的不同之处,让用户可以专注于业务开发而无需过多关心平台差异;同时,LarkSDK 也并非单纯的浅层 GUI 组件库,它覆盖了从底层的操作系统事件监听与分发,到通用的跨平台用户组件的外观与行为定制;它既提供各种各样的底层代码工具,以提升 C++ 的开发效率和体验,又能够通过自带的用户界面框架直接构建图形用户程序,未来还将提供界面编辑器及自动化测试工具等,从而完成应用软件开发的全生命周期闭环。
LarkSDK 于 2021 年在合迅科技正式立项,与成都电子科技大学合作研发,被中国高等教育学会认定为“校企合作 双百计划”成功案例 (opens new window),并于 2023 年 8 月正式上线发布初版。之后团队持续投入维护至今,目前版本已基本趋于稳定,同时支持 Windows 和 Linux 操作系统,并在多款国产操作系统上通过完整测试。项目获得诸多荣誉,包括“第五届中国先进技术转化大赛银奖(2023) (opens new window)”、“四川省计算机科学技术一等奖(2022) (opens new window)”、“成都市中国软件名城建设影响力产品(2023)”、“首批‘成都工业精品’(2024)”等等,同时于 2024 被列入《某目录》 (opens new window),成为目录中首个属于国产 C++ 开发平台门类的产品。
# 怎么做?
简而言之,我们可以简单的把 LarkSDK 分为多层架构设计,自底向上罗列如下:
# 1. 基础设施层
基础设施层包括一系列常用的数据结构和算法的设计与实现,包括动态长度序列容器、链表容器、字符串、字符串序列容器、字节序列容器、变体数据类型、元组类型等。其主要目的是在原生 C++ 之上封装一些易于使用的基础设施,以支持框架内上层功能模块的工作。
基础设施层单独封装于 LarkSDK-Util 库之中,是完全与平台无关的通用代码。除了为 LarkSDK 上层提供支持之外,也可以在应用程序中被单独引用。
# 2. 平台适配层
也称内核支持层,主要用于适配对接不同操作系统的各类接口,包括多线程支持、文件系统支持、事件机制封装、动态库插件框架、日志系统、基于事件驱动范式的主程序框架等。
对于这些接口,不同的操作系统都有不同的具体 API 实现(例如 Win32 实现和 Posix 实现的区别)。平台适配层的目的是对 LarkSDK 的用户隐藏这些区别,便于用户编写平台无关的应用程序代码。
LarkSDK 的对象模型系统也位于这一层,该子模块实现了对象树与信号槽机制。
平台支持层单独封装于 LarkSDK-Core 库之中,除了操作系统基础库之外,它只依赖 LarkSDK-Util 库。若用户希望基于 LarkSDK 编写非图形界面程序,可以只引用 LarkSDK-Core 和 LarkSDK-Util。
# 3.1. 图形绘制层
图形绘制层是一套完整的图形绘制流程。包括可绘制表面、绘图引擎、绘图上下文、字体数据库、位图以及各种基本图元等。其中可绘制表面、绘图引擎、绘图上下文均以抽象接口的形式实现,使得 LarkSDK 除了可以使用自带的软渲染引擎进行图形绘制之外,还可以引入 OpenGL 绘图引擎,或 Cairo 绘图框架。基础图形层所实现的绘图能力,为上层窗体和组件的实际绘制打下基础。
图形绘制层的输出是缓冲区数据(类似于将绘制好的界面输出为位图)。随后数据将通过窗口系统层被同步到操作系统的窗口内,图形用户界面就在屏幕上显示出来了。
# 3.2. 窗口系统层
也称为窗体上下文层、和平台适配层类似,该层也用于和操作系统的窗口系统(Window System)接口对接,封装了不同窗口系统下的差异。LarkSDK 之所以能同时支持 Windows 和 Linux 图形界面,是因为窗口系统层控制操作系统原生窗体承接了图形绘制层传来的缓冲区数据。
窗口系统层这对 LarkSDK 的用户几乎是透明的,用户通常无需直接接触窗口系统层。
# 4. 用户组件与窗体层
在图形绘制层和窗口系统层的支持下,用户就可以进行窗体和组件的搭建,来创造丰富多彩的图形用户界面了。LarkSDK 提供了一系列预定义的,可直接使用的常见窗体与组件类型,如顶层窗体、对话框、菜单、标签组件、按钮组件、文本输入组件等。除此之外,LarkSDK 还实现了一套组件布局系统,方便用户进行界面构建。
后续维护中我们也会直接在该层继续添加更多的用户组件。当然,用户自己也可以基于窗体与组件基类,通过派生类的方式构建自定义组件。
图形绘制层、窗口系统层、用户组件与窗体层均封装于 LarkSDK-GUI 库。