HarmonyOS鸿蒙PC的QT应用开发:QT项目运行原理与 EmbeddedUIExtensionAbility介绍

HarmonyOS鸿蒙PC的QT应用开发:QT项目运行原理与 EmbeddedUIExtensionAbility介绍
好消息,2026年3.31日,QT官方正式发布鸿蒙版QT。本次开源发布正式推出面向鸿蒙系统平板和PC设备的Qt 5.12.12 LTS 适配版本,在完整保留 Qt 5.12.12 核心能力(含界面渲染、信号槽机制、跨平台 I/O、网络通信及数据库模块)的基础上,深度适配鸿蒙系统架构。本版本可降低开发者跨平台移植成本,加速 Qt 与鸿蒙生态融合,助力多场景鸿蒙应用高效开发。

QT官方鸿蒙版开源地址https://wiki.qt.io/Qt5.12.12_Open_Source_Release_for_HarmonyOS_zh

QT官方文档地址https://wiki.qt.io/Qt_for_OpenHarmony/zh

在这里插入图片描述

前言

在 HarmonyOS 上运行 Qt 应用,跟传统的PC上的QT应用不同。

传统的PC上的QT应用是使用QtCreator开发完成后,直接编译为可执行文件exe.。 而鸿蒙版QT的开发流程,则是使用鸿蒙版QT的SDK和qmake工具链,最终的编译产物为.so. 之后呢还需要鸿蒙的QT工程项目模版,把so加载进去,将应用编译打包为hap或app包。

在HarmonyOS 上运行 Qt 应用,通常需要三层协作:系统 Ability 与窗口ArkUI 中的原生节点(XComponent),以及 Qt 平台的 QPA 插件(本模板中为 libqohos.so。当产品希望在「不整页跳转」的前提下,把 Qt 界面嵌进另一个界面的指定区域时,系统提供了 EmbeddedUIExtensionAbility(嵌入式 UI 扩展能力):由宿主页面的 EmbeddedComponent 发起一次嵌入会话,扩展侧在独立能力中加载页面并完成绘制与交互。

本文以鸿蒙项目模版,仓库内 ohostemplateforqtapplication_20260331 为例,介绍下QT项目结构运行原理与 EmbeddedUIExtensionAbility。

ohostemplateforqtapplication是用于构建最终 OpenHarmony Qt 应用程序的 DevEco 项目模板。这将用于在 HarmonyOS 设备上运行 Qt 应用程序。 开发者也可以从以下链接获取最新项目工程模版: http://codereview.qtcompany.cn:29416/template/

应用级 app.json5、工程级 build-profile.json5、模块级 module.json5ArkTS 与原生库调用关系,说明模板工程的运行原理,并单独梳理 EmbeddedUIExtensionAbility 在本项目中的职责与数据流。文中代码与配置均来自当前仓库快照;系统 API 行为以你所使用的 HarmonyOS SDK 版本及官方文档为准。


1. 核心概念

1.1 Qt 在鸿蒙模板中的位置

  • 入口形态:模板将 主界面 实现为 UIAbility 子类 QAbility,生命周期各阶段委托给 libqohos.so 暴露的 NAPI(代码中以 import qpa from 'libqohos.so' 引用),由 Qt for OpenHarmony / HarmonyOS 的 QPA 与系统窗口、输入等对接。
  • 绘制落点:ArkUI 页面通过 XComponenttype: XComponentType.NODElibraryname: 'qohos' 创建原生节点;QPA 在该节点上挂载 Qt 的渲染与事件循环逻辑。主窗口与嵌入扩展会话各对应一套页面与节点,但共用同一套 qohos 原生模块名。
  • 业务库:实际运行的 Qt 可执行形态为共享库(如 libcalculator.so),名称在 QtAppConstants.etsAPP_LIBRARY_NAME 中配置,并需与 entry/libs/<ABI>/ 下放置的 .so 一致。

1.2 EmbeddedUIExtensionAbility 在本项目中的角色

  • 系统定义EmbeddedUIExtensionAbility 是嵌入式 UI 类扩展能力,与 UIExtension 会话(UIExtensionContentSession 绑定;每次嵌入对应一次会话创建与销毁。
  • 模板封装QBaseEmbeddedUiExtensionAbility 继承系统基类,在 onCreateonSessionCreateonSessionDestroyonDestroy 中统一转发到 qpa.handleQEmbeddedUiExtensionAbility*;并在首次创建时用 uiExtensionMode: true 初始化 Qt 应用上下文,使 QPA 按「扩展嵌入」路径而非普通全屏 Ability 路径工作。
  • 双扩展名module.json5 声明了两个嵌入式扩展:QEmbeddedUiExtensionAbilityextensionProcessMode: "instance")与 QBundledEmbeddedUiExtensionAbilityextensionProcessMode: "bundle"),便于在同一模板内对比或选用不同进程/打包语义(具体调度以系统实现为准)。

