Qt for HarmonyOS/user development/application continuation guild zh: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Created page with "== 简介 == HarmonyOS 平台支持多进程架构,Qt 通过 '''startNoUiChildProcess''' API 为开发者提供了创建无 UI 子进程并传递启动参数的能力。本指南将详细说明该功能的使用方法、部署步骤,并提供完整的代码示例。 == 功能架构概述 == 在 HarmonyOS 中使用 Qt 子进程功能时,可以参考以下架构原则: * '''主应用进程''' ** 负责 UI 交互和用户界面 ** 通过 QtOhosExtras 模块调...")
 
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
__TOC__
== 简介 ==
== 简介 ==
本文面向 Qt 开发者,介绍如何在 HarmonyOS 上实现“应用接续”(跨设备迁移应用状态)。QtOhosExtras 模块已封装鸿蒙 '''onContinue/onNewWant''' 等流程,开发者仅需使用 Qt 接口完成迁移请求、数据封装与目标端恢复。


HarmonyOS 平台支持多进程架构,Qt 通过 '''startNoUiChildProcess''' API 为开发者提供了创建无 UI 子进程并传递启动参数的能力。本指南将详细说明该功能的使用方法、部署步骤,并提供完整的代码示例。
== 能力与模块 ==
 
* '''能力''':在设备间迁移当前应用状态,支持快速预热(ContinueQuickStart)与源端保留/退出。
== 功能架构概述 ==
* '''模块''':qtohosextras
 
** '''核心类''':QOhosAbilityContext、QOhosOnContinueContext、QOhosWantInfo
在 HarmonyOS 中使用 Qt 子进程功能时,可以参考以下架构原则:
** '''工具函数''':QtOhosExtras::tryGetOnContinueData
 
* '''数据通道''':<100KB 通过 Want parameters 携带(Base64 的 QByteArray,键名 __io_qt_on_continue_migration_data);传输更多数据的功能 Qt 暂未实现,将会在后续版本提供。
* '''主应用进程'''
** 负责 UI 交互和用户界面
** 通过 QtOhosExtras 模块调用子进程 API
** 传递启动参数给子进程
* '''子进程(无 UI)'''
** 接收主进程传递的启动参数
** 执行后台任务和数据处理
** 独立运行,不依赖主进程 UI
 
=== 核心特性 ===
 
Qt for HarmonyOS 的子进程功能具有以下特点:
 
# '''多参数传递支持''':应用可以自定义传递多个启动参数,参数类型为基础类型。
# '''差异化启动能力''':支持启动不同的子进程时传递不同的启动参数。
# '''无 UI 后台处理''':子进程专门用于后台处理任务,不占用 UI 资源。
# '''参数自动转发''':启动参数会自动转发到子进程的 <code>main()</code> 函数。
 
== API 详解 ==
 
=== startNoUiChildProcess 函数 ===
 
该函数是 Qt for HarmonyOS 提供的核心子进程启动 API:
 
<source lang="cpp">
static void QtOhosExtras::QOhosAppContext::startNoUiChildProcess(
    QString libraryName,
    QStringList args
);
</source>


==== 参数详解 ====
== 工作流程 ==
# 源端收到迁移请求(continueRequestReceived) → 序列化业务状态 → 同意/拒绝 → 按需决定源端是否退出。
# 目标端通过启动或 newWantInfoReceived 收到 Want → 用 tryGetOnContinueData() 恢复状态。
# '''可选''':配置 ContinueQuickStart 预热;动态开关迁移能力;控制源端保留/退出。


== 核心 API 速览 ==
{| class="wikitable"
{| class="wikitable"
! 参数 !! 类型 !! 说明
! API !! 说明
|-
| QOhosAbilityContext::continueRequestReceived || 源端迁移请求信号
|-
| QOhosOnContinueContext || 提供同意/拒绝/版本不匹配响应,设置源端是否退出
|-
|-
| <code>libraryName</code> || QString || 子进程的动态库名称(如 <code>"libChildApp.so"</code>)
| QOhosAbilityContext::newWantInfoReceived || 目标端接收新 Want 信号(热启动)
|-
|-
| <code>args</code> || QStringList || 要传递给子进程的参数列表
| QOhosWantInfo::launchReason()|| 获取启动原因:StartAbility / PrepareContinuation / Continuation
|-
| QtOhosExtras::tryGetOnContinueData(const QOhosWant &want) || 提取迁移数据(返回 QSharedPointer<QByteArray>
|-
| QOhosAbilityContext::setContinuationActive(bool) || 动态开关迁移能力
|-
| QOhosOnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool) || 控制源端是否在成功迁移后退出
|}
|}


