OpenHarmony(鸿蒙开发篇)多设备分布式组网认证规范

 鸿蒙HarmonyOS开发实战往期必看文章:(持续更新......)

一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!

HarmonyOS NEXT应用开发(5.0版)高频场景解决方案分享(1-100篇)持续更新中~

HarmonyOS NEXT应用开发性能实践总结(持续更新......)

HarmonyOS NEXT应用开发案例实践总结合集(持续更新......)


前提

安装好 DevEco Studio,新建项目,选择 API9 版本,stage 模型

点击 Finish,此时,咱们的 API9 项目就算创建成功啦~

替换 Full-SDK

参考 OpenAtom OpenHarmony

必要权限

ohos.permission.DISTRIBUTED_DATASYNC

允许不同设备间的数据交换。

权限级别:normal

授权方式:user_grant

ACL 使能:TRUE

ohos.permission.DISTRIBUTED_SOFTBUS_CENTER

允许不同设备之间进行组网处理。

权限级别:system_basic

授权方式:system_grant

ACL 使能:FALSE

权限申明

首先,在项目的模块级目录下找到并打开 module.json5 文件,在 module 下的对象里添加如下申明:

"requestPermissions": [
  {
    "name": "ohos.permission.DISTRIBUTED_DATASYNC",
    "reason": "$string:DataSync",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
    }
  },
  {
    "name": "ohos.permission.DISTRIBUTED_SOFTBUS_CENTER"
  }
]

此时,配置文件中的权限申明就完成了,但是,此时我们还不能获得这些权限。由于 ohos.permission.DISTRIBUTED_DATASYNC 权限是 ACL 使能为 TRUE 的权限,咱们需要在签名工具文件中说明一下。如何找到对应的签名工具文件呢?我们在安装 DevEco Studio 的时候是下载好了 OpenHarmony 的 SDK 的,此时在 OpenHarmony 文件夹中,打开 “你的 SDK 版本\toolchains\lib” 该路径,此时在 lib 文件夹中,咱们可以找到两个 json 文件,分别为 UnsgnedDebugProfileTemplate.json 和 UnsgnedReleasedProfileTemplate.json,点击并打开这两个文件,添加如下权限:

"acls":{

​ "allowed-acls":[

​ "ohos.permission.DISTRIBUTED_DATASYNC"

​ ]

}

此时咱们不着急关闭这两个文件,因为在我们申请的权限中,有一个权限是允许我们使用系统能力的,也就是说,我们申请的这个权限是一个系统权限,

ohos.permission.DISTRIBUTED_SOFTBUS_CENTER 是一个系统权限,其权限级别为 system_basic,授权方式为 system_grant,此时,咱们需要再次修改刚刚打开的文件,找到"bundle-info"标签,修改“apl”标签内容和“app-feature”标签内容如下:

"apl":"system_basic",

"app-feature":"hos_system_app"

OK,接下来开始编码了

在申请 ohos.permission.DISTRIBUTED_DATASYNC 权限时,其文档中将其标注为用户手动授权的权限,此时需要我们动态申请权限,在项目中,我们新建一个 ets 文件,我这里取名为 RequestPermission.ets

首先,导入以下包:

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
import common from '@ohos.app.ability.common';

获取访问控制模块对象实例:

let atManager = abilityAccessCtrl.createAtManager();

编写如下方法(这里我使用的是异步函数):

export async function checkAccessTokenID(permission: Array<Permissions>) {
  // 获取应用程序的accessTokenID
  let tokenId: number;
  let grantStatus: Array<abilityAccessCtrl.GrantStatus> = []
  try {
    let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    tokenId = appInfo.accessTokenId;
  } catch (err) {
    console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);
  }
  // 校验应用是否被授予权限,若申请多个权限,建议循环检查多个权限
  for (let index = 0;index < permission.length; index++) {
    try {
      grantStatus.push(await atManager.checkAccessToken(tokenId, permission[index]))
    } catch (err) {
      console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);
    }
  }
  return grantStatus;
}

export async function checkPermission(context: common.UIAbilityContext, permissions: Array<Permissions>) {
  let grantStatus: Array<abilityAccessCtrl.GrantStatus> = await checkAccessTokenID(permissions)
  for (let i = 0; i < grantStatus.length; i++) {
    if (grantStatus[i] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      console.info(`${permissions[i].toString()} 已授权`)
    } else {
      //申请权限
      console.info('开始向用户申请权限')
      requestPermissionFromUser(context, permissions)
    }
  }
}

export async function requestPermissionFromUser(context: common.UIAbilityContext, permissions: Array<Permissions>) {
  // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults
    let length: number = grantStatus.length
    for (let i = 0;i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
        console.info(`${permissions[i].toString()} 权限申请成功`)
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        console.info(`${permissions[i].toString()} 权限申请被用户拒绝`)
      }
    }
    // 授权成功
  })
}

