HarmonyOS鸿蒙Next中同个Ability创建了多个子窗口,在用UIAbilityContext.setMissionLabel()时会修改所有(同个Alibity创建)后台任务标题?

HarmonyOS鸿蒙Next中同个Ability创建了多个子窗口,在用UIAbilityContext.setMissionLabel()时会修改所有(同个Alibity创建)后台任务标题? 描述:同个Ability创建了多个子1窗口,在用UIAbilityContext.setMissionLabel()时会修改所有(同个Alibity创建)任务标题,这个有什么方式解决后台任务名称问题?

问题复现项目地址

https://gitee.com/code_yu/hongmeng-test

展示效果

展示效果

关键代码

module.json5

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    // 多窗口时必要的文件
    "srcEntry": "./ets/application/AppAbility.ets",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ]
      },
      {
        "name": "WinAppAbility",
        "srcEntry": "./ets/winappability/WinAppAbility.ets",
        "description": "$string:WinAppAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:WinAppAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "launchType": "specified",
        skills: [
          {
            actions: ["WinApp"],
          },
        ]
      }
    ],
    "extensionAbilities": [
      {
        "name": "EntryBackupAbility",
        "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
        "type": "backup",
        "exported": false,
        "metadata": [
          {
            "name": "ohos.extension.backup",
            "resource": "$profile:backup_config"
          }
        ],
      }
    ]
  }
}

Index.ets 页面点击事件,创建窗体

import { common } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  @State appid: number = 0;

  build() {
    RelativeContainer() {
      Button('创建窗口')
        .id('HelloWorld')
        .fontSize($r('app.float.page_text_font_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
        .onClick(() => {
          this.appid++
          // 创建子窗口
          let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext
          //启动一个新的UIAbility
          context.startAbility({
            action: 'WinApp',
            parameters: {
              appID: `${this.appid}`
            },
          })
        })
      
      Text('你可以多创建几个窗口,然后上滑查看后台任务列表就会发现标题是一样的').margin({top: 20}).fontColor("#f00")
    }
    .height('100%')
    .width('100%')
  }
}

WinAppAbility.ets

import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';

const DOMAIN = 0x0001

export default class WebAbility extends UIAbility {
  storage: LocalStorage = new LocalStorage();

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

    if (want.parameters) {
      const appID = want.parameters.appID as string
      // 传递给页面
      this.storage.setOrCreate('appID', appID);
      // 设置后台任务名称,
      // 问题就处在这,会修改所有窗口的标题
      this.context.setMissionLabel(`${appID}`)

    }
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/WinApp', this.storage, async (err, data) => {
      if (err.code) {
        hilog.info(DOMAIN, 'WebApp', '创建应用失败: %{public}s', JSON.stringify(err));
        return;
      }
    })
  }

  onDestroy() {
  }

  onWindowStageDestroy() {

  }

  onForeground() {

  }

  onBackground() {
  }

  onNewWant() {

  }
}

WinApp.ets 页面

@Entry({ useSharedStorage: true })
@Component
struct WinApp {
  @LocalStorageProp('appID') appID: string = '';

  build() {
    RelativeContainer() {

      Text("窗口:" + this.appID)
        .fontSize(40)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}

“srcEntry”: “./ets/application/AppAbility.ets”( AbilityStage 文件)

import { AbilityStage,Want } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onCreate() {
  }

  // 多窗口时用到
  onAcceptWant(want: Want) {
    // 当打开的Ability 是 'WinAppAbility '时进行拦截
    if (want && want.abilityName === 'WinAppAbility') {
      // 业务需求: 当指定的文档窗口已打开就显示已存在的,否则新建一个窗口打开文档
      if (want.parameters) {
        return `WinAppAbility_${want.parameters.appID}`;
      }
    }
    return '';
  }
}

更多关于HarmonyOS鸿蒙Next中同个Ability创建了多个子窗口,在用UIAbilityContext.setMissionLabel()时会修改所有(同个Alibity创建)后台任务标题?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

setMissionLabel当前不支持在多实例场景设置不同ability未不同label的功能。该功能从api20开始支持

更多关于HarmonyOS鸿蒙Next中同个Ability创建了多个子窗口,在用UIAbilityContext.setMissionLabel()时会修改所有(同个Alibity创建)后台任务标题?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


你把每个子窗口设计为独立的UIAbility实例,通过启动不同UIAbility实现独立任务标签控制呢?

module.json5中为每个子窗口定义独立的UIAbility,并配置支持分屏:

"abilities": [
  {
    "name": "EntryAbility1",
    "supportWindowMode": ["split"],
    // 其他配置...
  },
  {
    "name": "EntryAbility2",
    "supportWindowMode": ["split"],
    // 其他配置...
  }
]

通过startAbility启动不同UIAbility实例,并在各自的onCreate生命周期中设置独立任务标签:

// 主Ability中启动子窗口
let want1: Want = { 
  bundleName: 'com.example.demo',
  abilityName: 'EntryAbility1',
  moduleName: ''
};
let option: StartOptions = { 
  windowMode: AbilityConstant.WindowMode.WINDOW_MODE_SPLIT_PRIMARY 
};
context.startAbility(want1, option);

// 在EntryAbility1的onCreate中设置标签
import { UIAbility } from '@kit.AbilityKit';
export default class EntryAbility1 extends UIAbility {
  onCreate() {
    this.context.setMissionLabel('窗口1');
  }
}

请检查一下 UIAbilitye的启动模式是否是 specified启动模式

假设应用有两个UIAbility实例,即EntryAbility和SpecifiedAbility。EntryAbility以specified模式启动SpecifiedAbility。基本原理如下:

