HarmonyOS 应用开发之UIAbility组件间交互(设备内)

news2024/10/10 2:19:15

UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时,会涉及到启动特定的UIAbility,该UIAbility可以是应用内的其他UIAbility,也可以是其他应用的UIAbility(例如启动三方支付UIAbility)。

本文将从如下场景分别介绍设备内UIAbility间的交互方式。对于跨设备的应用组件交互,请参见 应用组件跨设备交互(流转)。

  • 启动应用内的UIAbility
  • 启动应用内的UIAbility并获取返回结果
  • 启动其他应用的UIAbility
  • 启动其他应用的UIAbility并获取返回结果
  • 启动UIAbility指定窗口模式(仅对系统应用开放)
  • 启动UIAbility的指定页面
  • 通过Call调用实现UIAbility交互(仅对系统应用开放)

启动应用内的UIAbility

当一个应用内包含多个UIAbility时,存在应用内启动UIAbility的场景。例如在支付应用中从入口UIAbility启动收付款UIAbility。

假设应用中有两个UIAbility:EntryAbility和FuncAbility(可以在同一个Module中,也可以在不同的Module中),需要从EntryAbility的页面中启动FuncAbility。

  1. 在EntryAbility中,通过调用 startAbility()方法启动UIAbility,want 为UIAbility实例启动的入口参数,其中bundleName为待启动应用的Bundle名称,abilityName为待启动的Ability名称,moduleName在待启动的UIAbility属于不同的Module时添加,parameters为自定义信息参数。示例中的context的获取方式请参见 获取UIAbility的上下文信息。
import common from '@ohos.app.ability.common';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  private context = getContext(this) as common.UIAbilityContext;

  build() {
    ...
    Button()
      .onClick(() => {
    // context为Ability对象的成员,在非Ability对象内部调用需要
        // 将Context对象传递过去
        let wantInfo: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.myapplication',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityA',
          parameters: { // 自定义信息
            info: '来自EntryAbility Page_UIAbilityComponentsInteractive页面'
          },
        }
        // context为调用方UIAbility的UIAbilityContext
        this.context.startAbility(wantInfo).then(() => {
          hilog.info(DOMAIN_NUMBER, TAG, 'startAbility success.');
        }).catch((error: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, 'startAbility failed.');
        });
      })
  }
}
  1. 在FuncAbility的 onCreate() 生命周期回调文件中接收EntryAbility传递过来的参数。
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want';

export default class FuncAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 接收调用方UIAbility传过来的参数
    let funcAbilityWant = want;
    let info = funcAbilityWant?.parameters?.info;
    // ...
  }
}

