HarmonyOS 应用开发之多端协同

let dmClass: deviceManager.DeviceManager;

function getRemoteDeviceId(): string | undefined {
if (typeof dmClass === ‘object’ && dmClass !== null) {
let list = dmClass.getAvailableDeviceListSync();
hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
if (typeof (list) === ‘undefined’ || typeof (list.length) === ‘undefined’) {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: list is null’);
return;
}
if (list.length === 0) {
hilog.info(DOMAIN_NUMBER, TAG, getRemoteDeviceId err: list is empty);
return;
}
return list[0].networkId;
} else {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: dmClass is null’);
return;
}
};

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

build() {
// …
Button(‘多端协同有返回数据’)
.onClick(()=>{
let want: Want = {
deviceId: getRemoteDeviceId(),
bundleName: ‘com.samples.stagemodelabilityinteraction’,
abilityName: ‘CollaborateAbility’,
moduleName: ‘entry’ // moduleName非必选
};
// context为发起端UIAbility的AbilityContext
this.context.startAbilityForResult(want).then((data) => {
// …
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, startAbilityForResult err: + JSON.stringify(error));
})
}
)
}
}


4. 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。



import common from ‘@ohos.app.ability.common’;
import hilog from ‘@ohos.hilog’;
import { BusinessError } from ‘@ohos.base’;

const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = ‘[Page_CollaborateAbility]’;

@Entry
@Component
struct PageName {

private context = getContext(this) as common.UIAbilityContext;

build() {
// …
Button(‘关闭多设备协同界面并返回数据’)
.onClick(()=>{
const RESULT_CODE: number = 1001;
// context为目标端UIAbility的AbilityContext
this.context.terminateSelfWithResult(
{
resultCode: RESULT_CODE,
want: {
bundleName: ‘ohos.samples.stagemodelabilitydevelop’,
abilityName: ‘CollaborateAbility’,
moduleName: ‘entry’,
parameters: {
info: ‘来自Page_CollaborateAbility页面’
}
}
},
(err: BusinessError) => {
hilog.info(DOMAIN_NUMBER, TAG, terminateSelfWithResult err: + JSON.stringify(err));
});
})
}
}


5. 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。



import common from ‘@ohos.app.ability.common’;
import deviceManager from ‘@ohos.distributedDeviceManager’;
import hilog from ‘@ohos.hilog’;
import Want from ‘@ohos.app.ability.Want’;
import { BusinessError } from ‘@ohos.base’;

const TAG: string = ‘[Page_CollaborateAbility]’;
const DOMAIN_NUMBER: number = 0xFF00;
let dmClass: deviceManager.DeviceManager;

function getRemoteDeviceId(): string | undefined {
if (typeof dmClass === ‘object’ && dmClass !== null) {
let list = dmClass.getAvailableDeviceListSync();
hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
if (typeof (list) === ‘undefined’ || typeof (list.length) === ‘undefined’) {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: list is null’);
return;
}
if (list.length === 0) {
hilog.info(DOMAIN_NUMBER, TAG, getRemoteDeviceId err: list is empty);
return;
}
return list[0].networkId;
} else {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: dmClass is null’);
return;
}
};

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

build() {
// …
Button(‘多端协同有返回数据’)
.onClick(() => {
let want: Want = {
deviceId: getRemoteDeviceId(),
bundleName: ‘com.samples.stagemodelabilityinteraction’,
abilityName: ‘CollaborateAbility’,
moduleName: ‘entry’ // moduleName非必选
};
const RESULT_CODE: number = 1001;
// …
// context为调用方UIAbility的UIAbilityContext
this.context.startAbilityForResult(want).then((data) => {
if (data?.resultCode === RESULT_CODE) {
// 解析目标端UIAbility返回的信息
let info = data.want?.parameters?.info;
// …
}
}).catch((error: BusinessError) => {
// …
})
}
)
}
}


