多端协同流程如下图所示。
图1 多端协同流程图
由于“多端协同任务管理”能力尚未具备,开发者当前只能通过开发系统应用获取设备列表,不支持三方应用接入。
多端协同需遵循 分布式跨设备组件启动规则。
为了获得最佳体验,使用want传输的数据建议在100KB以下。
在设备A上通过发起端应用提供的启动按钮,启动设备B上指定的UIAbility与ServiceExtensionAbility。
表1 跨设备启动API接口功能介绍
接口名 | 描述 |
---|---|
startAbility(want: Want, callback: AsyncCallback): void; | 启动UIAbility和ServiceExtensionAbility(callback形式)。 |
stopServiceExtensionAbility(want: Want, callback: AsyncCallback): void; | 退出启动的ServiceExtensionAbility(callback形式)。 |
stopServiceExtensionAbility(want: Want): Promise; | 退出启动的ServiceExtensionAbility(Promise形式)。 |
import deviceManager from '@ohos.distributedDeviceManager';
import hilog from '@ohos.hilog';
const TAG: string = '[Page_CollaborateAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
let dmClass: deviceManager.DeviceManager;
function initDmClass(): void {
// 其中createDeviceManager接口为系统API
try {
dmClass = deviceManager.createDeviceManager('com.samples.stagemodelabilitydevelop');
hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass) ?? '');
} catch (err) {
hilog.error(DOMAIN_NUMBER, TAG, 'createDeviceManager err: ' + JSON.stringify(err));
};
}
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;
}
}
startAbility()
接口,启动UIAbility或ServiceExtensionAbility。import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';
import Want from '@ohos.app.ability.Want';
import deviceManager from '@ohos.distributedDeviceManager';
import common from '@ohos.app.ability.common';
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 Page_CollaborateAbility {
private context = getContext(this) as common.UIAbilityContext;
build() {
// ...
Button('startAbility')
.onClick(() => {
let want: Want = {
deviceId: getRemoteDeviceId(),
bundleName: 'com.samples.stagemodelabilityinteraction',
abilityName: 'CollaborateAbility',
moduleName: 'entry' // moduleName非必选
}
// context为发起端UIAbility的AbilityContext
this.context.startAbility(want).then(() => {
// ...
}).catch((err: BusinessError) => {
// ...
hilog.error(DOMAIN_NUMBER, TAG, `startAbility err: ` + JSON.stringify(err));
});
}
)
}
}
import Want from '@ohos.app.ability.Want';
import hilog from '@ohos.hilog';
import { BusinessError } from '@ohos.base';
import deviceManager from '@ohos.distributedDeviceManager';
import common from '@ohos.app.ability.common';
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 Page_CollaborateAbility {
private context = getContext(this) as common.UIAbilityContext;
build() {
// ...
Button('stopServiceExtensionAbility')
.onClick(() => {
let want: Want = {
deviceId: getRemoteDeviceId(),
bundleName: 'com.example.myapplication',
abilityName: 'FuncAbility',
moduleName: 'module1', // moduleName非必选
}
// 退出由startAbility接口启动的ServiceExtensionAbility
this.context.stopServiceExtensionAbility(want).then(() => {
console.info("stop service extension ability success")
}).catch((err: BusinessError) => {
console.info("stop service extension ability err is " + JSON.stringify(err))
})
})
}
}
在设备A上通过应用提供的启动按钮,启动设备B上指定的UIAbility,当设备B上的UIAbility退出后,会将返回值发回设备A上的发起端应用。
表2 跨设备启动,返回结果数据API接口功能描述
接口名 | 描述 |
---|---|
startAbilityForResult(want: Want, callback: AsyncCallback): void; | 启动UIAbility并在该Ability退出的时候返回执行结果(callback形式)。 |
terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback): void; | 停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(callback形式)。 |
terminateSelfWithResult(parameter: AbilityResult): Promise; | 停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(promise形式)。 |
需要申请ohos.permission.DISTRIBUTED_DATASYNC
权限,配置方式请参见 声明权限 。
同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。
在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。getRemoteDeviceId方法参照 通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据 。
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import { BusinessError } from '@ohos.base';
import Want from '@ohos.app.ability.Want';
import deviceManager from '@ohos.distributedDeviceManager';
const DOMAIN_NUMBER: number = 0xFF00;
const TAG: string = '[Page_CollaborateAbility]';
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));
})
}
)
}
}
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));
});
})
}
}
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) => {
// ...
})
}
)
}
}
系统应用可以通过 connectServiceExtensionAbility() 跨设备连接一个服务,实现跨设备远程调用。比如:分布式游戏场景,平板作为遥控器,智慧屏作为显示器。
表3 跨设备连接API接口功能介绍
接口名 | 描述 |
---|---|
connectServiceExtensionAbility(want: Want, options: ConnectOptions): number; | 连接ServiceExtensionAbility。 |
disconnectServiceExtensionAbility(connection: number, callback:AsyncCallback): void; | 断开连接(callback形式)。 |
disconnectServiceExtensionAbility(connection: number): Promise; | 断开连接(promise形式)。 |
需要申请ohos.permission.DISTRIBUTED_DATASYNC
权限,配置方式请参见 声明权限。
同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。
如果已有后台服务,请直接进入下一步;如果没有,则 实现一个后台服务(仅对系统应用开放) 。
连接一个后台服务。
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组件实现多端协同无返回数据 。
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调用实现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 | 注册通用组件通信断开监听通知。 |
需要申请ohos.permission.DISTRIBUTED_DATASYNC
权限,配置方式请参见 声明权限 。
同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。
创建被调用端UIAbility。 被调用端UIAbility需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。
配置UIAbility的启动模式。 配置module.json5,将CalleeAbility配置为单实例"singleton"。
Json字段 | 字段说明 |
---|---|
“launchType” | Ability的启动模式,设置为"singleton"类型。 |
UIAbility配置标签示例如下:
"abilities":[{
"name": ".CalleeAbility",
"srcEntry": "./ets/CalleeAbility/CalleeAbility.ts",
"launchType": "singleton",
"description": "$string:CalleeAbility_desc",
"icon": "$media:icon",
"label": "$string:CalleeAbility_label",
"exported": true
}]
import UIAbility from '@ohos.app.ability.UIAbility';
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;
};
};
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}`)
};
}
}
1.导入UIAbility模块。
import UIAbility from '@ohos.app.ability.UIAbility';
2.获取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组件实现多端协同无返回数据 。
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<void> {
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}`);
};
}
// ...
}
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<void> {
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}`);
};
}
// ...
}
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)学习路线与学习文档给大家用来跟着学习。
针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。
1.基本概念
2.构建第一个ArkTS应用
3.……
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……
搭建开发环境
系统架构分析