最新鸿蒙Next 蓝牙开发流程

QQ6766
发布于 2025-8-8 13:33
浏览
0收藏

1. 权限配置

在 module.json5 文件中添加蓝牙相关权限:

json{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.ACCESS_BLUETOOTH",
"reason": "需要使用蓝牙功能"
}
]
}
}

2. 导入蓝牙模块

import bluetooth from '@ohos.bluetooth';

3. 蓝牙状态检查与开启

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;
 }

4. 设备扫描

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');
   }

5. 设备连接、数据接收

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

    }
  }

6. 数据发送

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

分类
收藏
回复
举报
回复
    相关推荐