### 通过跨设备连接ServiceExtensionAbility组件实现多端协同


系统应用可以通过 connectServiceExtensionAbility() 跨设备连接一个服务,实现跨设备远程调用。比如:分布式游戏场景,平板作为遥控器,智慧屏作为显示器。


#### 接口说明


**表3** 跨设备连接API接口功能介绍




| 接口名 | 描述 |
| --- | --- |
| connectServiceExtensionAbility(want: Want, options: ConnectOptions): number; | 连接ServiceExtensionAbility。 |
| disconnectServiceExtensionAbility(connection: number, callback:AsyncCallback): void; | 断开连接(callback形式)。 |
| disconnectServiceExtensionAbility(connection: number): Promise; | 断开连接(promise形式)。 |


#### 开发步骤


1. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见[声明权限]( )。
2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。
3. 如果已有后台服务,请直接进入下一步;如果没有,则 实现一个后台服务(仅对系统应用开放) 。
4. 连接一个后台服务。


	* 实现IAbilityConnection接口。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常终止的回调,onFailed()是用来处理连接Service失败的回调。
	* 设置目标组件参数,包括目标设备ID、Bundle名称、Ability名称。
	* 调用connectServiceExtensionAbility发起连接。
	* 连接成功,收到目标设备返回的服务句柄。
	* 进行跨设备调用,获得目标端服务返回的结果。



import common from ‘@ohos.app.ability.common’;
import deviceManager from ‘@ohos.distributedDeviceManager’;
import hilog from ‘@ohos.hilog’;
import rpc from ‘@ohos.rpc’;
import Want from ‘@ohos.app.ability.Want’;
import { BusinessError } from ‘@ohos.base’;

const TAG: string = ‘[Page_CollaborateAbility]’;
const DOMAIN_NUMBER: number = 0xFF00;
const REQUEST_CODE = 1;
let dmClass: deviceManager.DeviceManager;
let connectionId: number;
let options: common.ConnectOptions = {
onConnect(elementName, remote) {
hilog.info(DOMAIN_NUMBER, TAG, ‘onConnect callback’);
if (remote === null) {
hilog.info(DOMAIN_NUMBER, TAG, onConnect remote is null);
return;
}
let option = new rpc.MessageOption();
let data = new rpc.MessageSequence();
let reply = new rpc.MessageSequence();
data.writeInt(99); // 开发者可发送data到目标端应用进行相应操作
// @param code 表示客户端发送的服务请求代码。
// @param data 表示客户端发送的{@link MessageSequence}对象。
// @param reply 表示远程服务发送的响应消息对象。
// @param options 指示操作是同步的还是异步的。
//
// @return 如果操作成功返回{@code true}; 否则返回 {@code false}。
remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
let errCode = reply.readInt(); // 在成功连接的情况下,会收到来自目标端返回的信息(100)
let msg: number = 0;
if (errCode === 0) {
msg = reply.readInt();
}
// 成功连接后台服务
hilog.info(DOMAIN_NUMBER, TAG, sendRequest msg:${msg});
}).catch((error: BusinessError) => {
hilog.info(DOMAIN_NUMBER, TAG, sendRequest failed, ${JSON.stringify(error)});
});
},
onDisconnect(elementName) {
hilog.info(DOMAIN_NUMBER, TAG, ‘onDisconnect callback’);
},
onFailed(code) {
hilog.info(DOMAIN_NUMBER, TAG, ‘onFailed callback’);
}
};

function getRemoteDeviceId(): string | undefined {
if (typeof dmClass === ‘object’ && dmClass !== null) {
let list = dmClass.getAvailableDeviceListSync();
hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
if (typeof (list) === ‘undefined’ || typeof (list.length) === ‘undefined’) {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: list is null’);
return;
}
if (list.length === 0) {
hilog.info(DOMAIN_NUMBER, TAG, getRemoteDeviceId err: list is empty);
return;
}
return list[0].networkId;
} else {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: dmClass is null’);
return;
}
}