  1. EntryAbility调用startAbility()方法,并在Want的parameters字段中设置唯一的Key值,用于标识SpecifiedAbility。
  2. 系统在拉起SpecifiedAbility之前,会先进入对应的AbilityStageonAcceptWant()生命周期回调,获取用于标识目标UIAbility的Key值。
  3. 系统会根据获取的Key值来匹配UIAbility。
    • 如果匹配到对应的UIAbility,则会启动该UIAbility实例,并进入onNewWant()生命周期回调。
    • 如果无法匹配对应的UIAbility,则会创建一个新的UIAbility实例,并进入该UIAbility实例的onCreate()生命周期回调和onWindowStageCreate()生命周期回调。

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

我用的就是specified启动模式.

{
        "name": "WebAbility",
        "srcEntry": "./ets/webabilit/WebAbilit.ets",
        "description": "$string:WebAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:WebAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "launchType": "specified",
        skills: [
          {
            actions: ["WebApp"],
          },
        ]
      }
export default class MyAbilityStage extends AbilityStage {
  onCreate() {
  }

  // 多窗口时用到
  onAcceptWant(want: Want) {
    // 当打开的Ability 是 'WebAbility'时进行拦截
    if (want && want.abilityName === 'WebAbility') {
      // 业务需求: 当指定的文档窗口已打开就显示已存在的,否则新建一个窗口打开文档
      if (want.parameters) {
        return `WebAppAbility_${want.parameters.appID}`;
      }
    }
    return '';
  }
}

我现在的流程就是你说的这样, 实例都没有任何问题,问题是后台任务名称使一样的,比如创建了三个子窗口,三个子窗口的后台窗口任务名称会变为一样,

我创建了一个简单的项目, 可以复现该问题, https://gitee.com/code_yu/hongmeng-test ,前辈帮忙看看,感谢,

WEB开发不太清楚,但是arkts有getuicontext可以获取当前页面对应的uiability实例,

在HarmonyOS Next中,同个Ability创建的多个子窗口共享同一个任务栈。使用UIAbilityContext.setMissionLabel()设置的是整个Ability任务栈的标签,因此会同时修改所有子窗口的后台任务标题。这是系统任务管理的默认行为,无法单独为子窗口设置独立的后台任务标题。

在HarmonyOS Next中,UIAbilityContext.setMissionLabel() 方法设置的是当前Ability实例对应的任务(Mission)标签。当同一个Ability(例如 WinAppAbility)通过 onAcceptWant 返回不同的实例名称(如 WinAppAbility_1WinAppAbility_2)来创建多个窗口时,这些窗口本质上属于同一个Ability的不同实例,但它们共享同一个 UIAbilityContext

问题根源setMissionLabel 是通过 this.context(即 UIAbilityContext)调用的。在当前的架构设计下,同一个Ability的多个实例共享的上下文在设置任务标签时,可能会作用于该Ability相关的所有任务实例,导致所有窗口的后台任务标题被同步修改。这是系统层面对Ability实例与任务管理的一种当前行为。

解决方案: 要解决每个子窗口在后台任务列表中显示独立标题的需求,目前的标准做法是 为每个需要独立标题的窗口使用独立的Ability。这是HarmonyOS多窗口和任务管理的推荐设计模式。

具体调整方案

  1. 重构Ability设计:不要依赖同一个 WinAppAbility 通过不同参数创建多实例。应为每个需要独立任务标签的窗口配置独立的Ability。
  2. 定义多个Ability:在 module.json5 文件的 abilities 数组中,声明多个Ability。它们可以共享同一个 srcEntry(指向同一个Ability类文件),但必须拥有不同的 namelabel
  3. 独立启动:在 Index.ets 的点击事件中,根据需求启动不同的Ability(例如通过不同的 actionentity),而不是通过参数启动同一个Ability。
  4. 设置默认标签:每个独立Ability可以在其 module.json5label 字段设置不同的默认任务标签,也可以在运行时根据需要在各自的Ability实例中调用 setMissionLabel

修改示例概要

  • module.json5 中声明多个Ability:
    {
      "abilities": [
        {
          "name": "WinAppAbility1",
          "label": "窗口1", // 默认任务标签
          "srcEntry": "./ets/winappability/WinAppAbility.ets",
          "skills": [{"actions": ["action.win.app1"]}]
          // ...
        },
        {
          "name": "WinAppAbility2",
          "label": "窗口2",
          "srcEntry": "./ets/winappability/WinAppAbility.ets",
          "skills": [{"actions": ["action.win.app2"]}]
          // ...
        }
      ]
    }
    
  • 启动时指定对应的Ability:
    context.startAbility({
      action: 'action.win.app1', // 或 'action.win.app2'
      // ...
    })
    

总结: 在当前HarmonyOS Next的架构下,要实现多窗口在后台任务列表中拥有独立标题,最直接有效的方式是为每个窗口使用独立的Ability定义,而不是依赖同一个Ability的多个实例。这种方式符合系统任务管理模型,能确保每个任务标签独立可控。

回到顶部