
回复
在 module.json5 文件中添加蓝牙相关权限:
json{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.ACCESS_BLUETOOTH",
"reason": "需要使用蓝牙功能"
}
]
}
}
import bluetooth from '@ohos.bluetooth';
typescript//用户申请蓝牙权限
async requestBlueToothPermission() {
let grantStatus = await this.reqPermissionsFromUser();
for (let i = 0; i < grantStatus.length; i++) {
if (grantStatus[i] === 0) {
//查看当前蓝牙开启状态
this.isStartBlueTooth = BleState.getBluetoothState();
if (!this.isStartBlueTooth) {
showConfirmAlertDialog('蓝牙未开启,请滑出系统控制中心,打开蓝牙进行连接', () =>
}
else
showConfirmAlertDialog('蓝牙授权失败,请打开设置进行授权', () =>
WantUtil.toAppSetting()
})
console.info(CommonConstants.log_prefix + '蓝牙授权失败!')
}
}
}
//用户申请权限
async reqPermissionsFromUser(): Promise<number[]> {
// 申请权限
let context = getContext() as common.UIAbilityContext;
// 获取AbilityAccessCtrl对象
let atManager = abilityAccessCtrl.createAtManager();
// 请求权限,传入上下文和需要申请的权限列表
let grantStatus = await atManager.requestPermissionsFromUser(context, ['ohos.permission.ACCESS_BLUETOOTH']);
// 返回授权结果列表
return grantStatus.authResults;
}
javascripttry
const scanOptions: ble.ScanOptions
interval: 1000,
dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE,
};
// 订阅 BLEDeviceFind 事件
on('BLEDeviceFind', (data: Array<ble.ScanResult>) =>
//解析蓝牙广播数据
});
// 开始扫描
startBLEScan(filters, scanOptions);
this.isScanning = true;
catch
throw new Error('Failed to start BLE scan');
}
arduinoconst clientDevice = ble.createGattClientDevice(deviceId)
//连接状态
on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
const
switch
case constant.ProfileConnectionState.STATE_DISCONNECTED: // 设备已断开连接
break;
case constant.ProfileConnectionState.STATE_CONNECTING: // 设备正在连接
break;
case constant.ProfileConnectionState.STATE_CONNECTED: // 设备已连接
//发现服务
this.getServices();
break;
case constant.ProfileConnectionState.STATE_DISCONNECTING: // 设备正在断开连接
break;
default:
break;
}
})
//连接
try
connect()
catch
}
//获取服务
private async getServices() {
if (this.gattClientDevice) {
const result: Array<ble.GattService> = await this.gattClientDevice.getServices();
info('getServices successfully:' + JSON.stringify(result));
this.gattClientDevice;
debug('发现蓝牙服务>>>' + JSON.stringify(result))
for (const
info('getServices item= ' + JSON.stringify(item));
//服务UUID
if (item.serviceUuid === ‘读写特征UUID'’) {
this.gattServiceInfo = item;
const writeCharacteristic = item.characteristics.find(c => c.characteristicUuid == '读写特征UUID');
const notyCharacteristic = item.characteristics.find(c => c.characteristicUuid == '通知特征UUID');
// setNotification
if
try
const success = await this.setNotificationChannel(gatt, item, writeCharacteristic, true);
if
log(`Notification set successfully for characteristic(通道1) ${writeCharacteristic.characteristicUuid}`);
else
log(`Failed to set notification for characteristic(通道1) ${writeCharacteristic.characteristicUuid}`);
}
catch
}
}
// setNotification
if
try
const success = await this.setNotificationChannel(gatt, item, notyCharacteristic, true);
if
log(`Notification set successfully for characteristic(通道1) ${notyCharacteristic.characteristicUuid}`);
else
log(`Failed to set notification for characteristic(通道1) ${notyCharacteristic.characteristicUuid}`);
}
catch
}
}
}
}
//接收设备数据
this.onBleCharacteristicChange()
}
}
//向下位机发送设置通知此indicate征值请求
private async setNotificationChannel(
gatt: ble.GattClientDevice | null ,
gattService: ble.GattService | undefined,
characteristic: ble.BLECharacteristic,
boolean
): Promise<boolean>{
if
return false; // 返回失败
}
if
return false; // 返回失败
}
try
if
// 向下位机发送设置通知此indicate征值请求
setCharacteristicChangeNotification(characteristic, enable)
return true; // 返回成功
}
catch
return false; // 返回失败
}
return false; // 如果没有gatt,返回失败
}
//订阅蓝牙低功耗设备的特征值变化事件 (接收消息)
private onBleCharacteristicChange(){
debug('开始监听特征值变化')
try
if (this.gattClientDevice) {
//监听
this.gattClientDevice.on('BLECharacteristicChange', (characteristicChangeReq: ble.BLECharacteristic) => {
let serviceUuid: string = characteristicChangeReq.serviceUuid;
let characteristicUuid: string = characteristicChangeReq.characteristicUuid;
const
//服务UUID
if(serviceUuid == '读写特征UUID'){
//回调数据
else
}
})
}
catch
}
}
kotlinexport class TBBleCommandManager
private gatt: ble.GattClientDevice | null
private gattServiceInfo: ble.GattService | null
private data: ArrayBuffer;//特征数据
/**
* 构造函数
@param
@param
@param
*/
constructor(
null,
null,
data: ArrayBuffer,
) {
this.gatt = gatt
this.gattServiceInfo = gattServiceInfo
this.data = data
}
//写入特征值
writeBrushCharacteristicValue(){
//查找读写特征
const characteristic = this.gattServiceInfo?.characteristics.find(c => c.characteristicUuid === BrushConst.WRITE_CHARACTERISTIC_UUID);
if
return
}
try
if (this.gatt) {
// 设置特征值
this.data
// 写入特征值到设备中
this.gatt.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE)
else
}
}
catch
const errorCode = (err as
const errorMessage = (err as
}
}
}
数据粘包的问题,我们可以采用队列的方式处理
kotlinimport { BluetoothCommand } from "./BluetoothCommand";
import { BusinessError } from "@kit.BasicServicesKit";
import { TBBleCommandManager } from "../../toothbrush/model/TBBleCommandManager";
export class BluetoothCommandQueue
// 队列存储指令,根据优先级排序
private
// 标记是否正在处理指令
private isProcessing: boolean = false;
// 队列最大长度限制,可根据实际情况调整
private maxSize: number = 999;
// 添加指令到队列
enqueue(command: BluetoothCommand): boolean {
if (this.queue.length >= this.maxSize) {
return false;
}
// 根据优先级插入队列
false;
for (let i = 0; i < this.queue.length; i++) {
if (this.queue[i].priority < command.priority) {
this.queue.splice(i, 0, command);
true;
break;
}
}
if
this.queue.push(command);
}
this.processQueue();
return true;
}
// 从队列取出指令
dequeue(): BluetoothCommand | undefined {
return this.queue.shift();
}
// 处理队列中的指令
private
if (this.isProcessing || this.queue.length === 0) {
return;
}
this.isProcessing = true;
while (this.queue.length > 0) {
const command:BluetoothCommand = this.dequeue() as
if
try
// 这里调用实际的蓝牙发送接口
this.sendBluetoothCommand(command);
null);
catch
as
}
}
}
// 处理完成后,标记为非处理状态
this.isProcessing = false;
}
// 发送蓝牙指令的方法
private
return
// 发送蓝牙指令
new TBBleCommandManager(command.gatt, command.gattServiceInfo, command.command).writeBrushCharacteristicValue()
setTimeout(() => {
'Bluetooth command sent successfully');
// 成功回调
resolve();
100);
});
}
// 清空队列
clear(): void {
this.queue = [];
this.isProcessing = false;
}
// 获取队列大小
size(): number {
return this.queue.length;
}
}
import { BusinessError } from "@kit.BasicServicesKit";
import { ble } from "@kit.ConnectivityKit";
export class BluetoothCommand
command: ArrayBuffer;
priority: number;
timestamp: number;
null) => void;
null;
null;
/**
* 构造函数
@param
@param
@param
@param
@param
*/
constructor(command: ArrayBuffer, priority: number = 0, gatt: ble.GattClientDevice , gattServiceInfo: ble.GattService , callback?: (result: BusinessError | null) => void) {
this.command = command;
this.gatt = gatt;
this.gattServiceInfo = gattServiceInfo;
this.priority = priority;
this.timestamp = Date.now();
this.callback = callback;
}
}
队列的调用方法如下
typescriptprivate commandQueue: BluetoothCommandQueue = new BluetoothCommandQueue();//指令发送队列
// 写入BLE特征值
// 创建蓝牙指令对象
const command = new BluetoothCommand( buff, 0, this.gattClientDevice!, this.gattServiceInfo!,
(error: BusinessError | null) =>
if
// `发送失败: ${error.message}`;
else
// '发送成功';
}
}
);
this.commandQueue.enqueue(command)
注意事项
作者:沉淀风飛
链接:https://juejin.cn/post/7535740692191346714