OpenHarmony分布式 启动远程设备的FA
Posted OpenHarmony技术社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenHarmony分布式 启动远程设备的FA相关的知识,希望对你有一定的参考价值。
目标
基于OpenHarmony提供的分布式能力,实现在同一个网络下拉起远程设备的Ability,本节主要分享分布式中最基础的能力,分布式拉起的实现
效果
环境
- 系统版本:OpenHarmony 3.1 release
- SDK:OpenHarmony API 8
- 设备:Hi3516
- IDE:DevEco Studio 3.0 Beta3
- PC:win10 64
前置条件
1、在Hi3616开发板上烧写OpenHarmony 3.1 release系统
2、准备两台烧录相同的版本系统的Hi3516DV300开发板A,B
3、两个开发板A,B配置在同一个WiFi网络之下。打开设置--\\>WLAN--\\>点击右侧WiFi开关--\\>点击目标WiFi并输入密钥。
分布式实现
以下内容是本地学习和整理的材料,如果有不对的地方请留言指正,谢谢。
流程图
流程说明
1、用户授权,分布式启动远程FA需要申请敏感权限:ohos.permission.DISTRIBUTED_DATASYNC,用户授权成功后才可以使用;
2、通过deviceManager.createDeviceManager()创建设备管理对象实例DeviceManager;
3、同步获取所有可信设备列表:deviceManager.getTrustedDeviceListSync();
4、启动发现设备:deviceManager.startDeviceDiscovery();
5、注册监听器:deviceManager.on()
- deviceStateChange:设备状态发生改变,比如上班上线、下线、状态同步完成
- deviceFound:发现设备
- discoverFail:发现设备失败
- serviceDie:服务停止
6、设备认证:deviceManager.authenticateDevice(),两台设备互联需要先建立认证,认证通过两台设备即为可信设备,可以进行一些分布式操作;
7、启动远端FA,featureAbility.startAbility(),其中featureAbility是@ohos.ability.featureAbility。
核心代码分析
分布式权限
权限声明
说明:需要申请的权限可以在config.json的module模块中进行声明。
module
"reqPermissions": [
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
]
权限申请
说明:敏感权限需要用户授权后才可以访问,本案例应用启动就需要申请,所以在index.js的onInit()方法中申请。
接口说明
AbilityContext.requestPermissionsFromUser(permissions: Array<string>, requestCallback: AsyncCallback<PermissionRequestResult>) : void;
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
permissions | Array<string> | 是 | 权限列表。 |
callback | AsyncCallback<PermissionRequestResult> | 是 | 回调函数,返回接口调用是否成功的结果。 |
参数:PermissionRequestResult
说明:权限请求结果。
备注:本模块首批接口从API 9开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
名称 | 参数类型 | 可读 | 可写 | 说明 |
---|---|---|---|---|
permissions | Array<string> | 是 | 否 | 用户传入的权限 |
authResults | Array<number> | 是 | 否 | 相应请求权限的结果。0表示授权成功,-1表示失败。 |
实现
grantPermission()
let context = featureAbility.getContext();
context.requestPermissionsFromUser(REQUEST_PERMISSION_LIST, REQUEST_PERMISSION_CODE, function(result)
console.log(request Permissions From User Result: + JSON.stringify(result));
// todo 判断是否授权
获取DeviceManager实例
说明:需要操作设备必须获取设备实例才可以=,ohos.distributedHardware.deviceManager中提供了创建的方法:createDeviceManager(bundleName: string, callback: AsyncCallback<DeviceManager>): void
备注:DeviceManager API
参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
bundleName | string | 是 | 指示应用程序的包名。 |
callback | AsyncCallback<DeviceManager> | 是 | DeviceManager实例创建时调用的回调,返回设备管理器对象实例。 |
实现
registerDeviceListCallback(callback)
if (typeof (this.#deviceManager) === undefined)
// 获取设备管理对象
let self = this;
deviceManager.createDeviceManager(com.nlas.myapplication,
(error, value) =>
if (error)
console.error(createDeviceManager failed.);
return;
self.#deviceManager = value;// 设备管理器对象实例
// 执行操作...
)
else
// 设备管理器对象已经存在,直接可以执行操作...
获取可信设备
说明:同步获取所有可信设备列表
deviceManager.getTrustedDeviceListSync(): Array<DeviceInfo>
参数说明
名称 | 说明 |
---|---|
Array<DeviceInfo> | 返回可信设备列表。 |
实现
// 同步获取所有可信设备列表
var list = this.#deviceManager.getTrustedDeviceListSync();
console.info([RemoteDeviceModel] deviceList= + JSON.stringify(list));
开始发现设备
接口:deviceManager.startDeviceDiscovery(subscribeInfo: SubscribeInfo):void
接口说明
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
subscribeInfo | SubscribeInfo | 是 | 设备发现的服务订阅信息 |
参数:SubscribeInfo
名称 | 参数 | 说明 |
---|---|---|
subscribeId | number | 服务订阅ID,取值范围为[0,65535],对于每个发现进程应该是唯一 |
mode | DiscoverMode | 服务订阅的发现方式, DISCOVER_MODE_PASSIVE = 0x55-》被动; DISCOVER_MODE_ACTIVE = 0xAA-》主动 |
medium | ExchangeMedium | 设备发现介质,AUTO-》自动选择;BLE-》蓝牙; COAP-》Wi-Fi;USE-》USB |
freq | ExchangeFreq | 服务订购频率 ,LOW=0; MID=1; HIGH=2;SUPER_HIGH=3 |
isSameAccount | boolean | 只能找到帐号相同的设备。 |
isWakeRemote | boolean | 是否发现休眠设备 |
capability | SubscribeCap | 订阅功能,设备发现能力,SUBSCRIBE_CAPABILITY_DDMP = 0;SUBSCRIBE_CAPABILITY_OSD = 1 |
实现
// 随机数
SUBSCRIBE_ID = Math.floor(65536 * Math.random());
var info =
subscribeId: SUBSCRIBE_ID,// 服务订阅ID【0~65535】,对每个发现进程来说应该是唯一的
mode: 0xAA,//主动模式
medium: 2,//订阅媒介 2-wifi
freq: 2,// 订阅频率 高
isSameAccount: false,// 只能找到帐号相同的设备
isWakeRemote: true,// 发现休眠设备
capability: 0
;
console.info([RemoteDeviceModel] startDeviceDiscovery + SUBSCRIBE_ID);
deviceManager.startDeviceDiscovery(info);// 发现设备
注册监听器
注册设备状态回调
关键字:deviceStateChange
接口:deviceManager.on(type: deviceStateChange, callback: Callback< action: DeviceStateChangeAction, device: DeviceInfo >): void
参数说明
参数名 | 参数类型 | 必填 | 说明 |
---|---|---|---|
type | string | 是 | 注册设备状态回调,固定为deviceStateChange。 |
callback | Callback< action: DeviceStateChangeAction, device: DeviceInfo > | 是 | 指示要注册的设备状态回调,返回设备状态和设备信息。 |
参数:DeviceStateChangeAction
说明:表示设备状态变化的枚举
名称 | 默认值 | 说明 |
---|---|---|
ONLINE | 0 | 设备上线。 |
READY | 1 | 设备就绪,设备信息同步已完成。 |
OFFLINE | 2 | 设备下线。 |
CHANGE | 3 | 设备信息更改。 |
参数:DeviceInfo
说明:设备信息
参数名 | 类型 | 必填 | 描述 |
---|---|---|---|
deviceId | number | 是 | 设备的唯一标识 |
deviceName | string | 是 | 设备名称 |
deviceType | number | 是 | 设备类型 |
networkId | string | 否 | 设备的网络ID,API8 |
参数:DeviceType
说明:表示设备类型的枚举类。
名称 | 默认值 | 说明 |
---|---|---|
SPEAKER | 0x0A | 智能音箱 |
PHONE | 0x0E | 手机 |
TABLET | 0x11 | 平板 |
WEARABLE | 0x6D | 智能穿戴 |
TV | 0x9C | 智慧屏 |
CAR | 0x83 | 车 |
UNKNOWN_TYPE | 0 | 未知设备 |
实现
deviceManager.on(DEVICE_STATE_CHANGE, (data) =>
console.info([RemoteDeviceModel] deviceStateChange data= + JSON.stringify(data));
if (data == null)
return;
switch (data.action)
case 0:
self.deviceList[self.deviceList.length] = data.device;
console.info([RemoteDeviceModel] online, updated device list= + JSON.stringify(self.deviceList));
self.callback();
if (self.authCallback != null)
self.authCallback();
self.authCallback = null;
break;
case 1:
if (self.deviceList.length > 0)
for (var i = 0; i < self.deviceList.length; i++)
if (self.deviceList[i].deviceId === data.device.deviceId)
self.deviceList[i] = data.device;
break;
console.info([RemoteDeviceModel] change, updated device list= + JSON.stringify(self.deviceList));
self.callback();
break;
case 2:
const count = self.deviceList.length;
if (count > 0)
var list = [];
for (var i = 0; i < count; i++)
if (self.deviceList[i].deviceId != data.device.deviceId)
list[i] = data.device;
self.deviceList = list;
console.info([RemoteDeviceModel] offline, updated device list= + JSON.stringify(data.device));
self.callback();
break;
default:
break;
);
反注册设备状态回调
说明:在不需要监听时需要取消注册的监听器,减少资源浪费。
接口:deviceManager.off(type: deviceStateChange, callback?: Callback< action:
DeviceStateChangeAction, device: DeviceInfo >): void;
实现
deviceManager.off(deviceStateChange);
注册发现设备回调
关键字:deviceFound
接口:deviceManager.on(type: deviceFound, callback: Callback< subscribeId: number, device:
DeviceInfo >): void;
参数说明
参数名 | 参数类型 | 必填 | 说明 |
---|---|---|---|
type | string | 是 | 注册发现设备回调,固定为deviceFound。 |
callback | Callback< subscribeId: number, device: DeviceInfo > | 是 | 发现要注册的设备回调。 |
实现
deviceManager.on(DEVICE_FOUND, (data) =>
console.info([RemoteDeviceModel] deviceFound data= + JSON.stringify(data));
if (data == null)
return;
const count = self.discoverList.length;
for (var i = 0; i < count; i++)
if (self.discoverList[i].deviceId === data.device.deviceId)
// 设备已经在列表中
return;
// 新增发现的设备
self.discoverList[count] = data.device;
self.callback();
);
反注册发现设备回调
说明:在不需要监听时需要取消注册的监听器,减少资源浪费。
接口:deviceManager.off(type: deviceFound, callback?: Callback< subscribeId: number, device:
DeviceInfo >): void;
实现
deviceManager.off(deviceFound);
设备认证
说明:认证指定的设备
接口:deviceManager.authenticateDevice(deviceInfo: DeviceInfo, authParam: AuthParam, callback:
AsyncCallback<deviceId: string, pinTone ?: number>): void;
参数说明
参数名 | 类型 | 说明 |
---|---|---|
deviceInfo | DeviceInfo | 设备信息,包括:deviceId、deviceName、deviceType |
authParam | AuthParam | 认证参数 |
callback | AsyncCallback | 认证回调 |
参数:AuthParam
参数名 | 类型 | 说明 |
---|---|---|
authType | number | 认证类型,1-》PIN码认证 |
extraInfo | object | 扩展信息 |
实现
authDevice(deviceId, callback)
console.info([RemoteDeviceModel] authDevice + deviceId);
for (var i = 0; i < this.discoverList.length; i++)
if (this.discoverList[i].deviceId === deviceId)
// 在线设备中存在此设备,创建扩展信息
let extraInfo =
"targetPkgName": com.nlas.myapplication,
"appName": demo,
"appDescription": demo application,
"business": 0
;
let authParam =
"authType": 1,// 认证类型,1为pin码。
"appIcon": ,
"appThumbnail": ,
"extraInfo": extraInfo // 扩展信息:key-value
;
console.info([RemoteDeviceModel] authenticateDevice + JSON.stringify(this.discoverList[i]));
this.authDeviceInfo = this.discoverList[i];
let self = this;
this.#deviceManager.authenticateDevice(this.authDeviceInfo, authParam, (err, data)=>
if (err)
console.info([RemoteDeviceModel] authenticateDevice failed, err= + JSON.stringify(err));
self.authCallback = null;
else
console.info([RemoteDeviceModel] authenticateDevice succeed, data= + JSON.stringify(data));
self.authCallback = callback;
)
启动远程设备上的FA
说明:通过@ohos.ability.featureAbility 提供的 startAbility() 接口启动远程的FA.
接口:featureAbility.startAbility(parameter: StartAbilityParameter): Promise<number>
参数说明
启动新的ability(Promise形式)。
参数名 | 类型 | 必填 | 描述 |
---|---|---|---|
parameter | StartAbilityParameter | 是 | 表示被启动的Ability |
参数:StartAbilityParameter
参数名 | 读写 | 类型 | 必填 | 描述 |
---|---|---|---|---|
want | 只读 | Want | 是 | 表示需要包含有关目标启动能力的信息。 |
abilityStartSetting | 只读 | [key: string]: any | 否 | 表示能力的特殊属性,当开发者启动能力时,该属性可以作为调用中的输入参数传递。 |
参数:Want
名称 | 读写属性 | 类型 | 必填 | 描述 |
---|---|---|---|---|
deviceId | 只读 | string | 否 | 表示运行指定Ability的设备ID。 |
bundleName | 只读 | string | 否 | 表示包描述。 |
abilityName | 只读 | string | 否 | 表示待启动的Ability名称。如果在Want中该字段同时指定了package和AbilityName,则Want可以直接匹配到指定的Ability。 |
uri | 只读 | string | 否 | 表示Uri描述。如果在Want中指定了Uri,则Want将匹配指定的Uri信息,包括scheme, schemeSpecificPart, authority和path信息。 |
type | 只读 | string | 否 | 表示MIME type类型描述,比如:"text/plain" 、 "image/*"等。 |
flags | 只读 | number | 否 | 表示处理Want的方式。默认传数字,具体参考:[flags说明] |
action | 只读 | string | 否 | 表示action选项描述。 |
parameters | 只读 | [key: string]: any | 否 | 表示WantParams描述。 |
entities | 只读 | Array\\<string> | 否 | 表示entities相关描述。 |
extensionAbilityName<sup>9+<sup> | 只读 | string | 否 | Want中扩展能力名称的描述。 |
extensionAbilityType<sup>9+<sup> | 只读 | number | 否 | Want中扩展能力类型的描述。 |
参数:flags说明
名称 | 参数 | 描述 |
---|---|---|
FLAG_AUTH_READ_URI_PERMISSION | 0x00000001 | 指示对URI执行读取操作的授权。 |
FLAG_AUTH_WRITE_URI_PERMISSION | 0x00000002 | 指示对URI执行写入操作的授权。 |
FLAG_ABILITY_FORWARD_RESULT | 0x00000004 | 将结果返回给元能力。 |
FLAG_ABILITY_CONTINUATION | 0x00000008 | 确定是否可以将本地设备上的功能迁移到远程设备。 |
FLAG_NOT_OHOS_COMPONENT | 0x00000010 | 指定组件是否属于OHOS。 |
FLAG_ABILITY_FORM_ENABLED | 0x00000020 | 指定是否启动某个能力。 |
FLAG_AUTH_PERSISTABLE_URI_PERMISSION | 0x00000040 | 指示URI上可能持久化的授权。 |
FLAG_AUTH_PREFIX_URI_PERMISSION | 0x00000080 | 按照前缀匹配的方式验证URI权限。 |
FLAG_ABILITYSLICE_MULTI_DEVICE | 0x00000100 | 支持分布式调度系统中的多设备启动。 |
FLAG_START_FOREGROUND_ABILITY | 0x00000200 | 指示无论主机应用程序是否已启动,都将启动使用服务模板的功能。 |
FLAG_ABILITY_CONTINUATION_REVERSIBLE | 0x00000400 | 表示迁移是可拉回的。 |
FLAG_INSTALL_ON_DEMAND | 0x00000800 | 如果未安装指定的功能,请安装该功能。 |
FLAG_INSTALL_WITH_BACKGROUND_MODE | 0x80000000 | 如果未安装,使用后台模式安装该功能。 |
FLAG_ABILITY_CLEAR_MISSION | 0x00008000 | 指示清除其他任务的操作。可以为传递给 ohos.app.Context 中startAbility方法的Want设置此标志,并且必须与flag_ABILITY_NEW_MISSION一起使用。 |
FLAG_ABILITY_NEW_MISSION | 0x10000000 | 指示在历史任务堆栈上创建任务的操作。 |
FLAG_ABILITY_MISSION_TOP | 0x20000000 | 指示如果启动能力的现有实例已位于任务堆栈的顶部,则将重用该实例。否则,将创建一个新的能力实例。 |
实现
startAbilityContinuation(deviceId, deviceName)
this.$element(continueAbilityDialog).close();
console.info(featureAbility.startAbility deviceId= + deviceId
+ deviceName= + deviceName);
const wantValue =
bundleName: com.nlas.myapplication,
abilityName: com.nlas.myapplication.MainAbility,
deviceId: deviceId
;
featureAbility.startAbility(
want: wantValue
).then((data) =>
console.info(featureAbility.startAbility finished, + JSON.stringify(data));
);
console.info(featureAbility.startAbility want= + JSON.stringify(wantValue));
,
到此为止,OpenHarmony分布式调度启动远程FA的实现,如果有地方介绍有错误请指正。
完整代码
请在文章末尾下载。
感谢
如果您能看到最后,还希望您能动动手指点个赞,一个人能走多远关键在于与谁同行,我用跨越山海的一路相伴,希望得到您的点赞。
附件链接:https://ost.51cto.com/resource/1883
::: hljs-center
:::
以上是关于OpenHarmony分布式 启动远程设备的FA的主要内容,如果未能解决你的问题,请参考以下文章
v75.01 鸿蒙内核源码分析(远程登录) | 内核如何接待远方的客人 | 百篇博客分析OpenHarmony源码