1.3 宿主侧 EmbeddedComponent

  • 使用位置:模板在 feature 模块qEmbeddedUiExtensionHost 中提供演示 Ability EmbedQtAbility,其页面通过 EmbeddedComponent(want, EmbeddedType.EMBEDDED_UI_EXTENSION) 指定要拉起的扩展能力名称与参数。
  • Want 约定EmbedQtAbilitybundleName 设为当前应用包名,abilityName 设为 QEmbeddedUiExtensionAbility,并把启动参数中以 io.qt. 为前缀的项传入扩展,供 Qt 侧读取。

2. 工程与模块结构

2.1 应用标识(AppScope/app.json5)

应用级配置定义包名与版本信息,嵌入场景下 Want.bundleName 必须与之一致(模板在代码中用 getBundleInfoForSelfSync 取当前包名,避免硬编码错误)。

//:ohostemplateforqtapplication_20260331/AppScope/app.json5{"app":{"bundleName":"com.ohos.ohosqttemplate","configuration":"$profile:configuration","vendor":"example","versionCode":1000000,"versionName":"1.0.0","icon":"$media:app_icon","label":"$string:app_name"}}

2.2 多模块工程(build-profile.json5)

工程级 build-profile.json5 声明两个模块:entry(主模块,含 Qt 与嵌入式扩展)与 qEmbeddedUiExtensionHost(feature,演示嵌入宿主)。构建产物为同一应用包内的多个 HAP/HSP(以实际打包方式为准),因此 feature 中的 EmbeddedComponent 可以指向 entry 中声明的 embeddedUI 能力。

与 SDK 相关的字段示例(签名等本地路径略):

  • compatibleSdkVersiontargetSdkVersion:决定可用的 Ability / Extension API 集。
  • modules 数组:每项 name + srcPath 对应磁盘上的子工程目录。

2.3 entry 模块配置要点(entry/src/main/module.json5)

下列字段直接影响运行时行为,建议对照阅读。

配置项本模板取值含义说明
typeentry应用主模块。
srcEntry./ets/qabilitystage/QAbilityStage.ets指定 AbilityStage 实现,用于多实例、多进程键值与 Qt 全局初始化钩子。
mainElementQAbility默认启动的 UIAbility 名称。
deviceTypestablet2in1声明支持的设备类型;注释中说明 phone 与最小化还原存在已知问题(QTFOROH-1076)。
abilitiesQAbilitylaunchType: "specified"isolationProcess: true多实例与独立进程相关配置,与 QAbilityStage.onAcceptWant / onNewProcessRequest 配合。
extensionAbilities两条 type: "embeddedUI"声明嵌入式 UI 扩展;extensionProcessMode 分别为 instancebundle

嵌入式扩展与主 Ability 的声明片段如下:

