Linux桌面端应用向鸿蒙PC迁移适配纪实

背景

不知不觉,向鸿蒙的迁移工作从调研开始算已经半年多了,每次总觉得提测没问题了,就会又测出新的问题

不过这次应该可能......但愿真的没问题了,故趁着提测的空档,梳理这一篇文章作为记录,内容仅供参考

我们原本是运行在 Linux 中的 C++&Qt 项目,由一个用户界面和多个底层服务构成。

公司里所有人包括笔者在内都没有做过移动端开发,为什么明明是 PC 却说这是移动端开发呢,详见正文

什么是鸿蒙PC

鸿蒙系统实际上只有一种,在鸿蒙系统上又衍生出了对手机、电视、手表、PC/二合一设备的支持

所以非平台强相关的鸿蒙应用,理论上可以通过简单适配,运行在任意鸿蒙设备中,初衷是好的

但同时也因为如此,就造成了常规Windows\Linux桌面端应用难以进行迁移适配的窘境

例如缺少工业设计相关、图像处理相关、编程开发相关、桌面端游戏等大量生态

我们也就看到了鸿蒙电脑原生运行王者而不是英雄联盟的画面

因为像桌面游戏这种大多只有X64版本,它们除了下面这些工作外还要涉及跨架构适配工作

开发工具有哪些

目前针对鸿蒙开发主要有两套开发工具,一套是DevEco Studio ,属于集成式IDE,但其只能运行在Windows/macOS

如果你已经习惯了使用命令行,不想把Linux代码拷贝至上述两个陌生平台,那么就只能用另一套,也就是Command Line Tools 了

但使用Command Line Tools 有个缺点,它出包需要有完整的项目配置文件,但它似乎 并不支持初始化一个空项目作为模板

所以你还是需要先安装DevEco Studio然后用其生成一个空项目配置文件目录,拷贝到Linux中作为模板,改造后才能使用......

具体的生态差异有哪些

  • 通常为了高兼容性与平台一致性,在Linux中我们常用 gcc 作为编译器,而 鸿蒙SDK 携带的是基于 musl libc 的 clang 编译器,这也就导致了鸿蒙中的C、C++开发必须严格遵循 POSIX 标准,Linux 常用的 GNU扩展接口 均无法正常使用。
  • 在鸿蒙中,一个完整的应用,往往需要Ark TypeScript代码层 + C++代码层实现,因为有些系统能力 系统的C/C++库 并不提供,这也是和常见的桌面端应用开发不一样的地方。
  • 上下层分离问题,以往上下层分离往往是依据进程分为人机交互界面和底层服务,而鸿蒙中一个应用就是一个进程,且不允许私自创建进程,故只能通过线程进行上下层分离。
  • 在 Linux 系统中开发,往往需要关注 root 权限问题,将需要高权限的行为下放到底层高权限服务中实现,而鸿蒙有自己的一套权限体系,申请了某个权限就允许你调用相关的接口。
  • 沙箱化,这也是和移动端开发非常像的地方了,区别于普通的桌面端开发,鸿蒙中每个应用都在独属于自己的沙箱中,虽然提高了安全性,但这也在不使用DevEco Studio的情况下,提高了调试难度。
  • 日志系统,常规的桌面端开发我们通常会引入第三方日志依赖,例如谷歌的glog等,而鸿蒙有自身的hilog系统,并提供了对应的C/C++库和接口,如果不进行相应的处理,查看沙箱中的日志文件变得非常烦琐,即使引入了重定向,hilog日志的量也非常庞大,过滤条件加太多又会忽略代码和系统层面交互的异常。
  • 不便于调试,鸿蒙PC的系统中本身并不携带任何常见的调试工具,即使存在也会因为沙箱机制难以适用。
  • 最后,区别于常规的 Linux 应用开发,实现某个功能可以有大量的方案,非常自由;鸿蒙属于面向框架的开发,实现某个功能往往只有那几个固定的接口,或许移动端开发都这样吧。

需要进行的常规工作有哪些

