HarmonyOS 鸿蒙Next 物联网Iot开发-BLE设备鉴权

发布于 1周前 作者 gougou168 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 物联网Iot开发-BLE设备鉴权

前言

在鸿蒙系统(HarmonyOS)的广阔生态中,蓝牙作为一项基础且强大的无线连接技术,扮演着至关重要的角色。无论是智能家居设备的互联,还是健康监测手环的数据同步,都离不开蓝牙的支持。然而,在充分利用蓝牙功能之前,进行严格的权限检测是确保用户隐私安全、提升应用兼容性和用户体验的必要步骤。

首先,开发者需要确保目标设备支持蓝牙功能并且已经开启蓝牙开关。这可以通过鸿蒙系统提供的API接口进行查询,这里使用@kit.ConnectivityKit(蓝牙access模块)来检查设备是否开启蓝牙功能和订阅蓝牙设备开关状态事件,注意使用前需要配置权限:ohos.permission.ACCESS_BLUETOOTH

接下来,权限请求成为关键。在鸿蒙系统中,应用需要明确声明其所需的蓝牙权限,并在运行时向用户请求这些权限。并在用户首次使用蓝牙功能时,通过系统弹窗或应用内提示的方式请求用户授权。这一过程不仅是对用户隐私的尊重,也是遵守系统安全策略的重要体现。

获得用户授权后,应用才能开始执行蓝牙扫描、设备发现、连接与通信等操作。在这一过程中,鸿蒙系统还提供了丰富的API和工具,帮助开发者优化蓝牙连接的稳定性、降低功耗,并提升数据传输的效率。

综上所述,鸿蒙系统下的蓝牙使用权限检测是一个多环节、严要求的过程。它不仅关乎技术实现的细节,更体现了对用户隐私、系统安全和用户体验的高度重视。通过这一流程,鸿蒙系统为开发者提供了强大的蓝牙支持,也为用户带来了更加便捷、安全、高效的蓝牙体验。

蓝牙鉴权流程分析

在鸿蒙系统中,确保用户隐私和数据安全是首要任务之一,特别是在涉及蓝牙这样的敏感功能时。因此,核心点在于用户必须明确同意授权后,应用才能调用蓝牙相关的能力。以下是对这一流程的具体描述:

1. 初始状态检查

应用启动并准备使用蓝牙功能时,首先会检查用户是否已经授权蓝牙权限。这一步骤至关重要,因为它决定了应用是否有权进一步操作蓝牙设备。

  • 授权状态检查:通过鸿蒙系统提供的API接口,应用能够查询当前是否已经获得了蓝牙权限。

2. 授权情况处理

根据授权检查的结果,应用会采取不同的行动:

  • 已授权:如果应用已经获得了蓝牙权限,并且系统蓝牙功能也已打开,那么应用可以直接进入下一步操作,如扫描附近的蓝牙设备、建立连接等。

  • 未授权:如果应用尚未获得蓝牙权限,系统将自动调起权限请求界面,引导用户进行授权。

3. 权限请求与响应

在权限请求界面,用户有两个选择:同意或不同意。

  • 用户同意:如果用户选择同意授权,系统将允许应用访问蓝牙功能,并通知应用蓝牙权限已获取。此时,应用可以再次检查蓝牙功能是否已打开(因为有时用户可能关闭了蓝牙),如果蓝牙已打开,则进入下一步操作。

  • 用户不同意:如果用户选择不同意授权,系统将通知应用无法访问蓝牙功能。此时,应用应该给出明确的提示,告知用户由于未授权,无法进入下一步操作,并可能建议用户检查权限设置或联系技术支持。

蓝牙鉴权流程封装

接下来,根据鉴权流程分析,我们来做下流程的封装

新建鉴权模块单例

这里以翼康养老项目封装为例:

  1. 检查蓝牙授权方法
  2. 请求用户授权方法
  3. 检查蓝牙功能
class EcBlueAuth {
  checkBluePermission() {}
  reqUserPermission() {}
  isBlueOpen() {}
}

export const ecBlue = new EcBlueAuth()

检查蓝牙授权方法

  1. 获取应用信息
import bundleManager from '@ohos.bundle.bundleManager';
import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';

let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA;

try {
  bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => {
    hilog.info(0x0000, 'testTag', 'getBundleInfoForSelf successfully. Data: %{public}s', JSON.stringify(data));
  }).catch((err: BusinessError) => {
    hilog.error(0x0000, 'testTag', 'getBundleInfoForSelf failed. Cause: %{public}s', err.message);
  });
} catch (err) {
  let message = (err as BusinessError).message;
  hilog.error(0x0000, 'testTag', 'getBundleInfoForSelf failed: %{public}s', message);
}
  1. 调用检查授权方法
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let tokenID: number = 0; // 系统应用可以通过bundleManager.getApplicationInfo获取,普通应用可以通过bundleManager.getBundleInfoForSelf获取
let permissionName: Permissions = 'ohos.permission.GRANT_SENSITIVE_PERMISSIONS';
let data: abilityAccessCtrl.GrantStatus = atManager.checkAccessTokenSync(tokenID, permissionName);
console.log(`data->${JSON.stringify(data)}`);
  1. 获取授权信息