//:ohostemplateforqtapplication_20260331/entry/src/main/module.json5"extensionAbilities":[{"name":"QEmbeddedUiExtensionAbility","srcEntry":"./ets/qability/QEmbeddedUiExtensionAbility.ets","icon":"$media:layered_image","type":"embeddedUI","description":"","exported":true,"extensionProcessMode":"instance"},{"name":"QBundledEmbeddedUiExtensionAbility","srcEntry":"./ets/qability/QBundledEmbeddedUiExtensionAbility.ets","icon":"$media:layered_image","type":"embeddedUI","description":"","exported":true,"extensionProcessMode":"bundle"}],"abilities":[{"name":"QAbility","srcEntry":"./ets/qability/QAbility.ets","launchType":"specified",// ..."exported":true,"isolationProcess":true,

要点:type 必须为 embeddedUI,否则系统不会按嵌入式 UI 扩展路由;exported: true 允许同应用内通过 Want 访问该能力名称。

2.4 feature 宿主模块(qEmbeddedUiExtensionHost/src/main/module.json5)

该模块 仅声明普通 UIAbility,不声明 extensionAbilities;嵌入的扩展能力仍落在 entry 中,由运行时根据包内合并后的清单解析。

//:ohostemplateforqtapplication_20260331/qEmbeddedUiExtensionHost/src/main/module.json5{"module":{"name":"qEmbeddedUiExtensionHost","type":"feature","description":"$string:module_desc","mainElement":"EmbedQtAbility","deviceTypes":["2in1","tablet"],"deliveryWithInstall":true,"installationFree":false,"pages":"$profile:main_pages","abilities":[{"name":"EmbedQtAbility","srcEntry":"./ets/embedqtability/EmbedQtAbility.ets",// ..."exported":true,"skills":[{"entities":["entity.system.home"],"actions":["action.system.home"]}]}],}}

mainElement: "EmbedQtAbility" 表示从桌面图标等方式启动该 feature 时,默认进入嵌入演示 Ability。


3. 代码链路:从进程启动到 Qt 绘制

3.1 AbilityStage 与 Qt 单次初始化(QAbilityStage.ets)

QAbilityStage 在普通模式与扩展模式下都会调用 qpa.setupQtApplication,区别是 uiExtensionModeabilityClassName。扩展能力首次 onCreate 时走 initQtAppContextInUiExtensionMode,确保 QPA 以嵌入扩展语义初始化。

//:ohostemplateforqtapplication_20260331/entry/src/main/ets/qabilitystage/QAbilityStage.etsprivatestaticinitQtAppContextImpl(appContext: common.ApplicationContext, abilityClassName:string, uiExtensionMode:boolean):void{if(!QAbilityStage.setupQtApplicationCalled){ hilog.info(LOG_DOMAIN,LOG_TAG,'QAbilityStage::initQtAppContextImpl: init with uiExtensionMode='+ uiExtensionMode); QAbilityStage.setupQtApplicationCalled =true; qpa.setupQtApplication({ appContext: appContext, modules: QtUtils.getModulesMapForQt(), appName:APP_LIBRARY_NAME, appArgs: QAbilityStage.appArgs, abilityClassName: abilityClassName, uiExtensionMode: uiExtensionMode, _unusedQChildProcess:newQChildProcess(),});}else{ hilog.info(LOG_DOMAIN,LOG_TAG,'QAbilityStage::initQtAppContextImpl: already initialized');}}publicstaticinitQtAppContextIfNeeded(appContext: common.ApplicationContext):void{ QAbilityStage.initQtAppContextImpl(appContext, QAbility.name,false);}publicstaticinitQtAppContextInUiExtensionMode(appContext: common.ApplicationContext, abilityClassName:string):void{ QAbilityStage.initQtAppContextImpl(appContext, abilityClassName,true);}

APP_LIBRARY_NAME 来自 QtAppConstants.ets(当前为 libcalculator.so),需与部署到设备上的 Qt 应用库文件名一致。

//:ohostemplateforqtapplication_20260331/entry/src/main/ets/common/QtAppConstants.etsexportconstAPP_LIBRARY_NAME='libcalculator.so';exportconstLOG_DOMAIN=0x0000;exportconstLOG_TAG='ohosQtTemplate';