==== 功能机制 ====
== 源端实现(发起迁移) ==
 
# '''监听迁移请求''':连接 continueRequestReceived 信号。
该函数基于 HarmonyOS 的 [https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-app-ability-childprocessmanager-V5 Child Process Manager API] 实现,具有以下特点:
# '''校验版本/业务条件''':检查 ctx->sourceApplicationVersionCode()
 
# '''序列化状态并响应'''
# '''异步启动''':子进程启动为异步操作,不会阻塞主进程。
#* 同意:setAgreeResponse(serialized) (数据需 &lt;100KB)。
# '''参数转发''':传递的参数会被转发到子进程的 <code>main()</code> 函数中作为命令行参数。
#* 版本不匹配:setMismatchResponse()。
# '''进程隔离''':子进程独立运行,与主进程内存空间隔离。
#* 拒绝:setRejectResponse()。
# '''生命周期管理''':子进程需要自行管理生命周期。
# '''是否保留源端''':调用 setExitAppOnSourceDeviceAfterMigration(false)(默认值为 true,即退出)。
 
# '''动态开关''':根据业务逻辑调用 setContinuationActive(bool)。
== 手动开发步骤 ==
 
=== 1. 准备工作 ===
 
首先,确保您有:
* Qt for HarmonyOS 开发环境
* HarmonyOS 应用工程目录
* 对多进程架构的基本理解
 
=== 2. 创建项目结构 ===
 
典型的子进程应用需要包含主应用和子进程两部分,建议按以下结构组织:
 
<pre>
YourProject/
├── MainApp/                # 主应用(负责UI交互)
│  ├── main.cpp
│  ├── mainwindow.cpp
│  ├── mainwindow.h
│  ├── mainwindow.ui
│  └── MainApp.pro
└── BackgroundTask/        # 子进程应用(后台任务处理)
    ├── main.cpp
    └── BackgroundTask.pro
</pre>


=== 3. 子进程实现详解 ===
'''示例(同意迁移,保留源端):'''
 
==== 基础子进程框架 ====
 
子进程的核心任务是接收和处理主进程传递的启动参数。以下是一个完整的子进程实现:
 
'''BackgroundTask/main.cpp:'''
<source lang="cpp">
<source lang="cpp">
#include <QCoreApplication>
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
#include <QDebug>
QObject::connect(ability.get(), &QOhosUiAbilityContext::continueRequestReceived,
 
     [](auto ctx) {
int main(int argc, char *argv[])
         auto appVersion = QOhosAppContext::instance()->getBundleInfo()->versionCode();
{
         if (ctx->sourceApplicationVersionCode() == appVersion) {
    QCoreApplication app(argc, argv);
             QByteArray payload = /* serialize state (<100KB) */;
 
            ctx->setAgreeResponse(payload);
    qDebug() << "Child process started";
             ctx->setExitAppOnSourceDeviceAfterMigration(false); // 需要保留源端
    qDebug() << "Total arguments:" << argc;
         } else {
 
             ctx->setMismatchResponse();
     // 处理传递的参数
    for (int i = 0; i < argc; ++i) {
        qDebug() << "Argument" << i << ":" << argv[i];
    }
 
    // 根据参数执行不同的业务逻辑
    if (argc > 1) {
         QString command = QString::fromLocal8Bit(argv[1]);
         if (command == "task1") {
             qDebug() << "Executing task 1";
             // 执行任务1的逻辑
         } else if (command == "task2") {
             qDebug() << "Executing task 2";
            // 执行任务2的逻辑
         }
         }
     }
     });
 
    return app.exec();
}
</source>
</source>


=== 4. 主应用实现详解 ===
== 目标端实现(接收与恢复) ==
 
# '''冷启动获取''':<code>auto wantInfo = QOhosAppContext::getAppLaunchWantInfo();</code>
==== A. 界面头文件定义 ====
# '''运行时获取''':监听 '''QOhosAbilityContext::newWantInfoReceived''' 信号。
# '''场景区分''':检查 launchReason() 是否为 Continuation。
# '''提取数据''':使用 QtOhosExtras::tryGetOnContinueData。
# '''恢复 UI''':反序列化数据还原业务状态。


