HarmonyOS 鸿蒙Next Flutter对接 如何判断App是否有蓝牙权限

发布于 1周前 作者 nodeper 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next Flutter对接 如何判断App是否有蓝牙权限

Flutter对接鸿蒙:如何判断App是否有蓝牙权限

2 回复

可以通过flutter 调用鸿蒙原生实现 也可以直接使用flutter里面的插件来实现

utils:

import { abilityAccessCtrl, bundleManager, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';

import { BusinessError } from '@kit.BasicServicesKit';

/**

 * 权限管理工具类

 * 能力:检查权限是否已存在、请求用户授权

 */

class PermissionsUtil {

  /**

   * 校验应用是否被授予定位权限

   * @param permissions

   * @returns

   */

  async checkPermissions(permissions: Array<Permissions>): Promise<void> {

    let applyResult: boolean = false;

    for (let permission of permissions) {

      let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permission);

      if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {

        applyResult = true;

      } else {

        applyResult = false;

      }

    }

    if (!applyResult) {

      this.requestPermissions(permissions);

    }

  }

  async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {

    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

    // 获取应用程序的accessTokenID

    let tokenId: number = 0;

    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 (error) {

      let err: BusinessError = error as BusinessError;

      console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);

    }

    // 校验应用是否被授予权限

    try {

      grantStatus = await atManager.checkAccessToken(tokenId, permission);

    } catch (error) {

      let err: BusinessError = error as BusinessError;

      console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);

    }

    return grantStatus;

  }

  /**

   * 申请用户授权

   * @param permissions

   */

  requestPermissions(permissions: Array<Permissions>): void {

    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    atManager.requestPermissionsFromUser(getContext() as common.UIAbilityContext, permissions)

      .then((data: PermissionRequestResult) => {

        console.info('request Permissions success')

      })

      .catch((err: BusinessError) => {

        console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);

      })

  }

}

export default new PermissionsUtil();

Index.ets:

import PermissionsUtil from '../utils/PermissionsUtil'

aboutToAppear(): void {

  PermissionsUtil.requestPermissions(['ohos.permission.ACCESS_BLUETOOTH'])

}

https://gitee.com/openharmony-sig/flutter_permission_handler