3.2 主 UIAbility:QAbility.ets

主入口将系统回调逐一交给 QPA,形成与原生鸿蒙应用一致的「创建 → 窗口阶段 → 前后台 → 销毁」节奏。

//:ohostemplateforqtapplication_20260331/entry/src/main/ets/qability/QAbility.etsonCreate(want: Want, launchParam: AbilityConstant.LaunchParam){ hilog.info(LOG_DOMAIN,LOG_TAG,'QAbility::onCreate(): want.parameters: '+JSON.stringify(want.parameters)); QAbilityStage.initQtAppContextIfNeeded(this.context.getApplicationContext()); qpa.handleAbilityOnCreate(this, want, launchParam);}onDestroy():void|Promise<void>{ hilog.info(LOG_DOMAIN,LOG_TAG,'QAbility::onDestroy()');return qpa.handleAbilityOnDestroy(this);}// ...onWindowStageCreate(windowStage: Window.WindowStage){ hilog.info(LOG_DOMAIN,LOG_TAG,'QAbility::onWindowStageCreate(): this.launchWant.parameters: '+JSON.stringify(this.launchWant.parameters)); qpa.handleAbilityOnWindowStageCreate(this, windowStage);}

3.3 嵌入式扩展基类:QBaseEmbeddedUiExtensionAbility.ets

扩展侧在 onCreate 中调用 initQtAppContextInUiExtensionMode,随后各会话阶段同样进入 QPA。子类 QEmbeddedUiExtensionAbility / QBundledEmbeddedUiExtensionAbility 仅区分日志用的类名,行为一致。

//:ohostemplateforqtapplication_20260331/entry/src/main/ets/qability/QBaseEmbeddedUiExtensionAbility.etsonCreate(launchParam: AbilityConstant.LaunchParam):void{ hilog.info(LOG_DOMAIN,LOG_TAG,'%{public}s::onCreate()',this.getClassName()); QAbilityStage.initQtAppContextInUiExtensionMode(this.context.getApplicationContext(),this.getClassName()); qpa.handleQEmbeddedUiExtensionAbilityOnCreate(this, launchParam);}onDestroy():void|Promise<void>{ hilog.info(LOG_DOMAIN,LOG_TAG,'%{public}s::onDestroy()',this.getClassName());return qpa.handleQEmbeddedUiExtensionAbilityOnDestroy(this);}onSessionCreate(want: Want, session: UIExtensionContentSession):void{ hilog.info(LOG_DOMAIN,LOG_TAG,'%{public}s::onSessionCreate()',this.getClassName()); qpa.handleQEmbeddedUiExtensionAbilityOnSessionCreate(this, want, session);}onSessionDestroy(session: UIExtensionContentSession):void{ hilog.info(LOG_DOMAIN,LOG_TAG,'%{public}s::onSessionDestroy()',this.getClassName()); qpa.handleQEmbeddedUiExtensionAbilityOnSessionDestroy(this, session);}

3.4 XComponent 与 qohos:主窗口与扩展会话页面

主窗口节点页面(示例为 MainWindowNativeNode.ets)与扩展内页面 UiExtensionNativeNode.ets 结构相同:在 Stack 中放置 XComponent,指定 libraryname: 'qohos',由 QPA 注册的 native 模块承接 Qt 场景图。

//:ohostemplateforqtapplication_20260331/entry/src/main/ets/pages/MainWindowNativeNode.etsbuild(){Stack(){if(this.createInfo !==undefined){XComponent({ type: XComponentType.NODE, id:this.createInfo.xComponentId, libraryname:'qohos'}).onAttach(this.createInfo.onAttach).onAppear(this.createInfo.onAppear).onDisAppear(this.createInfo.onDisAppear).width('100%').height('100%')}}
//:ohostemplateforqtapplication_20260331/entry/src/main/ets/pages/UiExtensionNativeNode.etsif(this.createInfo !==undefined){XComponent({ type: XComponentType.NODE, id:this.createInfo.xComponentId, libraryname:'qohos'}).onAppear(this.createInfo.onAppear).onDisAppear(this.createInfo.onDisAppear).onAttach(()=>{if(this.createInfo !==undefined){this.createInfo.onAttach?.(this.getUIContext());}else{ hilog.error(LOG_DOMAIN,LOG_TAG,'Cannot call onAttach, createInfo is undefined');}}).width('100%').height('100%')}