此时,我们申请权限的方法就算编写完成了,在应用入口,即 EntryAbility.ts 文件中的 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam)方法中回调权限申请函数:

requestPermissionFromUser(this.context, PERMISSIONS)

其中,PERMISSIONS 定义如下:

const PERMISSIONS: Array<Permissions> = ['ohos.permission.DISTRIBUTED_DATASYNC']

到此,我们的权限申请就算完完全全完成啦,当用户第一次安装并打开应用的时候,应用会向用户通过弹窗形式申请权限,用户点击授权即可赋予应用相应的权限啦~

多设备组网认证

在开始编码之前,新建一个 ets 文件,我给它命名为 DistributedDeviceManagerFunctions.ets

首先,导入所需包:

import deviceManager from '@ohos.distributedHardware.deviceManager'

由于咱们多设备组网认证功能中需要使用到一些共享对象,所以我的设计方法是设计一个类,并将方法和对象封装到该类中,方便调用:

export class DistributedDeviceManageFunc {
  
}

定义类中对象:

static mDeviceManager: deviceManager.DeviceManager
static subscribeId: number
static publishId: number
static distributedDeviceList: Array<deviceManager.DeviceInfo> = []

初始化类

static init() {
  deviceManager.createDeviceManager(globalThis.context.abilityInfo.bundleName, (error, data) => {
    if (error) {
      console.error(`create device manager failed,error:${JSON.stringify(error)}`)
      return
    }
    this.mDeviceManager = data
    console.info('create device manager successfully')
    try {
      this.publishId = Math.floor(Math.random() * 10000 + 1000)
      data.publishDeviceDiscovery({
        publishId: this.publishId,
        mode: deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
        freq: deviceManager.ExchangeFreq.HIGH,
        ranging: false
      })
      console.info('publishDeviceDiscovery successfully')
    } catch (error) {
      console.error(`publishDeviceDiscovery failed,error:${JSON.stringify(error)}`)
    }
    try {
      data.on('publishSuccess', (data) => {
        console.info("publishSuccess:" + JSON.stringify(data))
      })
      console.info('publishSuccess on successfully')
    } catch (error) {
      console.error(`publishSuccess failed,error:${JSON.stringify(error)}`)
    }
    try {
      data.on('publishFail', (error) => {
        console.info("publishFail on:" + JSON.stringify(error))
      })
      console.info('publishFail on successfully')
    } catch (error) {
      console.error(`publishFail failed,error:${JSON.stringify(error)}`)
    }
    try {
      data.on('deviceStateChange', (data) => {
        console.info("deviceStateChange on:" + JSON.stringify(data))
        if (data.action == deviceManager.DeviceStateChangeAction.READY) {
          AppStorage.Set('statusColor', '#ff4fc100')
        } else if (data.action == deviceManager.DeviceStateChangeAction.OFFLINE) {
          AppStorage.Set('statusColor', '#ffff0000')
        } else if (data.action == deviceManager.DeviceStateChangeAction.ONLINE) {
          AppStorage.Set('statusColor', '#ffffd500')
        }
      })
      console.info('deviceStateChange on successfully')
    } catch (error) {
      console.error(`deviceStateChange failed,error:${JSON.stringify(error)}`)
    }
  })
}

在该方法中,我们通过 createDeviceManager(bundleName: string, callback: AsyncCallback): void 函数创建了一个设备管理器实例,并将回调函数中得到的 DeviceManager 对象传递给先前定义的 mDeviceManager.

以上操作完成后,使用 publishDeviceDiscovery(publishInfo: PublishInfo): void 函数发布周边设备发现,即调用该函数,主设备可以主动让周边(同一网络环境下)的设备发现识别:

try {
  this.publishId = Math.floor(Math.random() * 10000 + 1000)
  data.publishDeviceDiscovery({
    publishId: this.publishId,
    mode: deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
    freq: deviceManager.ExchangeFreq.HIGH,
    ranging: false
  })
  console.info('publishDeviceDiscovery successfully')
} catch (error) {
  console.error(`publishDeviceDiscovery failed,error:${JSON.stringify(error)}`)
}

注册设备状态回调,当设备状态发生改变时,可以通过 on(type: ‘deviceStateChange’, callback: Callback<{ action: DeviceStateChangeAction, device: DeviceInfo }>): void 获取设备状态改变后的第一状态:

try {
  data.on('deviceStateChange', (data) => {
    console.info("deviceStateChange on:" + JSON.stringify(data))
    if (data.action == deviceManager.DeviceStateChangeAction.READY) {
      AppStorage.Set('statusColor', '#ff4fc100')
    } else if (data.action == deviceManager.DeviceStateChangeAction.OFFLINE) {
      AppStorage.Set('statusColor', '#ffff0000')
    } else if (data.action == deviceManager.DeviceStateChangeAction.ONLINE) {
      AppStorage.Set('statusColor', '#ffffd500')
    }
  })
  console.info('deviceStateChange on successfully')
} catch (error) {
  console.error(`deviceStateChange failed,error:${JSON.stringify(error)}`)
}