'''MainApp/mainwindow.h:'''
'''示例(处理冷启动与热启动):'''
<source lang="cpp">
<source lang="cpp">
#ifndef MAINWINDOW_H
// 1. 冷启动处理
#define MAINWINDOW_H
if (auto launchInfo = QOhosAppContext::getAppLaunchWantInfo()) {
    auto data = QtOhosExtras::tryGetOnContinueData(launchInfo->want());
    if (data) { /* 反序列化并恢复状态 */ }
}


#include <QMainWindow>
// 2. 热启动处理(应用已在后台运行)
 
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
QT_BEGIN_NAMESPACE
QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
namespace Ui { class MainWindow; }
     [](const QSharedPointer<QOhosWantInfo> &info) {
QT_END_NAMESPACE
        if (info->launchReason() == QOhosWantInfo::LaunchReason::Continuation) {
 
            auto data = QtOhosExtras::tryGetOnContinueData(info->want());
class MainWindow : public QMainWindow
            if (data) { /* 反序列化并恢复状态 */ }
{
        }
    Q_OBJECT
    });
 
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
 
private slots:
     void startChildProcess1();
    void startChildProcess2();
 
private:
    Ui::MainWindow *ui;
};
 
#endif // MAINWINDOW_H
</source>
</source>


==== B. 核心功能实现 ====
== 快速预热(ContinueQuickStart) ==
* '''适用场景''':希望目标端先拉起界面占位,待数据传输完成后再刷新内容。
* '''配置''':在 module.json5 目标 Ability 的 continueType字段末尾添加 _ContinueQuickStart。
* '''流程''':系统先触发 PrepareContinuation(预热),随后触发 Continuation(携带数据)。


'''MainApp/mainwindow.cpp:'''
'''示例(区分预热与正式数据):'''
<source lang="cpp">
<source lang="cpp">
#include "mainwindow.h"
QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
#include "ui_mainwindow.h"
     [](const QSharedPointer<QOhosWantInfo> &info) {
#include <QtOhosExtras/QtOhosExtras>
        switch (info->launchReason()) {
#include <QStringList>
        case QOhosWantInfo::LaunchReason::PrepareContinuation:
 
             // 执行轻量级初始化或显示加载占位图
MainWindow::MainWindow(QWidget *parent)
             break;
    : QMainWindow(parent)
        case QOhosWantInfo::LaunchReason::Continuation:
     , ui(new Ui::MainWindow)
             auto data = QtOhosExtras::tryGetOnContinueData(info->want());
{
            if (data) { /* 恢复完整业务状态 */ }
    ui->setupUi(this);
            break;
}
         default:
 
             break;
MainWindow::~MainWindow()
         }
{
     });
    delete ui;
}
 
void MainWindow::startChildProcess1()
{
    // 启动子进程并传递参数
    QtOhosExtras::QOhosAppContext::startNoUiChildProcess(
        "libBackgroundTask.so",
        QStringList{
             "task1",          // 任务类型
             "param1",          // 参数1
            "param2",          // 参数2
             "priority_high"    // 优先级
        });
 
    ui->statusLabel->setText("Child Process 1 Started!");
}
 
void MainWindow::startChildProcess2()
{
    // 启动另一个子进程实例,传递不同参数
    QtOhosExtras::QOhosAppContext::startNoUiChildProcess(
         "libBackgroundTask.so",
        QStringList{
             "task2",          // 不同的任务类型
            "config.json",    // 配置文件
            "debug_mode"      // 调试模式
         });
 
     ui->statusLabel->setText("Child Process 2 Started!");
}
</source>
 
==== C. 主应用项目配置 ====
 
'''MainApp/MainApp.pro:'''
<source lang="pro">
QT += core gui widgets ohosextras
 
SOURCES += \
    main.cpp \
    mainwindow.cpp
 
HEADERS += \
    mainwindow.h
 
FORMS += \
    mainwindow.ui
</source>
 
== 手动编译和部署 ==
 
=== 1. 编译子进程动态库 ===
 
<source lang="bash">
# 进入子进程目录
cd BackgroundTask
 
# 生成 Makefile
qmake BackgroundTask.pro
 
# 编译生成 .so 文件
make
 
# 验证生成的文件
ls -la libBackgroundTask.so
</source>
 
=== 2. 手动部署动态库文件 ===
 
在 HarmonyOS 中部署子进程动态库时,需要遵循特定的目录结构:
 
<source lang="bash">
# 创建目标目录(如果不存在)
mkdir -p entry/libs/arm64-v8a
 
# 复制动态库到指定位置
cp BackgroundTask/libBackgroundTask.so entry/libs/arm64-v8a/
 