3.5 嵌入演示:EmbedQtAbility → Index → EmbeddedComponent

EmbedQtAbilityonWindowStageCreate 中过滤 io.qt.* 参数,构造指向 QEmbeddedUiExtensionAbilityWant,写入 LocalStorage 后加载 pages/Index

//:ohostemplateforqtapplication_20260331/qEmbeddedUiExtensionHost/src/main/ets/embedqtability/EmbedQtAbility.etsonWindowStageCreate(windowStage: window.WindowStage):void{const qtParameterPrefix:string='io.qt.';let qtParameters: Record<string, Object>={};if(this.launchWant.parameters){ Object.keys(this.launchWant.parameters).filter(key => key.startsWith(qtParameterPrefix)).forEach(qtKey => qtParameters[qtKey]=this.launchWant.parameters![qtKey]);}let localStorageProperties: Record<string, Want>={}; localStorageProperties[EmbedQtAbility.EMBEDDED_QT_START_WANT_PROP_NAME]={ bundleName: bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT).name, abilityName:'QEmbeddedUiExtensionAbility', parameters: qtParameters,}; windowStage.loadContent('pages/Index',newLocalStorage(localStorageProperties))}

Index.ets 取出上述 Want,交给 EmbeddedComponentImpl

//ohostemplateforqtapplication_20260331/qEmbeddedUiExtensionHost/src/main/ets/pages/Index.ets@Entry@Component struct Index {private want: Want = LocalStorage.getShared().get<Want>(EmbedQtAbility.EMBEDDED_QT_START_WANT_PROP_NAME)as Want;build(){Row(){Column(){EmbeddedComponentImpl({want:this.want}).width('100%').height('100%')}.width('100%')}.height('100%')}}

EmbeddedComponentImpl.etsEmbeddedComponentwant 不可省略,否则无法拉起嵌入式扩展;onTerminated / onError 用于观测嵌入失败或扩展退出。

//ohostemplateforqtapplication_20260331/qEmbeddedUiExtensionHost/src/main/ets/components/EmbeddedComponentImpl.etsbuild(){Row(){Column(){Text("Hello from EmbeddedComponentImpl")// This is the embedded component used to embed Qt application. Don't remove it.EmbeddedComponent(this.want, EmbeddedType.EMBEDDED_UI_EXTENSION).width('100%').height('90%').onTerminated((info: TerminationInfo)=>{console.warn(`Terminarion: code = ${info.code}, want = ${JSON.stringify(info.want)}`);}).onError((error: BusinessError)=>{console.error(`Error: code = ${error.code}, message = '${JSON.stringify(error.message)}'`);})}.width('100%')}.height('100%')}

3.6 原生侧 entry 库(entry/src/main/cpp)

模板附带最小 libentry.sohello.cpp + NAPI),与 libqohos.so、Qt 应用及 Qt 依赖库 分工不同:前者多为示例或胶水代码,Qt 运行主体由 QPA 与 Qt 共享库承担。CMake 仅声明 entrylibace_napi.z.so 链接,实际 Qt 库通过 entry/libs/<ABI>/ 部署。

#ohostemplateforqtapplication_20260331/entry/src/main/cpp/CMakeLists.txt cmake_minimum_required(VERSION 3.4.1) project(ohosQtTemplate) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${NATIVERENDER_ROOT_PATH}${NATIVERENDER_ROOT_PATH}/include) add_library(entry SHARED hello.cpp) target_link_libraries(entry PUBLIC libace_napi.z.so)

4. 生命周期与数据流小结

