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

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
= Qt for HarmonyOS 应用接续开发指南 =
__TOC__


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


QtOhosExtras 模块已封装 HarmonyOS 的 onContinue / onNewWant 等流程,开发者仅需使用 Qt 接口完成迁移请求、数据封装与目标端恢复。


----


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


== 工作流程 ==
== 工作流程 ==
 
# 源端收到迁移请求(<code>continueRequestReceived</code>) → 序列化业务状态 → 同意/拒绝 → 按需决定源端是否退出。
# 源端收到迁移请求(<code>continueRequestReceived</code>)
# 目标端通过启动或 <code>newWantInfoReceived</code> 收到 Want → 用 <code>tryGetOnContinueData()</code> 恢复状态。
#* 序列化业务状态(<100KB)
# '''可选''':配置 ContinueQuickStart 预热;动态开关迁移能力;控制源端保留/退出。
#* 同意 / 拒绝 / 版本不匹配响应
#* 按需决定源端是否退出
# 目标端收到 Want(冷启动或热启动)
#* 使用 <code>tryGetOnContinueData()</code> 提取迁移数据
#* 反序列化并恢复 UI 状态
# 可选能力
#* 配置 ContinueQuickStart 快速预热
#* 动态开关迁移能力
#* 控制源端保留 / 退出策略
 
----


== 核心 API 速览 ==
== 核心 API 速览 ==
{| class="wikitable"
{| class="wikitable"
! API / 信号 !! 说明
! API !! 说明
|-
|-
| <code>QOhosAbilityContext::continueRequestReceived</code> || 源端接收迁移请求的信号
| <code>QOhosAbilityContext::continueRequestReceived</code> || 源端迁移请求信号
|-
|-
| <code>QOhosOnContinueContext</code> || 同意/拒绝/版本不匹配响应;设置源端退出策略
| <code>QOhosOnContinueContext</code> || 提供同意/拒绝/版本不匹配响应,设置源端是否退出
|-
|-
| <code>QOhosAbilityContext::newWantInfoReceived</code> || 目标端运行时接收新 Want 的信号
| <code>QOhosAbilityContext::newWantInfoReceived</code> || 目标端接收新 Want 信号(热启动)
|-
|-
| <code>QOhosWantInfo::launchReason()</code> || 启动原因:StartAbility / PrepareContinuation / Continuation
| <code>QOhosWantInfo::launchReason()</code> || 获取启动原因:<code>StartAbility</code> / <code>PrepareContinuation</code> / <code>Continuation</code>
|-
|-
| <code>QtOhosExtras::tryGetOnContinueData(const QOhosWant &want)</code> || 提取迁移数据(返回 <code>QSharedPointer&lt;QByteArray&gt;</code>)
| <code>QtOhosExtras::tryGetOnContinueData(const QOhosWant &want)</code> || 提取迁移数据(返回 <code>QSharedPointer<QByteArray></code>)
|-
|-
| <code>QOhosAbilityContext::setContinuationActive(bool)</code> || 动态开关迁移能力
| <code>QOhosAbilityContext::setContinuationActive(bool)</code> || 动态开关迁移能力
|-
|-
| <code>QOhosOnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool)</code> || 控制源端迁移成功后是否退出
| <code>QOhosOnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool)</code> || 控制源端是否在成功迁移后退出
|}
|}
----


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


=== 实现步骤 ===
'''示例(同意迁移,保留源端):'''
# 监听迁移请求:<code>continueRequestReceived</code>
<source lang="cpp">
# 校验版本/业务条件:<code>ctx-&gt;sourceApplicationVersionCode()</code>
# 序列化状态(<100KB)并响应:
#* 同意:<code>setAgreeResponse(serialized)</code>
#* 版本不匹配:<code>setMismatchResponse()</code>
#* 拒绝:<code>setRejectResponse()</code>
# 是否保留源端:
#* <code>setExitAppOnSourceDeviceAfterMigration(false)</code>(默认 true)
# 按需开/关迁移:
#* <code>setContinuationActive(bool)</code>
 
=== 示例:同意迁移并保留源端 ===
<syntaxhighlight lang="cpp">
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
QObject::connect(ability.get(), &QOhosUiAbilityContext::continueRequestReceived,
QObject::connect(ability.get(), &QOhosUiAbilityContext::continueRequestReceived,
Line 92: Line 56:
             QByteArray payload = /* serialize state (<100KB) */;
             QByteArray payload = /* serialize state (<100KB) */;
             ctx->setAgreeResponse(payload);
             ctx->setAgreeResponse(payload);
             ctx->setExitAppOnSourceDeviceAfterMigration(false); // keep source
             ctx->setExitAppOnSourceDeviceAfterMigration(false); // 需要保留源端
         } else {
         } else {
             ctx->setMismatchResponse();
             ctx->setMismatchResponse();
         }
         }
     });
     });
</syntaxhighlight>
</source>
 
'''参考:''' <code>examples/qtohosextras/applicationcontinuation/main.cpp</code>
 
----


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


=== 实现步骤 ===
'''示例(处理冷启动与热启动):'''
# 冷启动获取:
<source lang="cpp">
#* <code>auto wantInfo = QOhosAppContext::getAppLaunchWantInfo();</code>
// 1. 冷启动处理
# 运行时获取:
#* 监听 <code>QOhosAbilityContext::newWantInfoReceived</code>
# 场景区分:
#* <code>launchReason()</code> == <code>PrepareContinuation</code>(预热)
#* <code>launchReason()</code> == <code>Continuation</code>(正式迁移数据)
# 提取数据:
#* <code>auto data = QtOhosExtras::tryGetOnContinueData(wantInfo-&gt;want());</code>
# 恢复状态:
#* 反序列化 <code>data</code>,还原业务状态并刷新 UI
 