# 验证部署
ls -la entry/libs/arm64-v8a/libBackgroundTask.so
</source>
 
=== 3. 编译主应用 ===
 
<source lang="bash">
# 编译主应用
cd MainApp
qmake MainApp.pro
make
</source>
</source>


=== 完整部署检查清单 ===
== 注意事项 ==
 
* '''显式响应''':未响应迁移请求默认视为拒绝,务必在回调中明确处理。
<pre>
* '''线程安全''':回调在 Qt 主线程执行,但仍需注意避免耗时的同步操作阻塞 UI。
ohostemplateforqtapplication/
* '''数据限制''':目前仅支持 &lt;100KB 数据。若超出此限制,迁移可能会失败。
├── entry/
* '''向前兼容''':迁移数据建议携带版本号,以便目标端处理来自旧版本源端的接续数据。
│  └── libs/
│      └── arm64-v8a/
│          ├── libBackgroundTask.so  # 子进程动态库
│          └── ... # 其他Qt相关库文件
├── MainApp/
└── BackgroundTask/
</pre>
 
== 测试验证方法 ==
 
=== 1. 功能测试 ===
 
# '''启动主应用''':运行编译好的主应用程序。
# '''触发子进程''':点击界面上的启动按钮。
# '''观察状态反馈''':检查应用界面的状态提示信息。
 
=== 2. 进程状态验证 ===
 
通过以下方式确认进程创建成功:
 
==== 任务管理器检查 ====
在设备的任务管理器中应该能看到:
* '''主进程''':<code>com.yourpackage.name</code>
* '''子进程''':<code>com.yourpackage.name:QChildProcess0</code>
 
=== 完整测试案例 ===
 
以下是基于 <code>testUiLessProcess</code> 参考示例的完整测试流程:
 
# 编译子进程
#: <source lang="bash">cd testUiLessProcess/TestConsoleApp && qmake TestConsoleApp.pro && make</source>
# 部署动态库
#: <source lang="bash">cp libTestConsoleApp.so ../ohostemplateforqtapplication/entry/libs/arm64-v8a/</source>
# 编译运行主应用
#: <source lang="bash">cd ../mainWindowApp && qmake mainWindowApp.pro && make && ./mainWindowApp</source>
# 执行测试操作
#* 点击 "Start Child Process" 按钮。
#* 观察到 "Start UI less Child Process Successfully!" 提示。
# 验证结果
#* 任务管理器查看进程。
 
== 相关资源 ==


=== 官方文档 ===
== 参考资源 ==
* [https://developer.huawei.com/consumer/en/doc/harmonyos-references-V5/js-apis-app-ability-childprocessmanager-V5 HarmonyOS Child Process Manager API] - 底层 API 参考
* '''示例代码''':qtohosextras/examples/qtohosextras/applicationcontinuation/main.cpp
* '''源码实现''':qtohosextras/src/ohosextras/qohosabilitycontext.cpp
* '''外部链接''':[https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-continuation HarmonyOS 应用接续官方指南]

Latest revision as of 07:14, 25 December 2025

简介

本文面向 Qt 开发者,介绍如何在 HarmonyOS 上实现“应用接续”(跨设备迁移应用状态)。QtOhosExtras 模块已封装鸿蒙 onContinue/onNewWant 等流程,开发者仅需使用 Qt 接口完成迁移请求、数据封装与目标端恢复。

能力与模块

  • 能力:在设备间迁移当前应用状态,支持快速预热(ContinueQuickStart)与源端保留/退出。
  • 模块:qtohosextras
    • 核心类:QOhosAbilityContext、QOhosOnContinueContext、QOhosWantInfo
    • 工具函数:QtOhosExtras::tryGetOnContinueData
  • 数据通道:<100KB 通过 Want parameters 携带(Base64 的 QByteArray,键名 __io_qt_on_continue_migration_data);传输更多数据的功能 Qt 暂未实现,将会在后续版本提供。

工作流程

  1. 源端收到迁移请求(continueRequestReceived) → 序列化业务状态 → 同意/拒绝 → 按需决定源端是否退出。
  2. 目标端通过启动或 newWantInfoReceived 收到 Want → 用 tryGetOnContinueData() 恢复状态。
  3. 可选:配置 ContinueQuickStart 预热;动态开关迁移能力;控制源端保留/退出。

核心 API 速览

API 说明
QOhosAbilityContext::continueRequestReceived 源端迁移请求信号
QOhosOnContinueContext 提供同意/拒绝/版本不匹配响应,设置源端是否退出
QOhosAbilityContext::newWantInfoReceived 目标端接收新 Want 信号(热启动)
QOhosWantInfo::launchReason() 获取启动原因:StartAbility / PrepareContinuation / Continuation
QtOhosExtras::tryGetOnContinueData(const QOhosWant &want) 提取迁移数据(返回 QSharedPointer<QByteArray>)
QOhosAbilityContext::setContinuationActive(bool) 动态开关迁移能力
QOhosOnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool) 控制源端是否在成功迁移后退出