4.1 主 Ability 与扩展 Ability 对比

阶段QAbility(UIAbility)QBaseEmbeddedUiExtensionAbility
应用级 Qt 初始化initQtAppContextIfNeededuiExtensionMode: falseinitQtAppContextInUiExtensionModeuiExtensionMode: true
窗口onWindowStageCreate 等,由 QPA 绑定主 WindowStage无独立「全屏窗口阶段」语义;由 onSessionCreate 进入会话 UI
会话不适用onSessionCreate / onSessionDestroy 对应每次嵌入
原生绘制载体MainWindowNativeNode 中 XComponentUiExtensionNativeNode 中 XComponent

4.2 整体数据流(示意)

entry

qEmbeddedUiExtensionHost

Want 指向同包扩展

EmbedQtAbility

LocalStorage 中的 Want

EmbeddedComponent

QEmbeddedUiExtensionAbility

libqohos.so / QPA

UiExtensionNativeNode XComponent


5. 集成与调试时注意点

  1. 库文件部署:将 Qt 应用依赖的qt库的 .solibqohos.so 及依赖的 Qt 模块库复制到 entry/libs/<ABI>/(如 arm64-v8ax86_64),与模拟器或真机 ABI 一致。
  2. 应用库名:修改 QtAppConstants.etsAPP_LIBRARY_NAME,与目标 .so 文件名一致。
  3. 设备类型:entry 与 host 模块当前均面向 平板 / 2in1;若需手机,需评估 module.json5 注释中的最小化还原问题后再改 deviceTypes
  4. 嵌入目标:演示页默认拉起 QEmbeddedUiExtensionAbility;若需改用 QBundledEmbeddedUiExtensionAbility,应同步修改 EmbedQtAbility.ets 中的 abilityName 与测试场景。
  5. 日志:统一 TAG 为 ohosQtTemplate(见 QtAppConstants.ets),便于在 HiLog 中过滤主流程与扩展流程。

6. 与传统 PC 桌面 Qt 应用的差异

  1. 进程与入口不是 main() 独占
    系统先按鸿蒙规则拉起 Ability。全屏场景走 QAbility(UIAbility);需要嵌在别的界面里时走 EmbeddedUIExtensionAbility 子类,由宿主页面的 EmbeddedComponent 触发会话。
  2. Qt 由 QPA 插件接入系统,而不是直接对接 Win32/X11
    ArkTS 通过 import qpa from ‘libqohos.so’ 把 onCreate / onWindowStageCreate / 前后台 / 销毁 以及扩展侧的 onSessionCreate / onSessionDestroy 等转给 Qt for OHOS 的 QPA(libqohos.so)。也就是说:鸿蒙生命周期 → NAPI → QPA → Qt 事件循环与窗口逻辑。
  3. 绘制表面是 ArkUI 的 XComponent,而不是系统原生 HWND 一层到底
    主窗口和嵌入场景都在 ArkUI 里用 XComponent,type: NODE,libraryname: ‘qohos’ 留出一块原生区域;QPA 在这块 NODE 上挂接 OpenGL/渲染与输入。模板里对应 MainWindowNativeNode.ets 与 UiExtensionNativeNode.ets。
  4. “可执行文件”形态是共享库 + 配置名
    业务 Qt 程序一般是 entry/libs// 下的 .so(如 QtAppConstants.ets 里的 APP_LIBRARY_NAME),再配合 libqohos.so 和 Qt 依赖库 一起打包进 HAP。没有传统 PC 上那种用户双击的单一 .exe 作为主入口(入口是鸿蒙 Ability)。
  5. 全局初始化与多实例
    QAbilityStage 里 setupQtApplication 只应执行一次,并区分普通模式与 uiExtensionMode: true 的嵌入模式;module.json5 里 launchType / isolationProcess 等与 onAcceptWant / onNewProcessRequest 一起服务于多实例、进程隔离等鸿蒙能力。