@Entry
@Component
struct PageName {
private context = getContext(this) as common.UIAbilityContext;
build() {
// …
Button(‘connectServiceExtensionAbility’)
.onClick(()=>{
let want: Want = {
‘deviceId’: getRemoteDeviceId(),
‘bundleName’: ‘com.samples.stagemodelabilityinteraction’,
‘abilityName’: ‘ServiceExtAbility’
};
// 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
connectionId = this.context.connectServiceExtensionAbility(want, options);
})
}
}


getRemoteDeviceId方法参照 通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据 。


5. 断开连接。调用disconnectServiceExtensionAbility()断开与后台服务的连接。



import common from ‘@ohos.app.ability.common’;
import { BusinessError } from ‘@ohos.base’;
import hilog from ‘@ohos.hilog’;
import Want from ‘@ohos.app.ability.Want’;
import rpc from ‘@ohos.rpc’;
import IdlServiceExtProxy from ‘…/IdlServiceExt/idl_service_ext_proxy’;

let connectionId: number;
const TAG: string = ‘[Page_ServiceExtensionAbility]’;
const DOMAIN_NUMBER: number = 0xFF00;
let want: Want = {
deviceId: ‘’,
bundleName: ‘com.samples.stagemodelabilitydevelop’,
abilityName: ‘ServiceExtAbility’
};

let options: common.ConnectOptions = {
onConnect(elementName, remote: rpc.IRemoteObject): void {
hilog.info(DOMAIN_NUMBER, TAG, ‘onConnect callback’);
if (remote === null) {
hilog.info(DOMAIN_NUMBER, TAG, ‘onConnect remote is null’);
return;
}
let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote);
// 通过接口调用的方式进行通信,屏蔽了RPC通信的细节,简洁明了
serviceExtProxy.processData(1, (errorCode: number, retVal: number) => {
hilog.info(DOMAIN_NUMBER, TAG, processData, errorCode: ${errorCode}, retVal: ${retVal});
});
serviceExtProxy.insertDataToMap(‘theKey’, 1, (errorCode: number) => {
hilog.info(DOMAIN_NUMBER, TAG, insertDataToMap, errorCode: ${errorCode});
})
},
onDisconnect(elementName): void {
hilog.info(DOMAIN_NUMBER, TAG, ‘onDisconnect callback’);
},
onFailed(code: number): void {
hilog.info(DOMAIN_NUMBER, TAG, ‘onFailed callback’, JSON.stringify(code));
}
};

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

build() {
// …
Button(‘disconnectServiceExtensionAbility’)
.onClick(() => {
this.context.disconnectServiceExtensionAbility(connectionId).then(() => {
connectionId = this.context.connectServiceExtensionAbility(want, options);
hilog.info(DOMAIN_NUMBER, TAG, ‘disconnectServiceExtensionAbility success’);
// 成功断连后台服务
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, ‘disconnectServiceExtensionAbility failed’);
})
})
}
}


### 通过跨设备Call调用实现多端协同


跨设备Call调用的基本原理与设备内Call调用相同,请参见通过Call调用实现UIAbility交互(仅对系统应用开放) 。


下面介绍跨设备Call调用实现多端协同的方法。


#### 接口说明


**表4** Call API接口功能介绍




| 接口名 | 描述 |
| --- | --- |
| startAbilityByCall(want: Want): Promise; | 启动指定UIAbility至前台或后台,同时获取其Caller通信接口,调用方可使用Caller与被启动的Ability进行通信。 |
| 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 | 注册通用组件通信断开监听通知。 |


#### 开发步骤


1. 需要申请`ohos.permission.DISTRIBUTED_DATASYNC`权限,配置方式请参见 声明权限 。
2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。
3. 创建被调用端UIAbility。 被调用端UIAbility需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。
4. 配置UIAbility的启动模式。 配置module.json5,将CalleeAbility配置为单实例"singleton"。