说明:
被拉起的FuncAbility中,可以通过获取传递过来的want参数的parameters来获取拉起方UIAbility的PID、Bundle Name等信息。

  1. 在FuncAbility业务完成之后,如需要停止当前UIAbility实例,在FuncAbility中通过调用 terminateSelf() 方法实现。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    ...
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        // context为需要停止的UIAbility实例的AbilityContext
        context.terminateSelf((err) => {
          if (err.code) {
            hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate Self. Code is ${err.code}, message is ${err.message}`);
            return;
          }
        });
      })
  }
}

说明:
调用 terminateSelf() 方法停止当前UIAbility实例时,默认会保留该实例的快照(Snapshot),即在最近任务列表中仍然能查看到该实例对应的任务。如不需要保留该实例的快照,可以在其对应UIAbility的 module.json5配置文件中,将 abilities标签的removeMissionAfterTerminate字段配置为true。

  1. 如需要关闭应用所有的UIAbility实例,可以调用 ApplicationContext 的 killAllProcesses() 方法实现关闭应用所有的进程。

启动应用内的UIAbility并获取返回结果

在一个EntryAbility启动另外一个FuncAbility时,希望在被启动的FuncAbility完成相关业务后,能将结果返回给调用方。例如在应用中将入口功能和帐号登录功能分别设计为两个独立的UIAbility,在帐号登录UIAbility中完成登录操作后,需要将登录的结果返回给入口UIAbility。

  1. 在EntryAbility中,调用 startAbilityForResult() 接口启动FuncAbility,异步回调中的data用于接收FuncAbility停止自身后返回给EntryAbility的信息。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext

        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilitydevelop',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityA',
          parameters: { // 自定义信息
            info: '来自EntryAbility UIAbilityComponentsInteractive页面'
          }
        };
        context.startAbilityForResult(want).then((data) => {
          // ...
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}
  1. 在FuncAbility停止自身时,需要调用terminateSelfWithResult() 方法,入参abilityResult为FuncAbility需要返回给EntryAbility的信息。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_FuncAbilityA]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_FuncAbilityA {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        const RESULT_CODE: number = 1001;
        let abilityResult: common.AbilityResult = {
          resultCode: RESULT_CODE,
          want: {
            bundleName: 'com.samples.stagemodelabilitydevelop',
            moduleName: 'entry', // moduleName非必选
            abilityName: 'FuncAbilityB',
            parameters: {
              info: '来自FuncAbility Index页面'
            },
          },
        };
        context.terminateSelfWithResult(abilityResult, (err) => {
          if (err.code) {
            hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);
            return;
          }
        });
      })
  }
}
  1. FuncAbility停止自身后,EntryAbility通过 startAbilityForResult() 方法回调接收被FuncAbility返回的信息,RESULT_CODE需要与前面的数值保持一致。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';
import promptAction from '@ohos.promptAction';

const TAG: string = '[EntryAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        const RESULT_CODE: number = 1001;

        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilitydevelop',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityA',
          parameters: { // 自定义信息
            info: '来自EntryAbility UIAbilityComponentsInteractive页面'
          }
        };
        context.startAbilityForResult(want).then((data) => {
          if (data?.resultCode === RESULT_CODE) {
            // 解析被调用方UIAbility返回的信息
            let info = data.want?.parameters?.info;
            hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
            if (info !== null) {
              promptAction.showToast({
                message: JSON.stringify(info)
              });
            }
          }
          hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

启动其他应用的UIAbility

启动其他应用的UIAbility,通常用户只需要完成一个通用的操作(例如需要选择一个文档应用来查看某个文档的内容信息)。系统会根据调用方的want参数来识别和启动匹配到的应用UIAbility。

启动UIAbility有 显式Want启动和隐式Want启动 两种方式。

  • 显式Want启动:启动一个确定应用的UIAbility,在want参数中需要设置该应用bundleName和abilityName,当需要拉起某个明确的UIAbility时,通常使用显式Want启动方式。

  • 隐式Want启动:根据匹配条件由用户选择启动哪一个UIAbility,即不明确指出要启动哪一个UIAbility(abilityName参数未设置),在调用 startAbility() 方法时,其入参want中指定了一系列的entities字段(表示目标UIAbility额外的类别信息,如浏览器、视频播放器)和actions字段(表示要执行的通用操作,如查看、分享、应用详情等)等参数信息,然后由系统去分析want,并帮助找到合适的UIAbility来启动。当需要拉起其他应用的UIAbility时,开发者通常不知道用户设备中应用的安装情况,也无法确定目标应用的bundleName和abilityName,通常使用隐式Want启动方式。

本文主要讲解如何通过隐式Want启动其他应用的UIAbility。

  1. 将多个待匹配的文档应用安装到设备,在其对应UIAbility的 module.json5配置文件 中,配置skills标签的entities字段和actions字段。
 {
   "module": {
     "abilities": [
       {
         ...
         "skills": [
           {
             "entities": [
               ...
               "entity.system.default"
             ],
             "actions": [
               ...
               "ohos.want.action.viewData"
             ]
           }
         ]
       }
     ]
   }
 }
  1. 在调用方want参数中的entities和action需要被包含在待匹配UIAbility的skills配置的entities和actions中。系统匹配到符合entities和actions参数条件的UIAbility后,会弹出选择框展示匹配到的UIAbility实例列表供用户选择使用。
import common from '@ohos.app.ability.common';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          // uncomment line below if wish to implicitly query only in the specific bundle.
          // bundleName: 'com.samples.stagemodelabilityinteraction',
          action: 'ohos.want.action.viewData',
          // entities can be omitted.
          entities: ['entity.system.default']
        };
        // context为调用方UIAbility的UIAbilityContext
        context.startAbility(want).then(() => {
          hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting FuncAbility.');
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start FuncAbility. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

效果示意如下图所示,点击“打开PDF文档”时,会弹出选择框供用户选择。

  1. 在文档应用使用完成之后,如需要停止当前UIAbility实例,通过调用 terminateSelf() 方法实现。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_FromStageModel]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_FromStageModel {
  @State message: string = 'Hello World'

  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        // context为需要停止的UIAbility实例的AbilityContext
        context.terminateSelf((err) => {
          if (err.code) {
            hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`);
            return;
          }
        });
      })
  }
}

启动其他应用的UIAbility并获取返回结果