本模板工程中,Qt 并不是「从 main() 起独占进程、直接对接 Win32/X11/Wayland/Cocoa」的传统桌面形态,而是落在 HarmonyOS Ability 模型 之内:由 QAbility(UIAbility)或 EmbeddedUIExtensionAbility 子类 作为系统入口,经 libqohos.so 将 Ability / Session 生命周期交给 QPA,再把界面画在 ArkUI XComponentlibraryname: 'qohos' 所暴露的原生节点上。

除下表外,还可记住三点:入口在 Ability 而非仅 main()平台抽象层是 ohos QPA 而非 windows/xcb 等业务常以 .so + APP_LIBRARY_NAME 形式部署于 entry/libs/<ABI>/

维度传统 PC(Windows / Linux / macOS)本鸿蒙 Qt 模板(ohostemplateforqtapplication_20260331
程序入口main() 中创建 QApplication / QGuiApplicationexec()系统拉起 UIAbility / ExtensionAbility;ArkTS 在 onCreateonWindowStageCreate 等回调中调用 qpa.handleAbilityOnCreate 等,由 QPA 驱动 Qt
平台插件(QPA)windowsxcb / waylandcocoa 等,直连各 OS 窗口与输入栈libqohos.so,衔接 Ability、WindowStage、扩展 SessionXComponent
窗口与 UI 框架Qt 窗口QWidget / QWindow)为主,占满或管理自有层级ArkUI 页面 + XComponent 原生区域;全屏走 MainWindowNativeNode,嵌入走 UiExtensionNativeNode;宿主侧可用 EmbeddedComponent 拉起 EmbeddedUIExtensionAbility
打包与部署安装目录或安装包中的 可执行文件.exe / ELF)及依赖 DLL/soHAP 模块;Qt 应用多为 entry/libs/<ABI>/ 下的 .so,与 libqohos.so、Qt 依赖库 一并随包安装;入口能力名在 module.json5,应用库名在 QtAppConstants.etsAPP_LIBRARY_NAME
生命周期进程启动到退出大致对应应用存活期,前后台多与窗口最小化等相关Ability 前后台、WindowStage 创建销毁、嵌入场景的 onSessionCreate / onSessionDestroy 强绑定,需与 QPA 对齐
设备与系统能力由桌面环境与用户权限模型决定module.json5deviceTypes权限声明多模块(entry + feature)真机/模拟器 ABI 约束

桌面 Qt 可概括为「Qt 即应用外壳」;鸿蒙模板则是「系统 Ability + ArkUI 壳 + XComponent 锚点 + ohos QPA」承载 Qt;嵌入能力再叠一层 同包 embeddedUI 扩展与 EmbeddedComponent。从 PC 迁来时,需改写入口与打包形态,并在调试中习惯用 HiLogAbility 状态 观察运行阶段,而非仅依赖桌面上的进程列表或控制台。


总结

鸿蒙版 Qt 项目模板 ohostemplateforqtapplication_20260331 通过 QAbility + libqohos.so 实现常规全屏 Qt 应用,通过 QBaseEmbeddedUiExtensionAbility + module.json5embeddedUI 声明 提供可被 EmbeddedComponent 嵌入的能力,并在 feature 模块 中用 EmbedQtAbilityEmbeddedComponent 走完端到端演示链路。

理解本模板的关键在于:清单中的 extensionProcessModetype: embeddedUIArkTS 侧对 QPA 的生命周期转发,以及 XComponent NODE 与 libraryname: 'qohos' 作为 Qt 渲染锚点。在此基础上的业务开发,主要集中在 Qt 侧功能、APP_LIBRARY_NAME 与 Want 参数约定,以及权限与 deviceTypes 的调整。


最后,欢迎加入开源鸿蒙开发者社区交流:https://harmonypc.ZEEKLOG.net/

附录:延伸阅读

