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日志的量也非常庞大,过滤条件加太多又会忽略代码和系统层面交互的异常。曾经定位一个不确定什么时间出现的偶现BUG,5个多小时的时间,本地存储的hilog全量日志就达到了1.2GB,随后经过足足20多次裁切、grep -v ""剔除才将日志缩减到33MB(24万3千行),然后再通过关键字逐一筛选,定位到了第15万1千行附近的日志与系统交互异常……
    微信图片_20260920192142_69_81
  • 不便于调试,鸿蒙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()调用。

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)都会有大大小小的兼容问题,如果项目不大,处理这些兼容问题的时间做本地化开发也足够了,可以把更多的精力放在业务层实现上。

posted on 2026-10-08 12:18  书生执笔画浮沉  阅读(54)  评论(0)    收藏  举报

导航

 
途虽修远,非庸人之可企及            运虽多舛,非志士之所屈从