| Json字段 | 字段说明 |
| --- | --- |
| “launchType” | Ability的启动模式,设置为"singleton"类型。 |


UIAbility配置标签示例如下:



“abilities”:[{
“name”: “.CalleeAbility”,
“srcEntry”: “./ets/CalleeAbility/CalleeAbility.ts”,
“launchType”: “singleton”,
“description”: “ s t r i n g : C a l l e e A b i l i t y d e s c " , " i c o n " : " string:CalleeAbility_desc", "icon": " string:CalleeAbilitydesc","icon":"media:icon”,
“label”: “$string:CalleeAbility_label”,
“exported”: true
}]


2. 导入UIAbility模块。



import UIAbility from ‘@ohos.app.ability.UIAbility’;


3. 定义约定的序列化数据。 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。



import rpc from ‘@ohos.rpc’
class MyParcelable {
num: number = 0;
str: string = ‘’;

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

mySequenceable(num: number, string: 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;
};
};


4. 实现Callee.on监听及Callee.off解除监听。 如下示例在Ability的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 type rpc from ‘@ohos.rpc’;
import type { Caller } from ‘@ohos.app.ability.UIAbility’;

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

class MyParcelable {
num: number = 0;
str: string = ‘’;

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

mySequenceable(num: number, string: 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})
};
}

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})
};
}
}


4. 获取Caller接口,访问被调用端UIAbility。
	1. 导入UIAbility模块。



import UIAbility from ‘@ohos.app.ability.UIAbility’;



  1. 获取Caller通信接口。 Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease和onRemoteStateChange监听。应用开发者根据实际业务需要做相应处理。


import { Caller } from ‘@ohos.app.ability.UIAbility’;
import { BusinessError } from ‘@ohos.base’;
import common from ‘@ohos.app.ability.common’;
import deviceManager from ‘@ohos.distributedDeviceManager’;
import hilog from ‘@ohos.hilog’;

const TAG: string = ‘[Page_CollaborateAbility]’;
const DOMAIN_NUMBER: number = 0xFF00;
let caller: Caller | undefined;
let dmClass: deviceManager.DeviceManager;

function getRemoteDeviceId(): string | undefined {
if (typeof dmClass === ‘object’ && dmClass !== null) {
let list = dmClass.getAvailableDeviceListSync();
hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));
if (typeof (list) === ‘undefined’ || typeof (list.length) === ‘undefined’) {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: list is null’);
return;
}
if (list.length === 0) {
hilog.info(DOMAIN_NUMBER, TAG, getRemoteDeviceId err: list is empty);
return;
}
return list[0].networkId;
} else {
hilog.info(DOMAIN_NUMBER, TAG, ‘getRemoteDeviceId err: dmClass is null’);
return;
}
}

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

build() {
// …
Button(‘多端协同有返回数据’)
.onClick(() => {
this.context.startAbilityByCall({
deviceId: getRemoteDeviceId(),
bundleName: ‘com.samples.stagemodelabilityinteraction’,
abilityName: ‘CalleeAbility’
}).then((data) => {
if (data !== null) {
caller = data;
hilog.info(DOMAIN_NUMBER, TAG, ‘get remote caller success’);
// 注册caller的release监听
caller.onRelease((msg) => {
hilog.info(DOMAIN_NUMBER, TAG, remote caller onRelease is called ${msg});
})
hilog.info(DOMAIN_NUMBER, TAG, ‘remote caller register OnRelease succeed’);
// 注册caller的协同场景下跨设备组件状态变化监听通知
try {
caller.onRemoteStateChange((str) => {
hilog.info(DOMAIN_NUMBER, TAG, 'Remote state changed ’ + str);
});
} catch (error) {
hilog.info(DOMAIN_NUMBER, TAG, Caller.onRemoteStateChange catch error, error.code: ${JSON.stringify(error.code)}, error.message: ${JSON.stringify(error.message)});
};
}
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, get remote caller failed with ${error});
});
}
)
}
}


