HarmonyOS 鸿蒙Next Flutter对接 如何判断App是否有蓝牙权限
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是否有蓝牙权限可以通过以下步骤实现:
-
权限声明: 首先,在
config.json
文件中声明蓝牙权限。添加以下权限配置:"module": { "package": "your.package.name", "reqPermissions": [ "ohos.permission.BLUETOOTH", "ohos.permission.BLUETOOTH_ADMIN" ] }
-
权限检查: 在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; }
- 原生(Java/Kotlin/Dart对应原生部分,但这里不涉及具体语言实现):
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html