当使用隐式Want启动其他应用的UIAbility并希望获取返回结果时,调用方需要使用 startAbilityForResult() 方法启动目标UIAbility。例如主应用中需要启动三方支付并获取支付结果。

  1. 在支付应用对应UIAbility的 module.json5配置文件 中,配置skills的entities字段和actions字段。
{
  "module": {
    "abilities": [
      {
        ...
        "skills": [
          {
            "entities": [
              ...
              "entity.system.default"
            ],
            "actions": [
              ...
              "ohos.want.action.editData"
            ]
          }
        ]
      }
    ]
  }
}
  1. 调用方使用 startAbilityForResult() 方法启动支付应用的UIAbility,在调用方want参数中的entities和action需要被包含在待匹配UIAbility的skills标签配置的entities和actions中。异步回调中的data用于后续接收支付UIAbility停止自身后返回给调用方的信息。系统匹配到符合entities和actions参数条件的UIAbility后,会弹出选择框展示匹配到的UIAbility实例列表供用户选择使用。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext

        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilitydevelop',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityA',
          parameters: { // 自定义信息
            info: '来自EntryAbility UIAbilityComponentsInteractive页面'
          }
        };
        context.startAbilityForResult(want).then((data) => {
          // ...
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}
  1. 在支付UIAbility完成支付之后,需要调用 terminateSelfWithResult() 方法实现停止自身,并将abilityResult参数信息返回给调用方。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';

const TAG: string = '[Page_FuncAbilityA]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_FuncAbilityA {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        const RESULT_CODE: number = 1001;
        let abilityResult: common.AbilityResult = {
          resultCode: RESULT_CODE,
          want: {
            bundleName: 'com.samples.stagemodelabilitydevelop',
            moduleName: 'entry', // moduleName非必选
            abilityName: 'FuncAbilityB',
            parameters: {
              info: '来自FuncAbility Index页面'
            },
          },
        };
        context.terminateSelfWithResult(abilityResult, (err) => {
          if (err.code) {
            hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self with result. Code is ${err.code}, message is ${err.message}`);
            return;
          }
        });
      })
  }
}
  1. 在调用方 startAbilityForResult() 方法回调中接收支付应用返回的信息,RESULT_CODE需要与前面 terminateSelfWithResult() 返回的数值保持一致。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';
import promptAction from '@ohos.promptAction';

const TAG: string = '[EntryAbility]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        const RESULT_CODE: number = 1001;

        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilitydevelop',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityA',
          parameters: { // 自定义信息
            info: '来自EntryAbility UIAbilityComponentsInteractive页面'
          }
        };
        context.startAbilityForResult(want).then((data) => {
          if (data?.resultCode === RESULT_CODE) {
            // 解析被调用方UIAbility返回的信息
            let info = data.want?.parameters?.info;
            hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(info) ?? '');
            if (info !== null) {
              promptAction.showToast({
                message: JSON.stringify(info)
              });
            }
          }
          hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(data.resultCode) ?? '');
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability for result. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

启动UIAbility指定窗口模式(仅对系统应用开放)

当用户打开应用时,应用程序会以不同的窗口模式进行展示,即启动UIAbility的窗口模式。应用程序可以启动为全屏模式,悬浮窗模式或分屏模式。

全屏模式是指应用程序启动后,占据整个屏幕,用户无法同时查看其他窗口或应用程序。全屏模式通常适用于那些要求用户专注于特定任务或界面的应用程序。

悬浮窗模式是指应用程序启动后,以浮动窗口的形式显示在屏幕上,用户可以轻松切换到其他窗口或应用程序。悬浮窗通常适用于需要用户同时处理多个任务的应用程序。

分屏模式允许用户在同一屏幕上同时运行两个应用程序,其中一个应用程序占据屏幕左侧/上侧的一部分,另一个应用程序占据右侧/下侧的一部分。分屏模式主要用于提高用户的多任务处理效率。

使用 startAbility() 方法启动UIAbility时,可以通过在入参中增加 StartOptions 参数的windowMode属性来配置启动UIAbility的窗口模式。

说明:

  1. 如果在使用 startAbility() 方法启动UIAbility时,入参中未指定 StartOptions 参数的windowMode属性,那么UIAbility将以系统默认的窗口展示形态启动。
  2. 为了确保启动的UIAbility展示形态能够被支持,需要在该UIAbility对应的 module.json5配置文件中 abilities标签的supportWindowMode字段确认启动的展示形态被支持。

以下是具体的操作步骤,以悬浮窗模式为例,假设需要从EntryAbility的页面中启动FuncAbility:

  1. 在调用 startAbility() 方法时,增加 StartOptions 参数。
  2. 在 StartOptions 参数中设置windowMode字段为WINDOW_MODE_FLOATING,表示启动的UIAbility将以悬浮窗的形式展示。
  3. windowMode属性仅适用于系统应用,三方应用可以使用displayId属性。
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import StartOptions from '@ohos.app.ability.StartOptions';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilitydevelop',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbilityB',
          parameters: { // 自定义信息
            info: '来自EntryAbility Index页面'
          }
        };
        let options: StartOptions = {
          windowMode: AbilityConstant.WindowMode.WINDOW_MODE_FLOATING
        };
        // context为调用方UIAbility的UIAbilityContext
        context.startAbility(want, options).then(() => {
          hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.');
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

效果示意如下图所示。

启动UIAbility的指定页面

概述

一个UIAbility可以对应多个页面,在不同的场景下启动该UIAbility时需要展示不同的页面,例如从一个UIAbility的页面中跳转到另外一个UIAbility时,希望启动目标UIAbility的指定页面。

UIAbility的启动分为两种情况:UIAbility冷启动和UIAbility热启动。

  • UIAbility冷启动:指的是UIAbility实例处于完全关闭状态下被启动,这需要完整地加载和初始化UIAbility实例的代码、资源等。
  • UIAbility热启动:指的是UIAbility实例已经启动并在前台运行过,由于某些原因切换到后台,再次启动该UIAbility实例,这种情况下可以快速恢复UIAbility实例的状态。

本文主要讲解 目标UIAbility冷启动 两种启动指定页面的场景,以及在讲解启动指定页面之前会讲解到在调用方如何指定启动页面。

调用方UIAbility指定启动页面

调用方UIAbility启动另外一个UIAbility时,通常需要跳转到指定的页面。例如FuncAbility包含两个页面(Index对应首页,Second对应功能A页面),此时需要在传入的want参数中配置指定的页面路径信息,可以通过want中的parameters参数增加一个自定义参数传递页面跳转信息。

import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';

const TAG: string = '[Page_UIAbilityComponentsInteractive]';
const DOMAIN_NUMBER: number = 0xFF00;

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        let want: Want = {
          deviceId: '', // deviceId为空表示本设备
          bundleName: 'com.samples.stagemodelabilityinteraction',
          moduleName: 'entry', // moduleName非必选
          abilityName: 'FuncAbility',
          parameters: { // 自定义参数传递页面信息
            router: 'FuncA'
          }
        };
        // context为调用方UIAbility的UIAbilityContext
        context.startAbility(want).then(() => {
          hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ability.');
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

目标UIAbility冷启动

目标UIAbility冷启动时,在目标UIAbility的onCreate()生命周期回调中,接收调用方传过来的参数。然后在目标UIAbility的onWindowStageCreate()生命周期回调中,解析EntryAbility传递过来的want参数,获取到需要加载的页面信息url,传入windowStage.loadContent()方法。

import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';

export default class FuncAbility extends UIAbility {
  funcAbilityWant: Want | undefined = undefined;

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 接收调用方UIAbility传过来的参数
    this.funcAbilityWant = want;
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    let url = 'pages/Index';
    if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
      url = 'pages/Page_ColdStartUp';
    }
    windowStage.loadContent(url, (err, data) => {
      // ...
    });
  }
}

目标UIAbility热启动

在应用开发中,会遇到目标UIAbility实例之前已经启动过的场景,这时再次启动目标UIAbility时,不会重新走初始化逻辑,只会直接触发onNewWant()生命周期方法。为了实现跳转到指定页面,需要在onNewWant()中解析参数进行处理。

例如短信应用和联系人应用配合使用的场景。

  1. 用户先打开短信应用,短信应用的UIAbility实例启动,显示短信应用的主页。
  2. 用户将设备回到桌面界面,短信应用进入后台运行状态。
  3. 用户打开联系人应用,找到联系人张三。
  4. 用户点击联系人张三的短信按钮,会重新启动短信应用的UIAbility实例。
  5. 由于短信应用的UIAbility实例已经启动过了,此时会触发该UIAbility的onNewWant()回调,而不会再走onCreate()onWindowStageCreate()等初始化逻辑。

图1 目标UIAbility热启动

开发步骤如下所示。

  1. 冷启动短信应用的UIAbility实例时,在onWindowStageCreate()生命周期回调中,通过调用 getUIContext() 接口获取UI上下文实例 UIContext 对象。
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';

import { UIContext } from '@ohos.arkui.UIContext';

const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EntryAbility]';

export default class EntryAbility extends UIAbility {
  funcAbilityWant: Want | undefined = undefined;
  uiContext: UIContext | undefined = undefined;

  // ...

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    let url = 'pages/Index';
    if (this.funcAbilityWant?.parameters?.router && this.funcAbilityWant.parameters.router === 'funcA') {
      url = 'pages/Page_ColdStartUp';
    }

    windowStage.loadContent(url, (err, data) => {
      if (err.code) {
        return;
      }

      let windowClass: window.Window;
      windowStage.getMainWindow((err, data) => {
        if (err.code) {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to obtain the main window. Code is ${err.code}, message is ${err.message}`);
          return;
        }
        windowClass = data;
        this.uiContext = windowClass.getUIContext();
      })
    });
  }
}
  1. 在短信应用UIAbility的onNewWant()回调中解析调用方传递过来的want参数,通过调用UIContext中的getRouter() 方法获取 Router 对象,并进行指定页面的跳转。此时再次启动该短信应用的UIAbility实例时,即可跳转到该短信应用的UIAbility实例的指定页面。
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base';