以下链接供查阅嵌入式 UI 扩展与 HarmonyOS Ability 相关内容:

  1. HarmonyOS 嵌入式 UI 扩展组件实战 - 博客园
  2. HarmonyOS 应用开发中 EmbeddedUIExtensionAbility:跨进程 UI 嵌入 - SegmentFault
  3. 知乎专栏
  4. https://wiki.qt.io/Qt_for_OpenHarmony/zh?login=from_ZEEKLOG
  5. https://wiki.qt.io/Qt5.12.12_Open_Source_Release_for_HarmonyOS_zh

官方文档请优先参考:HarmonyOS 开发者官网

Read more

每日两道力扣,day6

每日两道力扣,day6

每日两道力扣,day6 每日两道力扣,day6 每日两道力扣,今天是: 11. 盛最多水的容器 - 力扣(LeetCode) 15. 三数之和 - 力扣(LeetCode) 第一题:盛最多水的容器 11. 盛最多水的容器 - 力扣(LeetCode) 1.思路: 在写这个题之前,咱们需要了解一个经典原理——木桶效应。 显然,在相同底面积的情况下,木桶盛水的最大值,由最短的那块板决定。这个题很明显是双指针算法的应用场景。因为这个题目给出的是一个平面切割图,咱们定义left,right左右两个指针。底面积S = right - left。高度应是min(height[left],height[right]),所以体积v就是这二者的乘积。观察题目给的示例图,当height[left] <

50天学习FPGA第41天-PCIe的的介绍及使用

50天学习FPGA第41天-PCIe的的介绍及使用

目录 简介 配置过程 简介 XDMA是一种DMA/Bridge Subsystem for PCI Express IP,由Xilinx提供。 XDMA IP核设计使用Xilinx提供的DMASubsystem for PCI Express IP是一个高性能、可配置的适用于PCIE 2.0、PCIE 3.0的SG模式DMA,提供用户可选择的AXI4接口或者AXI4-Stream接口。一般情况下配置成AXI4接口可以加入到系统总线互联,适用于大数据量异步传输,通常情况都会使用到DDR,AXI4-Stream接口适用于低延迟数据流传输。XDMA是SGDMA,并非Block DMA,SG模式下,主机会把要传输的数据组成链表的形式,然后将链表首地址通过BAR传送给XDMA,XDMA会根据链表结构首地址依次完成链表所指定的传输任务 配置过程 本文以viado17.4为例,打开blockdesin 选择DMA/Bridge Subsystem for PCI Express IP核添加后,如下图

Codex / OpenCode / Cursor / OpenClaw 对比指南

前提说明:这四个工具并不处于同一维度。Cursor 和 Codex 更接近“主开发工作台”,OpenCode 是“开源终端 Agent”,OpenClaw 则更像“把 Agent 接入聊天软件的网关”。因此在横向对比前,先明确各自定位,才不会拿错标尺。 核心定位速览 工具本质定位主要使用界面模型 / 生态策略最适合谁CodexOpenAI 原生编程 Agent / 自动化开发平台CLI 终端、本地环境、云端任务流以 OpenAI 模型体系为核心已深度使用 ChatGPT / OpenAI,希望 Agent 直接读写仓库、执行命令、跑自动化流程CursorAI 原生 IDE(编辑器中心)编辑器主界面 + 内置终端 + Diff 审查支持 OpenAI / Anthropic / Google 等多模型,切换灵活追求一体化开发体验,希望写码、

vector

vector

vector * 1 vector的介绍 * 2 vector的使用 * 2.1 vector的定义 * 2.2 vector iterator的使用 * 2.3 vector空间 * 2.4 vector增删查改 * 2.5 迭代器失效问题 1 vector的介绍 vector是C++标准模板库(STL)中最常用的序列容器之一,封装了动态数组,可以自动管理内存,提供随机访问、动态扩容等功能,可以把vector理解成一个数组。 基本特性 动态数组: 大小可变,插入/删除元素时自动调整容量 连续存储: 元素在内存中连续存放,支持高效的随机访问 类型安全: 模板类,存储特定类型的对象 内存自动管理: 自动分配和释放内存,避免手动new[]/delete[] 2 vector的使用 2.