开始发现周边设备

使用 startDeviceDiscovery(subscribeInfo: SubscribeInfo, filterOptions?: string): void 函数可以使本设备暂时具有发现周边发布设备发现的设备的能力,即本设备可以识别周边设备:

static startDeviceDiscovery() {
  try {
    this.subscribeId = Math.floor(Math.random() * 10000 + 1000)
    this.mDeviceManager.startDeviceDiscovery({
      subscribeId: this.subscribeId,
      mode: deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
      medium: deviceManager.ExchangeMedium.AUTO,
      freq: deviceManager.ExchangeFreq.HIGH,
      isWakeRemote: false,
      isSameAccount: false,
      capability: deviceManager.SubscribeCap.SUBSCRIBE_CAPABILITY_OSD
    })
    this.mDeviceManager.on('deviceFound', (data) => {
      console.info('device found')
      console.info("deviceFound:" + JSON.stringify(data))
      this.distributedDeviceList = []
      if (this.distributedDeviceList.length == 0) {
        this.distributedDeviceList.push(data.device)
        AppStorage.Set('distributedDeviceList', this.distributedDeviceList)
      } else {
        var length = 0
        this.distributedDeviceList.forEach(element => {
          if (element.deviceId == data.device.deviceId) {
            return
          }
          length++
        })
        if (length == this.length) {
          this.distributedDeviceList.push(data.device)
          AppStorage.Set('distributedDeviceList', this.distributedDeviceList)
        }
      }
    })
  } catch (error) {
    console.error(`startDeviceDiscovery failed,error:${JSON.stringify(error)}`)
  }
}

在该函数中,我们注册发现设备回调监听,当周边有可认证设备被发现时,该回调函数会返回 DeviceInfo 类型的对象,其中为发现设备的部分设备信息:

this.mDeviceManager.on('deviceFound', (data) => {
  console.info('device found')
  console.info("deviceFound:" + JSON.stringify(data))
  this.distributedDeviceList = []
  if (this.distributedDeviceList.length == 0) {
    this.distributedDeviceList.push(data.device)
    AppStorage.Set('distributedDeviceList', this.distributedDeviceList)
  } else {
    var length = 0
    this.distributedDeviceList.forEach(element => {
      if (element.deviceId == data.device.deviceId) {
        return
      }
      length++
    })
    if (length == this.length) {
      this.distributedDeviceList.push(data.device)
      AppStorage.Set('distributedDeviceList', this.distributedDeviceList)
    }
  }
})

获取设备认证

在 authenticateDevice(deviceInfo: DeviceInfo, authParam: AuthParam, callback: AsyncCallback<{deviceId: string, pinToken ?: number}>): void 函数中,我们将所需配对的设备信息(DeviceInfo 类型)作为参数传入即可触发设备认证,当两个设备没有相互认证时,回调该函数,对端设备上会弹出 PIN 码,在请求认证设备(本设备)中输入对端设备生成的 PIN 码即可完成设备认证

static authenticateDevice(deviceInformation: deviceManager.DeviceInfo) {
  try {
    this.mDeviceManager.authenticateDevice(deviceInformation, {
      authType: 1,
      extraInfo: undefined
    }, (error, data) => {
      if (error) {
        console.error("authenticateDevice error:" + JSON.stringify(error))
        return
      }
      console.info("authenticateDevice result:" + JSON.stringify(data))
    })
  } catch (error) {
    console.error(`authenticateDevice error:${JSON.stringify(error)}`)
  }
}

终止发现周边设备

static stopDeviceDiscovery() {
  try {
    this.mDeviceManager.stopDeviceDiscovery(this.subscribeId)
  } catch (error) {
    console.error(`stopDeviceDiscovery failed,error:${JSON.stringify(error)}`)
  }
}

获取可信任设备列表

当多个设备间完成相互认证时,调用该方法会获取完成认证的设备列表(deviceManager.DeviceInfo[]):

static getTrustedDeviceListSync() {
  return this.mDeviceManager.getTrustedDeviceListSync()
}

解除设备认证

static unAuthenticateDevice(deviceInformation: deviceManager.DeviceInfo) {
  this.mDeviceManager.unAuthenticateDevice(deviceInformation)
}

释放资源

static release() {
  this.mDeviceManager.release()
}

以上便是 openHarmony 中的多设备分布式组网认证过程,怎么样,你 get 到了吗 <_>

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线图、学习视频、文档用来跟着学习是非常有必要的。 

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记  希望这一份鸿蒙学习文档能够给大家带来帮助~

这份鸿蒙(HarmonyOS NEXT)包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值