import { Router, UIContext } from '@ohos.arkui.UIContext';

const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[EntryAbility]';

export default class EntryAbility extends UIAbility {
  funcAbilityWant: Want | undefined = undefined;
  uiContext: UIContext | undefined = undefined;

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (want?.parameters?.router && want.parameters.router === 'funcB') {
      let funcAUrl = 'pages/Page_HotStartUp';
      if (this.uiContext) {
        let router: Router = this.uiContext.getRouter();
        router.pushUrl({
          url: funcAUrl
        }).catch((err: BusinessError) => {
       hilog.error(DOMAIN_NUMBER, TAG, `Failed to push url. Code is ${err.code}, message is ${err.message}`);
        });
      }
    }
  }
  // ...
}

说明:
当被调用方 UIAbility组件启动模式 设置为multiton启动模式时,每次启动都会创建一个新的实例,那么 onNewWant() 回调就不会被用到。

通过Call调用实现UIAbility交互(仅对系统应用开放)

Call调用是UIAbility能力的扩展,它为UIAbility提供一种能够被外部调用并与外部进行通信的能力。Call调用支持前台与后台两种启动方式,使UIAbility既能被拉起到前台展示UI,也可以在后台被创建并运行。Call调用在调用方与被调用方间建立了IPC通信,因此应用开发者可通过Call调用实现不同UIAbility之间的数据共享。