权限点:let permissionName: Permissions = ohos.permission.ACCESS_BLUETOOTH

async checkBluePermission() {
  let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA;
  try {
    // 1. 获取应用信息
    const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleFlags)
    // 2. 检查蓝牙权限
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // let tokenID: number = 0; // 系统应用可以通过bundleManager.getApplicationInfo获取,普通应用可以通过bundleManager.getBundleInfoForSelf获取
    let permissionName: Permissions = 'ohos.permission.ACCESS_BLUETOOTH';
    let data: abilityAccessCtrl.GrantStatus = atManager.checkAccessTokenSync(bundleInfo.appInfo.accessTokenId, permissionName);
    Log.info('蓝颜权限:' + data)
  } catch (err) {
    let message = (err as BusinessError).message;
    Log.error(message)
  }
}
  1. 授权页面使用
// 确认选择
Column() {
  Button('确认')
    .width(312)
    .backgroundColor(ResManager.EC_MAIN_COLOR)
    .onClick(() => {
      ecBlue.checkBluePermission()
    })
    .enabled(this.selectedProd ? true : false)
}
  1. 执行结果

返回-1说明未授权

请求用户蓝牙授权

  1. 校验授权信息
async checkBluePermission() {
  let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA;
  try {
    // 1. 获取应用信息
    const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleFlags)
    // 2. 检查蓝牙权限
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // let tokenID: number = 0; // 系统应用可以通过bundleManager.getApplicationInfo获取,普通应用可以通过bundleManager.getBundleInfoForSelf获取
    let permissionName: Permissions = 'ohos.permission.ACCESS_BLUETOOTH';
    let data: abilityAccessCtrl.GrantStatus = atManager.checkAccessTokenSync(bundleInfo.appInfo.accessTokenId, permissionName);
    Log.info('蓝牙权限:' + data)
    if(data === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
      this.reqUserPermission()
      return 
    }
  } catch (err) {
    let message = (err as BusinessError).message;
    Log.error(message)
  }
}
  1. 未授权情况:请求用户授权
import abilityAccessCtrl, { Context, PermissionRequestResult } from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
let context: Context = getContext(this) as common.UIAbilityContext;
atManager.requestPermissionsFromUser(context, ['ohos.permission.CAMERA'], (err: BusinessError, data: PermissionRequestResult) => {
  if (err) {
    console.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
  } else {
    console.info('data:' + JSON.stringify(data));
    console.info('data permissions:' + data.permissions);
    console.info('data authResults:' + data.authResults);
  }
});
reqUserPermission() {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
  let context: Context = getContext(this) as common.UIAbilityContext;
  atManager.requestPermissionsFromUser(context, ['ohos.permission.ACCESS_BLUETOOTH'],
  (err: BusinessError, data: PermissionRequestResult) => {
    if (err) {
      Log.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
    } else {
      Log.info('data:' + JSON.stringify(data));
      if (data.authResults[0] === 0) {
        AlertDialog.show({
          message: '已授权'
        })
      } else {
        // 未授权
        AlertDialog.show({
          message: '请前往系统页面授权蓝牙权限后,才能继续绑定操作!'
        })
      }
    }
  });
}

检查蓝牙功能开关

获取蓝牙开关状态。

需要权限:ohos.permission.ACCESS_BLUETOOTH 系统能力:SystemCapability.Communication.Bluetooth.Core