getRemoteDeviceId方法参照 通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据 。


5. 向被调用端UIAbility发送约定序列化数据。


	1. 向被调用端发送Parcelable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。



import UIAbility, { Caller } from ‘@ohos.app.ability.UIAbility’;
import type rpc from ‘@ohos.rpc’;

const MSG_SEND_METHOD: string = ‘CallSendMsg’;
class MyParcelable {
num: number = 0;
str: string = ‘’;

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

mySequenceable(num: number, string: 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;
};
};

export default class EntryAbility extends UIAbility {
// …
caller: Caller | undefined;
async onButtonCall(): Promise {
try {
let msg: MyParcelable = new MyParcelable(1, ‘origin_Msg’);
if (this.caller) {
await this.caller.call(MSG_SEND_METHOD, msg);
}
} catch (error) {
hilog.info(DOMAIN_NUMBER, TAG, caller call failed with ${error});
};
}
// …
}



  1. 如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据originMsg,并将’CallSendMsg’方法处理完毕的数据赋值给backMsg。


import UIAbility, { Caller } from ‘@ohos.app.ability.UIAbility’;
import rpc from ‘@ohos.rpc’;

const MSG_SEND_METHOD: string = ‘CallSendMsg’;
let originMsg: string = ‘’;
let backMsg: string = ‘’;

class MyParcelable {
num: number = 0;
str: string = ‘’;

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

mySequenceable(num: number, string: 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;
};
};

export default class EntryAbility extends UIAbility {
// …
caller: Caller | undefined;
async onButtonCallWithResult(originMsg: string, backMsg: string): Promise {
try {
let msg: MyParcelable = new MyParcelable(1, originMsg);
if (this.caller) {
const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg);
hilog.info(DOMAIN_NUMBER, TAG, ‘caller callWithResult succeed’);
let result: MyParcelable = new MyParcelable(0, ‘’);
data.readParcelable(result);
backMsg = result.str;
hilog.info(DOMAIN_NUMBER, TAG, caller result is [${result.num}, ${result.str}]);
}
} catch (error) {
hilog.info(DOMAIN_NUMBER, TAG, caller callWithResult failed with ${error});
};
}
// …
}


6. 释放Caller通信接口。 Caller不再使用后,应用开发者可以通过release接口释放Caller。



import UIAbility, { Caller } from ‘@ohos.app.ability.UIAbility’;

export default class EntryAbility extends UIAbility {
caller: Caller | undefined;
releaseCall(): void {
try {
if (this.caller) {
this.caller.release();
this.caller = undefined;
}
hilog.info(DOMAIN_NUMBER, TAG, ‘caller release succeed’);
} catch (error) {
hilog.info(DOMAIN_NUMBER, TAG, caller release failed with ${error});
};
}
}


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


### 《鸿蒙开发学习手册》:


**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/b1b8d13a060db54575c0cc1d9036fc4f.png)
![img](https://img-blog.csdnimg.cn/img_convert/b4a4fa44f0e185ca1f8526eeb3aff19e.png)
![img](https://img-blog.csdnimg.cn/img_convert/b7f9b19508437d88719182e3056bbb32.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**

**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)**
![img](https://img-blog.csdnimg.cn/img_convert/e5e6c0b7e424c41456ed9cc22f9228a9.png)

**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

页),希望对大家有所帮助:[`https://qr21.cn/FV7h05`]( )**


### 《鸿蒙开发学习手册》:


**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中...(img-YktMPDnV-1712844417395)]
[外链图片转存中...(img-Z8J140Lk-1712844417395)]
[外链图片转存中...(img-TQ8P4abF-1712844417396)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**

**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)**
[外链图片转存中...(img-700APRFH-1712844417396)]

**一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值