Call调用的核心接口是startAbilityByCall()方法,与startAbility()接口的不同之处在于:

  • startAbilityByCall支持前台与后台两种启动方式,而startAbility()仅支持前台启动。
  • 调用方可使用startAbilityByCall()所返回的Caller对象与被调用方进行通信,而startAbility()不具备通信能力。

Call调用的使用场景主要包括:

  • 需要与被启动的UIAbility进行通信。
  • 希望被启动的UIAbility在后台运行。

表1 Call调用相关名词解释

名词描述
CallerAbility进行Call调用的UIAbility(调用方)。
CalleeAbility被Call调用的UIAbility(被调用方)。
Caller实际对象,由startAbilityByCall接口返回,CallerAbility可使用Caller与CalleeAbility进行通信。
Callee实际对象,被CalleeAbility持有,可与Caller进行通信。

Call调用示意图如下所示。

图1 Call调用示意图

  • CallerAbility调用startAbilityByCall接口获取Caller,并使用Caller对象的call方法向CalleeAbility发送数据。
  • CalleeAbility持有一个Callee对象,通过Callee的on方法注册回调函数,当接收到Caller发送的数据时将会调用对应的回调函数。

说明:

  1. 当前仅支持系统应用使用Call调用。
  2. CalleeAbility的启动模式需要为单实例。
  3. Call调用既支持本地(设备内)Call调用,也支持跨设备Call调用,下面介绍设备内Call调用方法。

接口说明

Call功能主要接口如下表所示。具体的API详见 接口文档。

表2 Call功能主要接口