以下工作需要结合自身项目取舍,所以仅供参考。

  • 将代码 POSIX 化、 将界面、服务的库化、线程化,将原有的可执行程序包装为线程再编译成库,然后导出启停符号......、移除所有system 、popen 、execve 家族调用。
  • 对于原有代码的复用,则是实现了 桥接库 以及 Ark 实现层,部分业务在桥接库中使用鸿蒙提供的 C++ 库实现,另一部分穿透桥接库,使用 Ark TypeScript代码层 实现。
  • 关于出包,在前面开发工具小节已经有部分描述了,鸿蒙当前也只提供了 Windows 和 Mac 的教程,于是结合前两者摸索了一套 Linux平台 的出包模板,使用 SDK 中携带的工具出包、使用 java 命令进行签名、然后将一系列步骤整合进自动化出包脚本得以实现。
  • 关于日志,需要分析项目当前使用的第三方日志系统是否支持重定向,而glog虽然比较老,但是在日志重定向上是支持的,这就节省了很大一部分工作量。
  • 关于调试,单独找台机器安装DevEco Studio 进行无线调试,DevEco Studio中的堆栈信息还是比较丰富的,可以获取到是因为ArkTS代码引起的崩溃,还是C++代码引起的崩溃。

关于Qt

  • 对于界面从 Linux 平台的移植,有两个Qt版本可用,一是GitCode社区版本,另一个是QT官方版本, 本人最终选用了 GitCode社区 的版本,原因是官方版本行为差异较大,很多行为与 Linux 系统中并不一致,虽然社区版本也有行为差异,但整体可接受。
  • 关于 QT 与 ArkUI 画布的转接,GitCode 和官方的 Qt ,在画布转接上完完全全是两套不同的逻辑......,最后是配合 Ai 边猜边试实现的,记得一遍遍调整得(děi)有十几二十几次吧。

重点

后期测试过程中,发现一些场景下界面经常假死,经排查发现是由于QDialog界面的exec()调用引起,使用Ai进行深度分析后,得到在移动端开发中,不建议使用QDialog的exec()调用的结论,因为移动端开发中并非Qt原生管理画布而是桥接,存在异步时差,且QDialog的exec()底层机制属于事件循环嵌套,放大了由于异步导致状态不同步的概率,从而诱发界面假死,而我们所有的界面、子界面,几乎全部基于QDialog......
由于上述原因,叠加exec()的同步阻塞的特性(如下伪代码所示),导致笔者为此修改了很多处代码,将原本需要同步执行的逻辑修改为了异步open()调用。

cpp 复制代码
void classX::slot_A()
{
	......
	func_B();
	......
	func_C();
	......
}
void classX::func_B()
{
	......
	func_D();
	......
	func_E();
	......
}
void classX::func_D()
{
	// 如果exec更换为异步的open,func_F和func_G、func_H等虽然可以通过绑定Rejected的槽函数得以调用
	// 但是,上层函数的func_E和func_C等都会被瞬间执行,从而打乱原有业务逻辑,必须修改为闭包......
	// 实际代码中有些地方要更复杂,甚至存在exec嵌套......
	QDialog tmp;
	if(tmp.exec() == QDialog::Rejected)
		func_F();
	else
		func_G();
	......
	func_H();
	......
}

Ai工具

迁移期间,也曾经寄希望于Ai,但无论是gmini还是gpt,由于没有训练数据的支撑,它们也是依靠安卓、IOS的开发惯例去推断某些地方应该是怎么样的

很多时候需要将鸿蒙开发文档手动喂给Ai,有时候需要询问鸿蒙开发文档页面的Ai客服......

后续建议

如果团队人员充沛,建议使用 Ark UI+ TypeScript + DevEco Studio 进行原生开发,原因是无论官方还是社区的Qt,在目前(2026.09)都会有大大小小的兼容问题,如果项目不大,处理这些兼容问题的时间做本地化开发也足够了,可以把更多的精力放在业务层实现上。

相关推荐
(Charon)1 小时前
【C++面试】单例模式:懒汉式与饿汉式的实现、区别与线程安全
开发语言·c++·面试
某不知名網友1 小时前
ROS2入门:命令行启动节点与Launch程序
c++·机器人
小米里的大麦2 小时前
C++ 移动语义
c++·后端
jimy12 小时前
虚函数和 RTTI实现运行时多态
开发语言·c++
今夜有雨.2 小时前
图像运算、掩膜/ROI 与绘制交互
c语言·数据结构·c++·qt·算法·计算机视觉
UIU1142 小时前
P1028 [NOIP 2001 普及组] 数的计算
c++·算法
垆边人似月.3 小时前
日志时间窗口内的最大并发请求数(100分 / 滑动窗口 + 排序)
数据结构·c++·算法
Chen_harmony3 小时前
一、C++入门基础
开发语言·c++
水饺编程4 小时前
第1章,[Win32 章节]:Windows 的方方面面
c语言·c++·windows·visual studio