=== 示例:冷启动 + 热启动恢复 ===
<syntaxhighlight lang="cpp">
// Cold start
if (auto launchInfo = QOhosAppContext::getAppLaunchWantInfo()) {
if (auto launchInfo = QOhosAppContext::getAppLaunchWantInfo()) {
     auto data = QtOhosExtras::tryGetOnContinueData(launchInfo->want());
     auto data = QtOhosExtras::tryGetOnContinueData(launchInfo->want());
     if (data) { /* deserialize and restore */ }
     if (data) { /* 反序列化并恢复状态 */ }
}
}


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


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


=== 适用场景 ===
'''示例(区分预热与正式数据):'''
希望目标端先拉起/预热,数据到达后再恢复业务状态。
<source lang="cpp">
 
=== 配置方式 ===
在 <code>module.json5</code> 中,将目标 Ability 的 <code>continueType</code> 末尾添加:
* <code>_ContinueQuickStart</code>
 
=== 流程说明 ===
* 首先触发 <code>PrepareContinuation</code>(预热)
* 随后触发 <code>Continuation</code>(正式数据)
 
=== 示例:区分预热/正式 ===
<syntaxhighlight lang="cpp">
QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
QObject::connect(ability.get(), &QOhosUiAbilityContext::newWantInfoReceived,
     [](const QSharedPointer<QOhosWantInfo> &info) {
     [](const QSharedPointer<QOhosWantInfo> &info) {
         switch (info->launchReason()) {
         switch (info->launchReason()) {
         case QOhosWantInfo::LaunchReason::PrepareContinuation:
         case QOhosWantInfo::LaunchReason::PrepareContinuation:
             // Warm-up / placeholder
             // 执行轻量级初始化或显示加载占位图
             break;
             break;
         case QOhosWantInfo::LaunchReason::Continuation: {
         case QOhosWantInfo::LaunchReason::Continuation:
             auto data = QtOhosExtras::tryGetOnContinueData(info->want());
             auto data = QtOhosExtras::tryGetOnContinueData(info->want());
             if (data) { /* deserialize and restore */ }
             if (data) { /* 恢复完整业务状态 */ }
             break;
             break;
        }
         default:
         default:
             break;
             break;
         }
         }
     });
     });
</syntaxhighlight>
</source>
 
----
 
== 动态开关迁移 ==
 
=== 适用场景 ===
特定页面不允许迁移时关闭,需要迁移前再开启。
 
=== 接口 ===
<code>QOhosAbilityContext::setContinuationActive(bool)</code>(默认开启)
 
=== 示例 ===
<syntaxhighlight lang="cpp">
auto ability = QOhosAbilityContext::getInstanceForMainWindow(window.windowHandle());
ability->setContinuationActive(false); // disable
ability->setContinuationActive(true);  // enable when needed
</syntaxhighlight>
 
----
 
== 源端退出策略 ==
 
=== 说明 ===
默认情况下,迁移成功后系统会关闭源端;调试或需要保留源端时可将其设置为 false。
 
=== 接口 ===
<code>QOhosOnContinueContext::setExitAppOnSourceDeviceAfterMigration(bool)</code>
 
=== 示例:同意迁移但保留源端 ===
<syntaxhighlight lang="cpp">
QObject::connect(ability.get(), &QOhosUiAbilityContext::continueRequestReceived,
    [](auto ctx) {
        auto appVersion = QOhosAppContext::instance()->getBundleInfo()->versionCode();
        if (ctx->sourceApplicationVersionCode() == appVersion) {
            ctx->setAgreeResponse(QByteArray("Migration Test Data"));
            ctx->setExitAppOnSourceDeviceAfterMigration(false);
        } else {
            ctx->setMismatchResponse();
        }
    });
</syntaxhighlight>
 
----
 
== 快速上手清单 ==
 
# 源端:监听 <code>continueRequestReceived</code>,序列化数据 <100KB,调用 <code>setAgreeResponse</code> 或 mismatch/reject;按需设置退出策略与迁移开关。
# 目标端:通过 <code>launchReason()</code> 判定预热/正式;使用 <code>tryGetOnContinueData</code> 提取并恢复状态。
# 需要预热:配置 <code>continueType</code> 为 <code>_ContinueQuickStart</code>,在 <code>PrepareContinuation</code> 只做轻量处理。
 
----
 
== 参考路径 ==
 
* 示例:<code>qtohosextras/examples/qtohosextras/applicationcontinuation/main.cpp</code>
* 实现:<code>qtohosextras/src/ohosextras/qohosabilitycontext.cpp/.h</code>
* Want 定义:<code>qtohosextras/src/ohosextras/qohoswant.h</code>
 
----


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


* 未响应迁移请求默认视为拒绝,请在回调中明确处理。
== 参考资源 ==
* 回调在 Qt 线程执行,避免跨线程操作 UI。
* '''示例代码''':<code>qtohosextras/examples/qtohosextras/applicationcontinuation/main.cpp</code>
* 迁移数据需向前兼容,协议变更时携带版本并做好容错。
* '''源码实现''':<code>qtohosextras/src/ohosextras/qohosabilitycontext.cpp</code>
* Qt 暂未支持大于 100KB 数据的接续,将在未来版本中提供。
* '''外部链接''':[https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-continuation HarmonyOS 应用接续官方指南]
* 更多说明参考:HarmonyOS 应用接续官方指南(外部链接)

Revision as of 07:08, 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 应用接续官方指南