import { BusinessError } from '@ohos.base';
import access from '@ohos.bluetooth.access';
import ble from '@ohos.bluetooth.ble';
import _ from '@wolfx/lodash'
import { CommonUtil, KeyConstants, Logger } from '@ohos/utils';
import { LinkDevicesConstants } from '../constants/LinkDevicesConstants';
import { BlePackInfoModel, BleKeyInfoModel, BleWlanInfoModel, BleInfoModel } from '../model/BleInfoModel'
import { StrUtil } from '@pura/harmony-utils';
import { ApiKey, ApiVerify, HttpRequest, BindDevRequestData, BindDevResultData } from '@ohos/network';
const TAG = '[BLUE]'
type Callback = (result?: Array<ble.ScanResult>) => void;
export class ScanBleInfo {
  private static instance: ScanBleInfo;
  private result: Array<ble.ScanResult> = [];
  private resultTmp: Array<ble.ScanResult> = [];
  private resultOnlyMid: Array<string> = [];
  private callbackArray ?: Array<Callback | undefined>;
  private lastTime = 0;
  private static blueServiceUUID = "0000FD06-173C-93D2-488E-FE144D2E12A2";
  private static blueServiceWriteUUID = "FD03";
  private static blueServiceReadUUID = "FD04";
  private bleKey = '';
  // private rest: HomeItem = {}
  private constructor() {
  }
  /**
   * 订阅BLE设备发现上报事件回调函数,用户获取BLE信息
   * @param data
   */
  onReceiveEvent = (data: Array<ble.ScanResult>) => {
    this.resultTmp = this.resultTmp ? [...this.resultTmp, ...data] : data
    this.resultTmp = Array.from(new Set(this.resultTmp))
    if (new Date().getTime() - this.lastTime > 500) {
      this.lastTime = new Date().getTime();
      ScanBleInfo.getInstance().filterBlueDevice(this.resultTmp)
    }
  }
  /**
   * 获取 ScanBleInfo 单例实例
   * @returns ScanBleInfo
   */
  public static getInstance(): ScanBleInfo {
    if (!ScanBleInfo.instance) {
      ScanBleInfo.instance = new ScanBleInfo();
    }
    return ScanBleInfo.instance;
  }
  /**
   * 获取蓝牙状态
   * @returns BluetoothState
   */
  public getBleStatus(): access.BluetoothState {
    try {
      let state = access.getState();
      return state
    } catch (err) {
      Logger.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
      return err
    }
  }
  /**
   * 开启蓝牙
   */
  public openBle() {
    try {
      access.enableBluetooth();
    } catch (err) {
      Logger.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
  /**
   * 发起BLE扫描流程
   */
  public startBluetoothDiscovery() {
    let scanOptions: ble.ScanOptions = {
      interval: 1000 //扫描间隔时间
    }
    const bleStatus = this.getBleStatus()
    Logger.info(TAG, 'bleStatus: ' + bleStatus)
    if (bleStatus !== 2) {
      this.openBle()
      this.startBluetoothDiscovery()
    } else {
      ble.startBLEScan(null, scanOptions);
      ble.on("BLEDeviceFind", this.onReceiveEvent);
    }
  }
  setCallback(callback: Callback) {
    // this.callbackArray?.push(callback)
    if (this.callbackArray) {
      this.callbackArray.push(callback);
    } else {
      // 如果 callbackArray 未初始化,则初始化
      this.callbackArray = [callback];
    }
  }
  /**
   * 停止BLE扫描流程
   */
  public stopBluetoothDiscovery() {
    try {
      ble.stopBLEScan();
    } catch (err) {
      Logger.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
  /**
   * 过滤蓝牙热点
   * @param bleData
   * @param callback
   */
  public filterBlueDevice = (bleData: Array<ble.ScanResult>) => {
    const lastResult = [...this.result]
    bleData.forEach((scanResult) => {
      const bit7: number = scanResult.data[7];
      const bit8: number = scanResult.data[8];
      if (scanResult?.deviceName.includes('GR-') && bit7 == 0 && bit8 == 0) {
        Logger.info(TAG, 'scanResult data: ' + JSON.stringify(scanResult))
        const sameMacDeviceIndex = _.findIndex(this.result, o => {
          return o.deviceId == scanResult.deviceId
        })
        if (sameMacDeviceIndex != -1) {
          this.result[sameMacDeviceIndex] = scanResult;
          this.resultOnlyMid[sameMacDeviceIndex] = scanResult.deviceName
        } else {
          this.result.push(scanResult);
          this.resultOnlyMid.push(scanResult.deviceName)
        }
        Logger.info(TAG, 'result data: ' + JSON.stringify(this.result))
      } else {
      }
    })
    Logger.info(TAG, 'return----result: ' + JSON.stringify(this.result))
    this.callbackArray?.forEach((callback) => {
      Logger.info(TAG, 'filterBlueDevice callback = ' + callback)
      if (callback != undefined) {
        if (lastResult.length != this.result.length) {
          callback(this.result)
        } else {
          // const lastResultWithoutKey = _.omit(lastResult, 'rssi');
          // const othValueWithoutKey = _.omit(this.result, 'rssi');
          // console.log('排除信号强度:', JSON.stringify(objValueWithoutKey), JSON.stringify(othValueWithoutKey))
          // if (!_.isEqual(objValueWithoutKey, othValueWithoutKey)) {
          //   callback(this.result)
          // }
        }
      }
    })
    // AppStorage.setOrCreate('BleDevicesList', this.result)
    // AppStorage.setOrCreate('BleDevicesMidList', this.resultOnlyMid)
  }
  /**
   * 连接设备
   * @param deviceId
   * @param devMac
   * @param homeId
   */
  public connectionDevice(deviceId: string, devMac: string, homeId: number) {
    try {
      let gattClient: ble.GattClientDevice = ble.createGattClientDevice(deviceId);
      gattClient.connect();
      // 监听蓝牙连接状态
      gattClient.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
        let connectState: ble.ProfileConnectionState = state.state;
        if (connectState == 2) {
          // 蓝牙连接成功后获取服务
          gattClient.getServices()
            .then((gattServices: Array<ble.GattService>) => {
              let services: Array<ble.GattService> = gattServices;
              for (const service of services) {
                if (service.serviceUuid == ScanBleInfo.blueServiceUUID) {
                  this.BLECharacteristicListener(gattClient, devMac, homeId)
                }
              }
            })
            .catch((err: BusinessError) => {
              Logger.info(TAG, 'getBleServes :' + err)
            })
        }
      });
      // 断开蓝牙来连接
      gattClient.disconnect()
    } catch (err) {
      console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
    }
  }
  /**
   * 设置蓝牙特征值监听器
   * @param gattClient
   * @param devMac
   * @param homeId
   */
  BLECharacteristicListener = (gattClient: ble.GattClientDevice, devMac: string, homeId: number) => {
    let arrayBufferC = new ArrayBuffer(8);
    let characteristicChange: ble.BLECharacteristic = {
      serviceUuid: ScanBleInfo.blueServiceUUID,
      characteristicUuid: '0000FD04-0000-1000-8000-00805F9B34FB',
      characteristicValue: arrayBufferC,
      descriptors: []
    }
    gattClient.setCharacteristicChangeNotification(characteristicChange, true, (code: BusinessError) => {
      if (code == null) {
        this.sendBleBindPack(gattClient, devMac)
        // 监听特征值变化
        gattClient.on('BLECharacteristicChange', (characteristicChangeReq: ble.BLECharacteristic) => {
          let serviceUuid: string = characteristicChangeReq.serviceUuid;
          let characteristicUuid: string = characteristicChangeReq.characteristicUuid;
          let value: Uint8Array = new Uint8Array(characteristicChangeReq.characteristicValue);
          const valueJson: BlePackInfoModel = JSON.parse(StrUtil.bufferToStr(value))
          if (valueJson.pIn == 1) {
            this.sendBleWlanPack(gattClient, valueJson)
          } else if (valueJson.pIn == 2) {
            this.bindDevsToCloud(valueJson, homeId)
          }
        });
      }
    });
    // 移除监听器
    gattClient.off('BLECharacteristicChange');
  }
  /**
   * 发送bind包
   * @param gattClient
   * @param devMac
   */
  sendBleBindPack(gattClient: ble.GattClientDevice, devMac: string) {
    const bindAes = CommonUtil.encryptAES(JSON.stringify({
      t: 'bind',
      mac: devMac
    }), KeyConstants.WIFI_PUBLIC_SECRET_KEY);
    const bindPack: BlePackInfoModel = {
      t: 'pack',
      i: 1,
      pIn: 1,
      uid: '0',
      pack: bindAes
    }
    const bindBuff = StrUtil.strToBuffer(JSON.stringify(bindPack))
    let characteristic: ble.BLECharacteristic = {
      serviceUuid: ScanBleInfo.blueServiceUUID,
      characteristicUuid: '0000FD03-0000-1000-8000-00805F9B34FB',
      characteristicValue: bindBuff,
      descriptors: []
    };
    gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (code: BusinessError) => {
      if (code != null) {
        return;
      }
      console.log('bluetooth writeCharacteristicValue success');
    });
  }
  /**
   * 发送wlan包
   * @param gattClient
   * @param valueJson
   */
  sendBleWlanPack = (gattClient: ble.GattClientDevice, valueJson: BlePackInfoModel) => {
    const bleKeyDecryptAES: BleKeyInfoModel =
      JSON.parse(CommonUtil.decryptAES(valueJson.pack, KeyConstants.WIFI_PUBLIC_SECRET_KEY))
    this.bleKey = bleKeyDecryptAES.key
    const wlan: BleWlanInfoModel = {
      t: 'wlan',
      host: 'dis.xxx.com',
      psw: 'xxxxx',
      ssid: 'LYKJ-2'
    }
    const wlanAes = CommonUtil.encryptAES(JSON.stringify(wlan), bleKeyDecryptAES.key);
    const wlanPack: BlePackInfoModel = {
      t: 'pack',
      i: 0,
      pIn: 2,
      uid: '0',
      pack: wlanAes
    }
    const wlanBuff = StrUtil.strToBuffer(JSON.stringify(wlanPack))
    let characteristic: ble.BLECharacteristic = {
      serviceUuid: ScanBleInfo.blueServiceUUID,
      characteristicUuid: '0000XX03-0000-3000-2000-00805F9B34FD',
      characteristicValue: wlanBuff,
      descriptors: []
    };
    gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (code: BusinessError) => {
      if (code != null) {
        return;
      }
      console.log('bluetooth writeCharacteristicValue success');
    });
  }
  /**
   * 上传绑定关系
   * @param valueJson
   * @param homeId
   */
  bindDevsToCloud = (valueJson: BlePackInfoModel, homeId: number) => {
    const wlanDecryptAES: BleInfoModel = JSON.parse(CommonUtil.decryptAES(valueJson.pack, this.bleKey))
    let url: string = ApiKey.BindDev;
    let bindDevData: BindDevRequestData = {
      uid: ApiVerify.loginResultData.uid,
      token: ApiVerify.loginResultData?.token,
      devs: [
        {
          mac: wlanDecryptAES.mac,
          pmac: '',
          name: 'qqq',
          key: this.bleKey,
          mid: wlanDecryptAES.mid,
          homeId: homeId,
          ssid: 'LYKJ-2',
          vender: ''
        }
      ]
    }
    HttpRequest.getInstance()
      .baseRequest<BindDevResultData>(url, bindDevData)
      .then((res) => {
        Logger.info(TAG, 'bindDevRes:' + res.resStr)
      });
  }
  public stopBleDevicesScan() {
    ble.off('BLEDeviceFind', this.onReceiveEvent);
    ble.stopBLEScan();
  }
}

更多关于HarmonyOS 鸿蒙Next Flutter对接 如何判断App是否有蓝牙权限的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在HarmonyOS鸿蒙Next Flutter对接中,判断App是否有蓝牙权限可以通过以下步骤实现:

  1. 权限声明: 首先,在config.json文件中声明蓝牙权限。添加以下权限配置:

    "module": {
      "package": "your.package.name",
      "reqPermissions": [
        "ohos.permission.BLUETOOTH",
        "ohos.permission.BLUETOOTH_ADMIN"
      ]
    }
    
  2. 权限检查: 在Flutter代码中,可以通过平台通道(Platform Channel)调用原生代码来检查权限。创建一个原生方法用于检查蓝牙权限,然后在Flutter中调用这个方法。

    示例(伪代码):

    • 原生(Java/Kotlin/Dart对应原生部分,但这里不涉及具体语言实现):
      public boolean hasBluetoothPermission() {
          return checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED;
      }
      
    • Flutter:
      MethodChannel _channel = MethodChannel('your_channel_name');
      Future<bool> checkBluetoothPermission() async {
        final bool hasPermission = await _channel.invokeMethod('hasBluetoothPermission');
        return hasPermission;
      }
      

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

回到顶部