import { BusinessError } from '@ohos.base';
try {
    let state = access.getState();
} catch (err) {
    console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
  1. 配置蓝牙权限
"requestPermissions": [
  // ...
  {
    "name": "ohos.permission.ACCESS_BLUETOOTH",
    "reason": "$string:app_name",
    "usedScene": {
      "abilities": [ "EntryAbility" ],
      "when": "inuse"
    }
  }
]
  1. 封装蓝牙是否打开方法
isBlueOpen() {
  try {
    const state = access.getState()
    if (state === access.BluetoothState.STATE_ON) {
      return true
    } else {
      return false    
    }
  } catch (e) {
    Log.error('ble_demo_log' + e.message)
    return false
  }
}
  1. 鉴权使用
async checkBluePermission() {
  let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA;
  try {
    // 1. 获取应用信息
    const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleFlags)
    // 2. 检查蓝牙权限
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // let tokenID: number = 0; // 系统应用可以通过bundleManager.getApplicationInfo获取,普通应用可以通过bundleManager.getBundleInfoForSelf获取
    let permissionName: Permissions = 'ohos.permission.ACCESS_BLUETOOTH';
    let data: abilityAccessCtrl.GrantStatus = atManager.checkAccessTokenSync(bundleInfo.appInfo.accessTokenId, permissionName);
    Log.info('蓝牙权限:' + data)

    if (data === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
      // 未授权:请求用户授权
      this.reqUserPermission()
      return
    }

    if (!this.isBlueOpen()) {
      AlertDialog.show({ message: '请打开蓝牙开关再试!' })
      return
    }

    Log.warn('go')

  } catch (err) {
    let message = (err as BusinessError).message;
    Log.error(message)
  }
}
reqUserPermission() {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
  let context: Context = getContext(this) as common.UIAbilityContext;
  atManager.requestPermissionsFromUser(context, ['ohos.permission.ACCESS_BLUETOOTH'],
    (err: BusinessError, data: PermissionRequestResult) => {
      if (err) {
        Log.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
      } else {
        Log.info('data:' + JSON.stringify(data));
        if (data.authResults[0] === 0) {
          if(this.isBlueOpen()) {
            Log.info('go')
          }else {
            AlertDialog.show({ message: '请打开蓝牙开关再试!' })
          }
        } else {
          // 未授权
          AlertDialog.show({
            message: '请前往系统页面授权蓝牙权限后,才能继续绑定操作!'
          })
        }
      }
    });
}

鉴权通过操作封装

问题:如何满总条件后,执行特定逻辑?

  1. 检查授权和请求授权添加回调
async checkBluePermission(cb?: () => void) {
  // ...
  try {
    // 1. 获取应用信息
    const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleFlags)
    // 2. 检查蓝牙权限
    // ...

    if (data === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
      // 未授权:请求用户授权
      this.reqUserPermission(cb)
      return
    }

    if (!this.isBlueOpen()) {
      AlertDialog.show({ message: '请打开蓝牙开关再试!' })
      return
    }
    cb && cb()
    // Log.warn('go')
  } catch (err) {
    let message = (err as BusinessError).message;
    Log.error(message)
  }
}
reqUserPermission(cb?: () => void) {
  // ...
  (err: BusinessError, data: PermissionRequestResult) => {
    if (err) {
      Log.error(`requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
    } else {
      Log.info('data:' + JSON.stringify(data));
      if (data.authResults[0] === 0) {
        if (this.isBlueOpen()) {
          cb && cb()
          // Log.info('go')
        } else {
          AlertDialog.show({ message: '请打开蓝牙开关再试!' })
        }
      } else {
        // 未授权
        AlertDialog.show({
          message: '请前往系统页面授权蓝牙权限后,才能继续绑定操作!'
        })
      }
    }
  });
}

授权页面测试

// 2. 绑定
bindDevice() {
  ecBlue.checkBluePermission(() => {
    Log.info('鉴权通过!')
  })
}

总结

将鉴权流程封装成一个独立的模块或类,可以在不同的应用或项目中重复使用,减少了重复编码的工作量,提高了开发效率。当鉴权流程需要更新或修复时,只需修改封装好的模块或类即可,无需在每个使用到鉴权的应用或项目中都进行修改,从而降低了维护成本。

综上所述,蓝牙鉴权流程封装的好处是多方面的,它不仅能够提高安全性、提升用户体验,还便于复用和维护,促进标准化和规范化。这些好处使得蓝牙技术在各种应用场景中更加可靠、高效和易用。


更多关于HarmonyOS 鸿蒙Next 物联网Iot开发-BLE设备鉴权的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next 物联网Iot开发-BLE设备鉴权的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对帖子标题“HarmonyOS 鸿蒙Next 物联网Iot开发-BLE设备鉴权”的问题,以下是一个简洁的回答:

在HarmonyOS鸿蒙Next物联网(IoT)开发中,对于BLE(蓝牙低功耗)设备的鉴权,主要涉及到设备间的身份验证和数据加密。在鸿蒙系统中,可以通过以下方式实现BLE设备的鉴权:

  1. 配对与绑定:在BLE设备首次连接时,通过配对过程生成一个共享密钥。这个密钥用于后续通信中的数据加密和身份验证。

  2. 特征值读写权限:为BLE设备的特征值设置读写权限,只有经过鉴权的设备才能访问或修改这些特征值。

  3. 安全连接:使用蓝牙的安全连接功能(如LE Secure Connections),确保设备在连接过程中的数据传输是加密和安全的。

  4. 证书验证:对于需要更高安全性的应用,可以引入数字证书机制,对BLE设备进行身份验证,确保只有合法的设备才能接入系统。

在鸿蒙系统中,开发者可以利用系统提供的API和框架,方便地实现上述鉴权机制。如果开发者在开发过程中遇到具体问题,如API使用不当或功能实现上的疑问,可以参考鸿蒙系统的官方文档或开发指南。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部