接口名描述
startAbilityByCall(want: Want): Promise启动指定UIAbility并获取其Caller通信接口,默认为后台启动,通过配置want可实现前台启动,详见 接口文档。AbilityContext与ServiceExtensionContext均支持该接口。
on(method: string, callback: CalleeCallBack): void通用组件Callee注册method对应的callback方法。
off(method: string): void通用组件Callee解注册method的callback方法。
call(method: string, data: rpc.Parcelable): Promise向通用组件Callee发送约定序列化数据。
callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence>向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。
release(): void释放通用组件的Caller通信接口。
on(type: “release”, callback: OnReleaseCallback): void注册通用组件通信断开监听通知。

设备内通过Call调用实现UIAbility交互,涉及如下两部分开发:

  • 创建Callee被调用端
  • 访问Callee被调用端

开发步骤(创建Callee被调用端)

在Callee被调用端,需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。

  1. 配置UIAbility的启动模式。

例如将CalleeAbility配置为单实例模式singleton

  1. 导入UIAbility模块。
import UIAbility from '@ohos.app.ability.UIAbility';
  1. 定义约定的序列化数据。 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。
import type rpc from '@ohos.rpc';

class MyParcelable {
  num: number = 0;
  str: string = '';

  constructor(num: number, string: string) {
    this.num = num;
    this.str = string;
  };

  mySequenceable(num, string): void {
    this.num = num;
    this.str = string;
  };

  marshalling(messageSequence: rpc.MessageSequence): boolean {
    messageSequence.writeInt(this.num);
    messageSequence.writeString(this.str);
    return true;
  };

  unmarshalling(messageSequence: rpc.MessageSequence): boolean {
    this.num = messageSequence.readInt();
    this.str = messageSequence.readString();
    return true;
  };
};
  1. 实现Callee.on监听及Callee.off解除监听。

被调用端Callee的监听函数注册时机,取决于应用开发者。注册监听之前的数据不会被处理,取消监听之后的数据不会被处理。如下示例在UIAbility的onCreate注册’MSG_SEND_METHOD’监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回,应用开发者根据实际需要做相应处理。具体示例代码如下:

import type AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';
import hilog from '@ohos.hilog';
import Logger from '../utils/Logger';
import type rpc from '@ohos.rpc';
import type { Caller } from '@ohos.app.ability.UIAbility';

const MSG_SEND_METHOD: string = 'CallSendMsg';
const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[CalleeAbility]';

class MyParcelable {
  num: number = 0;
  str: string = '';

  constructor(num: number, string: string) {
    this.num = num;
    this.str = string;
  }

  mySequenceable(num, string): void {
    this.num = num;
    this.str = string;
  }

  marshalling(messageSequence: rpc.MessageSequence): boolean {
    messageSequence.writeInt(this.num);
    messageSequence.writeString(this.str);
    return true;
  };

  unmarshalling(messageSequence: rpc.MessageSequence): boolean {
    this.num = messageSequence.readInt();
    this.str = messageSequence.readString();
    return true;
  };
};

function sendMsgCallback(data: rpc.MessageSequence): rpc.Parcelable {
  hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'CalleeSortFunc called');

  // 获取Caller发送的序列化数据
  let receivedData: MyParcelable = new MyParcelable(0, '');
  data.readParcelable(receivedData);
  hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `receiveData[${receivedData.num}, ${receivedData.str}]`);
  let num: number = receivedData.num;

  // 作相应处理
  // 返回序列化数据result给Caller
  return new MyParcelable(num + 1, `send ${receivedData.str} succeed`) as rpc.Parcelable;
}

export default class CalleeAbility extends UIAbility {
  caller: Caller | undefined;
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    try {
      this.callee.on(MSG_SEND_METHOD, sendMsgCallback);
    } catch (error) {
      hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`);
    };
  }
  releaseCall(): void {
    try {
      if (this.caller) {
        this.caller.release();
        this.caller = undefined;
      }
      Logger.info('caller release succeed');
    } catch (error) {
      Logger.info(`caller release failed with ${error}`);
    };
  }
  onDestroy(): void {
    try {
      this.callee.off(MSG_SEND_METHOD);
      hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Callee OnDestroy');
      this.releaseCall();
    } catch (error) {
      hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`);
    };
  }
}

开发步骤(访问Callee被调用端)

  1. 导入UIAbility模块。
import UIAbility from '@ohos.app.ability.UIAbility';
  1. 获取Caller通信接口。 UIAbilityContext属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取UIAbility实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease监听。应用开发者根据实际需要做相应处理。
import { Caller } from '@ohos.app.ability.UIAbility';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';
import promptAction from '@ohos.promptAction';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';

const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[Page_UIAbilityComponentsInteractive]';

@Entry
@Component
struct Page_UIAbilityComponentsInteractive {
  caller: Caller | undefined = undefined;