源端实现(发起迁移)

  1. 监听迁移请求:连接 continueRequestReceived 信号。
  2. 校验版本/业务条件:检查 ctx->sourceApplicationVersionCode()。
  3. 序列化状态并响应
    • 同意:setAgreeResponse(serialized) (数据需 <100KB)。
    • 版本不匹配:setMismatchResponse()。
    • 拒绝:setRejectResponse()。
  4. 是否保留源端:调用 setExitAppOnSourceDeviceAfterMigration(false)(默认值为 true,即退出)。
  5. 动态开关:根据业务逻辑调用 setContinuationActive(bool)。

示例(同意迁移,保留源端):

auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
QObject::connect(ability.get(), &QOhosUiAbilityContext::continueRequestReceived,
    [](auto ctx) {
        auto appVersion = QOhosAppContext::instance()->getBundleInfo()->versionCode();
        if (ctx->sourceApplicationVersionCode() == appVersion) {
            QByteArray payload = /* serialize state (<100KB) */;
            ctx->setAgreeResponse(payload);
            ctx->setExitAppOnSourceDeviceAfterMigration(false); // 需要保留源端
        } else {
            ctx->setMismatchResponse();
        }
    });

目标端实现(接收与恢复)

  1. 冷启动获取
    auto wantInfo = QOhosAppContext::getAppLaunchWantInfo();
    
  2. 运行时获取:监听 QOhosAbilityContext::newWantInfoReceived 信号。
  3. 场景区分:检查 launchReason() 是否为 Continuation。
  4. 提取数据:使用 QtOhosExtras::tryGetOnContinueData。
  5. 恢复 UI:反序列化数据还原业务状态。

示例(处理冷启动与热启动):

// 1. 冷启动处理
if (auto launchInfo = QOhosAppContext::getAppLaunchWantInfo()) {
    auto data = QtOhosExtras::tryGetOnContinueData(launchInfo->want());
    if (data) { /* 反序列化并恢复状态 */ }
}

// 2. 热启动处理(应用已在后台运行)
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
    [](const QSharedPointer<QOhosWantInfo> &info) {
        if (info->launchReason() == QOhosWantInfo::LaunchReason::Continuation) {
            auto data = QtOhosExtras::tryGetOnContinueData(info->want());
            if (data) { /* 反序列化并恢复状态 */ }
        }
    });

快速预热(ContinueQuickStart)

  • 适用场景:希望目标端先拉起界面占位,待数据传输完成后再刷新内容。
  • 配置:在 module.json5 目标 Ability 的 continueType字段末尾添加 _ContinueQuickStart。
  • 流程:系统先触发 PrepareContinuation(预热),随后触发 Continuation(携带数据)。

示例(区分预热与正式数据):

QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
    [](const QSharedPointer<QOhosWantInfo> &info) {
        switch (info->launchReason()) {
        case QOhosWantInfo::LaunchReason::PrepareContinuation:
            // 执行轻量级初始化或显示加载占位图
            break;
        case QOhosWantInfo::LaunchReason::Continuation:
            auto data = QtOhosExtras::tryGetOnContinueData(info->want());
            if (data) { /* 恢复完整业务状态 */ }
            break;
        default:
            break;
        }
    });

注意事项

  • 显式响应:未响应迁移请求默认视为拒绝,务必在回调中明确处理。
  • 线程安全:回调在 Qt 主线程执行,但仍需注意避免耗时的同步操作阻塞 UI。
  • 数据限制:目前仅支持 <100KB 数据。若超出此限制,迁移可能会失败。
  • 向前兼容:迁移数据建议携带版本号,以便目标端处理来自旧版本源端的接续数据。

参考资源

  • 示例代码:qtohosextras/examples/qtohosextras/applicationcontinuation/main.cpp
  • 源码实现:qtohosextras/src/ohosextras/qohosabilitycontext.cpp
  • 外部链接HarmonyOS 应用接续官方指南