  // 注册caller的release监听
  private regOnRelease(caller: Caller): void {
    hilog.info(DOMAIN_NUMBER, TAG, `caller is ${caller}`);
    try {
      caller.on('release', (msg: string) => {
        hilog.info(DOMAIN_NUMBER, TAG, `caller onRelease is called ${msg}`);
      })
      hilog.info(DOMAIN_NUMBER, TAG, 'succeeded in registering on release.');
    } catch (err) {
      let code = (err as BusinessError).code;
      let message = (err as BusinessError).message;
      hilog.error(DOMAIN_NUMBER, TAG, `Failed to caller register on release. Code is ${code}, message is ${message}`);
    }
    ;
  }

  build() {
    Button()
      .onClick(() => {
        let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext
        let want: Want = {
          bundleName: 'com.samples.stagemodelabilityinteraction',
          abilityName: 'CalleeAbility',
          parameters: { // 自定义信息
            info: 'CallSendMsg'
          }
        };

        context.startAbilityByCall(want).then((caller: Caller) => {
          hilog.info(DOMAIN_NUMBER, TAG, `Succeeded in starting ability.Code is ${caller}`);
          if (caller === undefined) {
            hilog.info(DOMAIN_NUMBER, TAG, 'get caller failed');
            return;
          }
          else {
            hilog.info(DOMAIN_NUMBER, TAG, 'get caller success');
            this.regOnRelease(caller);
            promptAction.showToast({
              message: $r('app.string.CallerSuccess')
            });
          }
        }).catch((err: BusinessError) => {
          hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ability. Code is ${err.code}, message is ${err.message}`);
        });
      })
  }
}

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1554413.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用优化型读取和 pgvector,提高 Amazon Aurora 上生成式 AI 工作负载的性能

生成式 AI 为企业带来了更多的机会&#xff0c;可以构建需要搜索和比较非结构化数据类型&#xff08;例如文本、图像和视频等&#xff09;的应用程序。通过 嵌入体 或 向量&#xff0c;以机器可读的格式捕获这些非结构化数据的含义和上下文&#xff0c;然后基于这种方法&#x…

C语言结合体和枚举的魅力展现

前言 ✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱’博客 所属栏目&#xff1a;人工智能 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 引言: 前面我们已经讲了结构体的声明&#xff0c;自引用&#xff0c;内存…

Kibana操作Elasticsearch教程

文章目录 简介ES文档操作创建索引查看索引创建映射字段查看映射关系字段属性详解typeindexstore 字段映射设置流程 新增数据新增会随机生成id新增自定义id智能判断 修改数据删除数据查询基本查询查询所有&#xff08;match_all&#xff09;匹配查询多字段查询词条匹配多词条精确…

图片标注编辑平台搭建系列教程(4)——fabric几何定制渲染

背景 标注的几何&#xff0c;有时需要一些定制化的渲染样式&#xff0c;例如&#xff0c;线中间展示箭头&#xff0c;表示方向。本期教程教大家如何实现fabric几何定制化渲染。 带箭头的线 fabric提供了一些原生的几何&#xff0c;例如Point、Polyline、Polygon。同时提供了…

【快速上手ESP32(基于ESP-IDFVSCode)】01-环境配置GPIO口延时函数(先点个灯)

前言 立创开发板之前出了个ESP32S3R8N8的开发板&#xff0c;当时嫖了个优惠券&#xff0c;九块九拿下了。 现在不仅是35.9一个&#xff0c;而且还没货。 如果真的想要的小伙伴可以自己去打板焊一个&#xff0c;人家开源了&#xff08;目测难度较大&#xff0c;反正我是焊不上…

vue-devtools 不显示的问题

vue 项目中浏览器右上角可以显示出插件&#xff0c;但是控制台却没有显示。 项目中在main.js中添加设置devtools为trueVue.config.devtools true插件显示可以使使用&#xff0c;控制台没有显示VUE选项 项目使用了 externals 打包优化&#xff0c;使用了vue的压缩版本&#x…

Etcd 基本入门

1&#xff1a;什么是 Etcd ? Etcd 是 CoreOS 团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法&#xff0c;Etcd基于 Go 语言实现。 名字由来&#xff0c;它源于两个方面&#xff0c;…

Intel Arc显卡安装Stable Diffusion

StableDiffusion是一种基于深度学习的文本到图像生成模型&#xff0c;于2022年发布。它主要用于根据文本描述生成详细图像&#xff0c;也可应用于其他任务&#xff0c;如内补绘制、外补绘制和在提示词指导下生成图像翻译。通过给定文本提示词&#xff0c;该模型会输出一张匹配提…

Nagios工具

一 nagios 相关概念 Nagios 是一款开源的免费网络监视工具&#xff0c;能有效监控 Windows、Linux 和 Unix 的主机状态&#xff0c;交换机路由器等网络设置&#xff0c;打印机等。在系统或服务状态异常时发出邮件或短信报警第 一时间通知网站运维人员&#xff0c;在状态恢复后…

不愧是字节出来的,真厉害...

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前段时间公司缺人&#xff0c;也面了许多测试&#xff0c;一开始…

互联网轻量级框架整合之JavaEE基础

不得不解释得几个概念 JavaEE SUN公司提出来的企业版Java开发中间件&#xff0c;主要用于企业级互联网系统的框架搭建&#xff0c;同时因为Java语言优质的平台无关性、可移植性、健壮性、支持多线程和安全性等优势&#xff0c;其迅速成为构建企业互联网平台的主流技术&#x…

4T第十四届省赛模拟2

一、Seg 温度读取&#xff1a; ①温度 温度读他读出来就是有精度的所以自带小数 我们读取的时候直接强制类型转换读它的各个位也不会丢失精度 ②电压 电压是你人为的/51.0了&#xff0c;从char->float->char所以会有精度丢失 所以要用原始数据来换算 在原始数据上多…

web布局——说清楚fixed布局

极限省流 想要fixed做导航页面&#xff1a;指定清楚top、left、right、bottom&#xff0c;没指定清楚布局位置就会采用默认的方式&#xff1a; 0&#xff09;父元素的padding&#xff1a;fixed元素相对位移 1&#xff09;同级元素是fixed元素&#xff1a;覆盖 2&#xff09…

.NET CORE 分布式事务(三) DTM实现Saga及高并发下的解决方案

目录(结尾附加项目代码资源地址) 引言&#xff1a; 1. SAGA事务模式 2. 拆分为子事务 3. 失败回滚 4. 如何做补偿 4.1 失败的分支是否需要补偿 5. 异常 6. 异常与子事务屏障 6.1 NPC的挑战 6.2 现有方案的问题 6.3 子事务屏障 6.4 原理 7. 更多高级场景 7.1 部分…

Golang-Gorm-快速上手

Gorm文档 GORM文档地址 安装依赖 go get -u "gorm.io/driver/mysql"go get -u "gorm.io/gorm"连接数据库 默认连接方式 func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情dsn : "user:passtcp(127.0.0…

Django自动化测试平台项目前端框架设计

引言 在之前根据项目具体情况&#xff0c;开发了一套自动预报数据的平台&#xff0c;但是前端页面不耐看&#xff0c;久了就生厌。于是就想更换前端框架&#xff0c;顺便记录一下。 前端设计 原来的界面&#xff1a; 一键预报模块&#xff1a; 为了有更好的感官体验&#xf…

设计模式——结构型——外观模式Facade

处理器类 public class Cpu {public void start() {System.out.println("处理器启动了...");} } 内存类 public class Memory {public void start() {System.out.println("内存启动了...");} } 硬盘类 public class Disk {public void start() {Syste…

单目图像加单点测距,求解目标位姿

单目图像加单点测距&#xff0c;求解目标位 附赠自动驾驶学习资料和量产经验&#xff1a;链接 单目相机通过对极约束来求解相机运动的位姿。参考了ORBSLAM中单目实现的代码&#xff0c;这里用opencv来实现最简单的位姿估计。 对极约束的概念可以参考我的这篇 Visual SLAM –…

总结TCP各类知识点

前言 本篇博客博主将详细地介绍TCP有关知识点&#xff0c;坐好板凳发车啦~ 一.TCP特点 1.有连接 TCP传输的过程中类似于打电话的各个过程 2.可靠传输 通过TCP自身的多种机制来保证可靠传输 3.面向字节流 内容是以字节的方式来进行发送与接收 4.缓冲区 TCP有接收缓冲区…

谈一谈BEV和Transformer在自动驾驶中的应用

谈一谈BEV和Transformer在自动驾驶中的应用 BEV和Transformer都这么火&#xff0c;这次就聊一聊。 结尾有资料连接 一 BEV有什么用 首先&#xff0c;鸟瞰图并不能带来新的功能&#xff0c;对规控也没有什么额外的好处。 从鸟瞰图这个名词就可以看出来&#xff0c;本来摄像头…