当前位置: 首页 > news >正文

OpenHarmony蓝牙技术全解析:从设备发现到数据传输的完整流程

目录

  • 蓝牙技术概述
  • 蓝牙设置
  • 传统蓝牙开发
    • 查找设备
    • 配对连接设备
    • 连接和传输数据
  • 低功耗蓝牙开发
    • 查找设备
    • 连接和传输数据
  • 开发实践与注意事项

蓝牙技术概述

蓝牙技术发展历程

蓝牙技术起源于1994年,由爱立信公司首创,旨在开发一种短距离无线通信技术,以替代传统有线连接。1998年,蓝牙特别兴趣小组(SIG)成立,负责蓝牙技术的标准化和推广。蓝牙技术经历了多次重大演进:

  • 蓝牙1.0/1.1B:基础速率(BR)技术,传输速率约721kbps
  • 蓝牙2.0+EDR:增强数据速率(EDR),传输速率提升至2-3Mbps
  • 蓝牙3.0+HS:高速传输,结合WiFi技术实现高达24Mbps的传输速率
  • 蓝牙4.0:引入低功耗蓝牙(BLE)技术,显著降低功耗
  • 蓝牙5.0/5.1/5.2/5.3:不断提升传输距离、速度和连接稳定性,增加音频共享、定位等功能

蓝牙通信原理

蓝牙通信基于**跳频扩频(FHSS)**技术,在2.402-2.480GHz的ISM频段内工作。通信原理包括以下几个关键方面:

1. 跳频技术

蓝牙设备将频段划分为79个1MHz宽的信道(部分国家为23个),通信时按照伪随机序列在这些信道间快速跳变,每秒跳变1600次。跳频技术具有以下优势:

  • 抗干扰能力强:避免特定频段的持续干扰
  • 安全性高:只有知道跳频序列的设备才能通信
  • 频谱利用率高:多设备可同时工作而互不干扰
2. 蓝牙网络拓扑

蓝牙支持多种网络拓扑结构:

  • 点对点(Piconet):一个主设备最多连接7个从设备
  • 散射网(Scatternet):多个Piconet通过桥接设备互联
  • 广播网络:一个设备向多个设备广播数据
3. 蓝牙协议栈架构

蓝牙协议栈分为四层:

  1. 核心协议层

    • 基带(Baseband):处理物理层连接和数据传输
    • 链路管理协议(LMP):负责链路建立、配置和安全
    • 逻辑链路控制和适配协议(L2CAP):提供面向连接和无连接的数据服务
  2. 电缆替代协议层

    • RFCOMM:模拟串口通信,支持传统串口应用
  3. 电话控制协议层

    • TCS Binary:提供电话控制信令
  4. 选用协议层

    • PPP、TCP/IP、UDP、OBEX、WAP等

蓝牙技术分类

OpenHarmony系统支持两种蓝牙技术:

  1. 传统蓝牙(BR/EDR)

    • 支持高质量音频传输(A2DP)
    • 支持免提通话(HFP)
    • 支持人机接口设备(HID)
    • 支持串口通信协议(SPP)
    • 适合流媒体传输、音频设备等场景
  2. 低功耗蓝牙(BLE)

    • 功耗极低,适合电池供电设备
    • 支持通用属性协议(GATT)
    • 适用于物联网设备、健康监测设备等场景
    • 连接建立速度快,数据传输量小但频繁

蓝牙架构

OpenHarmony蓝牙架构主要包含以下层次:

  1. 应用层:开发者使用蓝牙API实现应用功能
  2. 框架层:提供蓝牙功能接口
  3. 协议层:实现蓝牙协议栈
  4. 驱动层:与蓝牙硬件交互

蓝牙设置

权限申请

开发蓝牙应用前,需要在module.json5文件中声明必要的权限:

{"module": {"requestPermissions": [{"name": "ohos.permission.ACCESS_BLUETOOTH","reason": "$string:bluetooth_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]}
}

蓝牙状态管理

获取蓝牙状态
import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';try {// 获取蓝牙状态let state = connection.getBluetoothState();console.info('bluetooth state: ' + state);
} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
订阅蓝牙状态变化
// 定义蓝牙状态变化回调函数
function onReceiveEvent(data: connection.BluetoothState) {console.info('bluetooth state: ' + data);
}try {// 发起订阅connection.on('stateChange', onReceiveEvent);
} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
开启/关闭蓝牙
import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';async function requestBluetoothPermission(context: common.UIAbilityContext): Promise<boolean> {try {// 检查蓝牙权限let result = await context.requestPermissionsFromUser(['ohos.permission.ACCESS_BLUETOOTH']);if (result.authResults[0] === 0) {// 权限已授予return true;} else {// 权限被拒绝return false;}} catch (err) {console.error('requestBluetoothPermission errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);return false;}
}async function enableBluetooth(context: common.UIAbilityContext) {try {// 检查蓝牙权限let hasPermission = await requestBluetoothPermission(context);if (!hasPermission) {console.error('no bluetooth permission');return;}// 检查蓝牙状态let state = connection.getBluetoothState();if (state === connection.BluetoothState.STATE_OFF) {// 蓝牙未开启,请求开启蓝牙connection.enableBluetooth();}} catch (err) {console.error('enableBluetooth errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}
}async function disableBluetooth() {try {// 检查蓝牙状态let state = connection.getBluetoothState();if (state === connection.BluetoothState.STATE_ON) {// 蓝牙已开启,请求关闭蓝牙connection.disableBluetooth();}} catch (err) {console.error('disableBluetooth errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}
}

传统蓝牙开发

传统蓝牙(BR/EDR)基于主从架构工作,在通信过程中,一个设备作为主设备(Master),其他设备作为从设备(Slave)。主设备负责控制通信时序和跳频序列,从设备根据主设备的指令进行响应。

传统蓝牙通信流程

传统蓝牙通信遵循以下基本流程:

  1. 设备发现:通过查询(Inquiry)过程发现周围的蓝牙设备
  2. 设备配对:建立安全连接,交换密钥信息
  3. 设备连接:建立物理链路(ACL)和逻辑链路(L2CAP)
  4. 服务发现:查询对方设备支持的服务和协议
  5. 数据传输:通过RFCOMM或其他协议进行数据交换
  6. 连接断开:释放资源,终止通信

传统蓝牙协议栈详解

传统蓝牙协议栈包含以下关键组件:

  1. 物理层(Baseband)

    • 负责无线信号调制解调
    • 实现跳频序列生成和同步
    • 管理物理信道接入
  2. 链路管理层(LMP)

    • 处理设备认证和加密
    • 管理链路参数配置
    • 控制设备功率模式
  3. L2CAP层

    • 提供面向连接和无连接的数据服务
    • 支持协议多路复用和分段重组
    • 管理服务质量(QoS)参数
  4. RFCOMM层

    • 模拟RS-232串口通信
    • 支持流控和错误控制
    • 为上层应用提供熟悉的串口接口

查找设备

扫描周边蓝牙设备

传统蓝牙设备发现过程基于查询(Inquiry)和查询扫描(Inquiry Scan)机制:

  • 查询设备:主设备发送查询包,从设备在查询扫描状态下响应
  • 查询响应:从设备返回包含设备地址、类别等信息的FHS包
  • 名称请求:主设备获取从设备的友好名称

OpenHarmony提供了简化的API来封装这些底层过程:

import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class DiscoveryDeviceManager {// 定义扫描结果上报回调函数onReceiveEvent = (data: Array<string>) => {console.info('bluetooth device: '+ JSON.stringify(data));};public startDiscovery() {try {connection.on('bluetoothDeviceFind', this.onReceiveEvent);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}try {// 判断本机设备是否正在进行扫描let scan = connection.isBluetoothDiscovering();if (!scan) {// 若当前不处于扫描过程,则开始扫描设备connection.startBluetoothDiscovery();}} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}public stopDiscovery() {try {// 判断本机设备是否正在进行扫描let scan = connection.isBluetoothDiscovering();if (scan) {// 若当前处于扫描过程,则停止扫描设备connection.stopBluetoothDiscovery();}// 若不再需要使用扫描,可以取消订阅扫描上报结果connection.off('bluetoothDeviceFind', this.onReceiveEvent);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}public setScanMode() {try {// 获取当前本机的扫描模式let scanMode: connection.ScanMode = connection.getBluetoothScanMode();console.info('scanMode: ' + scanMode);if (scanMode != connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE) {// 将本机设备的扫描模式设为可被发现和可被连接connection.setBluetoothScanMode(connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, 0);}} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}public getPairedDevices() {try {// 获取已配对设备信息let devices = connection.getPairedDevices();console.info('pairedDevices: ' + JSON.stringify(devices));// 若已知道设备地址,可主动查询该设备是否是已配对的if (devices.length > 0) {let pairState = connection.getPairState(devices[0]);console.info('device: '+ devices[0] + ' pairState is ' + pairState);}} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}
}

配对连接设备

蓝牙配对机制详解

蓝牙配对是建立安全连接的关键步骤,主要目的是生成用于加密通信的链路密钥。配对过程包含以下阶段:

  1. 能力交换:设备交换输入输出能力、认证要求等信息
  2. 用户认证:根据设备能力执行认证步骤(如PIN码输入、数字比较等)
  3. 密钥生成:基于ECDH算法生成共享密钥
  4. 链路密钥确认:验证生成的密钥是否正确

蓝牙4.2及以上版本引入了**安全连接(SC)**技术,使用椭圆曲线Diffie-Hellman(ECDH)加密替代传统的PIN码认证,提供更强的安全性。

蓝牙连接管理

蓝牙连接分为多个层次:

  1. 物理链路(ACL)

    • 异步无连接链路,用于数据传输
    • 支持主设备与多个从设备同时通信
    • 提供流量控制和错误检测
  2. 逻辑链路(L2CAP)

    • 在ACL链路上建立逻辑通道
    • 支持协议多路复用
    • 提供分段重组和流控功能
  3. 应用层连接

    • 基于特定协议的连接(如RFCOMM、AVDTP等)
    • 面向特定应用场景的通信
配对设备
import { connection, a2dp, hfp, hid, baseProfile, constant } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class PairDeviceManager {device: string = '';pairState: connection.BondState = connection.BondState.BOND_STATE_INVALID;a2dpSrc = a2dp.createA2dpSrcProfile();hfpAg = hfp.createHfpAgProfile();hidHost = hid.createHidHostProfile();// 定义配对状态变化回调函数onBondStateEvent = (data: connection.BondStateParam) => {console.info('pair result: '+ JSON.stringify(data));if (data && data.deviceId == this.device) {this.pairState = data.state; // 保存目标设备的配对状态}};// 发起配对,设备地址可以通过查找设备流程获取public startPair(device: string) {this.device = device;try {// 发起订阅配对状态变化事件connection.on('bondStateChange', this.onBondStateEvent);} catch (err) {console.error('bondStateChange errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}try {// 发起配对connection.pairDevice(device).then(() => {console.info('pairDevice');}, (error: BusinessError) => {console.error('pairDevice: errCode:' + error.code + ',errMessage' + error.message);});} catch (err) {console.error('startPair: errCode:' + err.code + ',errMessage' + err.message);}}// 定义A2DP连接状态变化回调函数onA2dpConnectStateChange = (data: baseProfile.StateChangeParam) => {console.info(`A2DP State: ${JSON.stringify(data)}`);};// 定义HFP连接状态变化回调函数onHfpConnectStateChange = (data: baseProfile.StateChangeParam) => {console.info(`HFP State: ${JSON.stringify(data)}`);};// 定义HID连接状态变化回调函数onHidConnectStateChange = (data: baseProfile.StateChangeParam) => {console.info(`HID State: ${JSON.stringify(data)}`);};// 发起连接public async connect(device: string) {try {let uuids = await connection.getRemoteProfileUuids(device);console.info('device: ' + device + ' remoteUuids: '+ JSON.stringify(uuids));let allowedProfiles = 0;// 若存在应用需要的profile,则监听对应的profile连接状态if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_A2DP_SINK.toLowerCase())) {console.info('device supports a2dp');allowedProfiles++;this.a2dpSrc.on('connectionStateChange', this.onA2dpConnectStateChange);}if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HFP_HF.toLowerCase())) {console.info('device supports hfp');allowedProfiles++;this.hfpAg.on('connectionStateChange', this.onHfpConnectStateChange);}if (uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HID.toLowerCase()) ||uuids.some(uuid => uuid == constant.ProfileUuids.PROFILE_UUID_HOGP.toLowerCase())) {console.info('device supports hid');allowedProfiles++;this.hidHost.on('connectionStateChange', this.onHidConnectStateChange);}if (allowedProfiles > 0) { // 若存在可用的profile,则发起连接connection.connectAllowedProfiles(device).then(() => {console.info('connectAllowedProfiles');}, (error: BusinessError) => {console.error('errCode:' + error.code + ',errMessage' + error.message);});}} catch (err) {console.error('errCode:' + err.code + ',errMessage' + err.message);}}
}

连接和传输数据

SPP客户端实现

SPP(Serial Port Profile)是传统蓝牙中最常用的数据传输协议,它基于RFCOMM协议模拟串口通信。SPP通信流程如下:

  1. 服务发现:客户端查询设备支持的SPP服务
  2. RFCOMM连接:建立RFCOMM通道
  3. 数据传输:通过RFCOMM通道进行双向数据传输
  4. 连接断开:释放RFCOMM通道

以下是一个完整的SPP客户端实现示例:

import { socket } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class SppClient {private clientNumber: number = -1;private readCallback: (data: ArrayBuffer) => void;constructor(readCallback: (data: ArrayBuffer) => void) {this.readCallback = readCallback;}// 发起连接public connect(device: string, uuid: string) {// 配置连接参数let option: socket.SppOptions = {uuid: uuid,secure: false,type: socket.SppType.SPP_RFCOMM};console.info('startConnect ' + device);socket.sppConnect(device, option, (err, num: number) => {if (err) {console.error('startConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);} else {console.info('startConnect clientNumber: ' + num);this.clientNumber = num;// 订阅读取数据事件this.subscribeRead();}});}// 订阅读取数据事件private subscribeRead() {try {socket.on('sppRead', this.clientNumber, this.readCallback);} catch (err) {console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 发送数据public write(data: ArrayBuffer) {try {socket.sppWrite(this.clientNumber, data);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 断开连接public disconnect() {try {// 取消接收数据订阅socket.off('sppRead', this.clientNumber, this.readCallback);} catch (err) {console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}try {// 从client端断开连接socket.sppCloseClientSocket(this.clientNumber);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}
}
SPP服务端实现

SPP服务端负责监听来自客户端的连接请求,并建立RFCOMM通道进行数据传输。SPP服务端工作流程如下:

  1. 创建服务端套接字:注册SPP服务,指定UUID和通道参数
  2. 监听连接请求:等待客户端连接
  3. 接受连接:建立RFCOMM通道
  4. 数据传输:通过RFCOMM通道进行双向数据传输
  5. 断开连接:释放RFCOMM通道和服务端套接字

以下是一个完整的SPP服务端实现示例:

import { socket } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class SppServer {private serverNumber: number = -1;private clientNumber: number = -1;private readCallback: (data: ArrayBuffer) => void;constructor(readCallback: (data: ArrayBuffer) => void) {this.readCallback = readCallback;}// 创建服务端套接字public createServer(serviceName: string, uuid: string) {// 配置监听参数let option: socket.SppOptions = {uuid: uuid,secure: false,type: socket.SppType.SPP_RFCOMM};// 创建服务端监听socket,将在蓝牙子系统中注册该UUID服务socket.sppListen(serviceName, option, (err, num: number) => {if (err) {console.error('sppListen errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);} else {console.info('sppListen serverNumber: ' + num);this.serverNumber = num;// 开始监听客户端连接this.acceptConnection();}});}// 监听客户端连接private acceptConnection() {socket.sppAccept(this.serverNumber, (err, num: number) => {if (err) {console.error('accept errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);} else {console.info('accept clientNumber: ' + num);this.clientNumber = num;// 订阅读取数据事件this.subscribeRead();}});}// 订阅读取数据事件private subscribeRead() {try {socket.on('sppRead', this.clientNumber, this.readCallback);} catch (err) {console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 发送数据public write(data: ArrayBuffer) {try {socket.sppWrite(this.clientNumber, data);} catch (err) {console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 断开连接public disconnect() {try {// 取消接收数据订阅socket.off('sppRead', this.clientNumber, this.readCallback);} catch (err) {console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}try {// 从server端断开连接socket.sppCloseServerSocket(this.serverNumber);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}
}

低功耗蓝牙开发

低功耗蓝牙(BLE)是蓝牙4.0引入的革命性技术,专为低功耗应用场景设计。与传统蓝牙相比,BLE在保持相似通信范围的同时,大幅降低了功耗,使其成为物联网、可穿戴设备等领域的理想选择。

BLE技术特点

BLE具有以下显著特点:

  1. 超低功耗

    • 待机电流低至微安级别
    • 通信时电流消耗仅为传统蓝牙的十分之一
    • 支持深度睡眠和快速唤醒机制
  2. 快速连接

    • 连接建立时间仅需几毫秒
    • 适合间歇性数据传输场景
  3. 简化协议栈

    • 协议栈更简单,降低了实现复杂度
    • 减少了处理和内存需求
  4. 广播机制

    • 支持一对多的无连接广播
    • 适合信标(Beacon)等应用场景

BLE通信原理

BLE通信基于**GAP(通用访问配置文件)GATT(通用属性配置文件)**两个核心协议:

GAP(通用访问配置文件)

GAP定义了设备发现、连接建立和安全等基本功能:

  1. 设备角色

    • 广播者(Broadcaster):只发送广播数据,不接收连接
    • 观察者(Observer):扫描广播数据,不发起连接
    • 外围设备(Peripheral):可被连接的设备
    • 中央设备(Central):发起连接的设备
  2. 广播过程

    • 设备在37、38、39三个广播信道上发送广播包
    • 广播包包含设备地址、标志位、广播数据等信息
    • 广播间隔可配置,通常为20ms到10.24s
  3. 扫描过程

    • 主动扫描:发送扫描请求,获取扫描响应
    • 被动扫描:仅接收广播数据,不发送请求
GATT(通用属性配置文件)

GATT定义了基于属性的数据传输模型:

  1. 属性协议(ATT)

    • 轻量级协议,用于在BLE链路上传输属性
    • 属性由句柄、类型和值三部分组成
    • 支持查找、读取、写入、通知和指示操作
  2. 服务、特征和描述符

    • 服务(Service):一组相关特征的集合
    • 特征(Characteristic):数据值及其描述信息
    • 描述符(Descriptor):特征的元数据信息
  3. 数据传输方式

    • 读取(Read):中央设备从外围设备读取数据
    • 写入(Write):中央设备向外围设备写入数据
    • 通知(Notification):外围设备主动发送数据,无需确认
    • 指示(Indication):外围设备主动发送数据,需要确认

BLE连接管理

BLE连接管理包含以下关键参数:

  1. 连接参数

    • 连接间隔(Connection Interval):两次连接事件之间的时间,范围7.5ms-4s
    • 从设备延迟(Slave Latency):从设备可跳过的连续连接事件数量
    • 监督超时(Supervision Timeout):连接断开前允许的最大通信间隔
  2. 连接事件

    • 在每个连接事件中,中央设备和外围设备交换数据包
    • 连接事件持续时间由数据包数量和大小决定
    • 无数据传输时可提前结束连接事件以节省功耗
  3. 数据长度扩展

    • BLE 4.2支持数据长度扩展,最大数据包长度从27字节增加到251字节
    • 减少了数据包开销,提高了传输效率

BLE安全机制

BLE提供多层次的安全保护:

  1. 设备认证

    • Just Works:无用户交互,适用于低安全需求场景
    • Passkey Entry:用户输入6位数字,适用于有显示屏和键盘的设备
    • Out of Band:通过其他通信通道交换认证信息
  2. 数据加密

    • 使用AES-CCM加密算法
    • 128位加密密钥
    • 每个连接使用不同的会话密钥
  3. 隐私保护

    • 设备可使用随机可解析地址替代真实地址
    • 地址定期更新,防止设备被跟踪

查找设备

BLE扫描实现

BLE扫描过程与传统蓝牙设备发现有显著不同:

  • 扫描类型:主动扫描和被动扫描
  • 扫描窗口和间隔:控制扫描占空比和功耗
  • 过滤器:根据设备地址、服务UUID等过滤扫描结果

OpenHarmony提供了简化的API来封装这些底层过程:

import { ble } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class BleScanner {private scanning: boolean = false;// 定义扫描结果上报回调函数private onReceiveEvent = (data: Array<ble.ScanResult>) => {console.info('bluetooth device: '+ JSON.stringify(data));};// 开始扫描public startScan() {try {// 订阅扫描结果ble.on('BLEDeviceFind', this.onReceiveEvent);// 开始扫描ble.startBLEScan();this.scanning = true;} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 停止扫描public stopScan() {if (this.scanning) {try {// 停止扫描ble.stopBLEScan();// 取消订阅ble.off('BLEDeviceFind', this.onReceiveEvent);this.scanning = false;} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}}
}

连接和传输数据

GATT客户端实现

GATT客户端是BLE通信中的中央设备角色,负责发起连接、发现服务、读写特征值等操作。GATT客户端工作流程如下:

  1. 设备扫描:发现周围BLE设备
  2. 连接建立:与目标设备建立BLE连接
  3. 服务发现:查询设备支持的服务
  4. 特征发现:查询服务包含的特征和描述符
  5. 数据交互:读取、写入特征值或订阅通知
  6. 连接断开:终止BLE连接

以下是一个完整的GATT客户端实现示例:

import { ble } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class GattClient {private gattClient: ble.GattClientDevice;private connected: boolean = false;constructor(device: string) {this.gattClient = ble.createGattClientDevice(device);this.setupEventHandlers();}// 设置事件处理器private setupEventHandlers() {// 订阅连接状态变化事件this.gattClient.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {console.info('bluetooth connect state changed');let connectState: ble.ProfileConnectionState = state.state;this.connected = (connectState === ble.ProfileConnectionState.STATE_CONNECTED);});}// 发起连接public connect() {try {this.gattClient.connect();} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 断开连接public disconnect() {try {this.gattClient.disconnect();} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 服务发现public async getServices(): Promise<Array<ble.GattService>> {try {return await this.gattClient.getServices();} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);return [];}}// 读取特征值public readCharacteristicValue(characteristic: ble.BLECharacteristic): Promise<ble.BLECharacteristic> {return new Promise((resolve, reject) => {try {this.gattClient.readCharacteristicValue(characteristic).then((result: ble.BLECharacteristic) => {resolve(result);}).catch((error: BusinessError) => {reject(error);});} catch (err) {reject(err);}});}// 写入特征值public writeCharacteristicValue(characteristic: ble.BLECharacteristic, writeType: ble.GattWriteType = ble.GattWriteType.WRITE): Promise<void> {return new Promise((resolve, reject) => {try {this.gattClient.writeCharacteristicValue(characteristic, writeType, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 订阅特征值变化通知public subscribeCharacteristicChange(callback: (characteristic: ble.BLECharacteristic) => void) {try {this.gattClient.on('BLECharacteristicChange', callback);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 取消订阅特征值变化通知public unsubscribeCharacteristicChange(callback: (characteristic: ble.BLECharacteristic) => void) {try {this.gattClient.off('BLECharacteristicChange', callback);} catch (err) {console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);}}// 启用特征值变化通知public setCharacteristicChangeNotification(characteristic: ble.BLECharacteristic, enable: boolean): Promise<void> {return new Promise((resolve, reject) => {try {this.gattClient.setCharacteristicChangeNotification(characteristic, enable, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 启用特征值变化指示public setCharacteristicChangeIndication(characteristic: ble.BLECharacteristic, enable: boolean): Promise<void> {return new Promise((resolve, reject) => {try {this.gattClient.setCharacteristicChangeIndication(characteristic, enable, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}
}
GATT服务端实现
import { ble } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';export class GattServer {private gattServer: ble.GattServer;constructor() {this.gattServer = ble.createGattServer();this.setupEventHandlers();}// 设置事件处理器private setupEventHandlers() {// 订阅连接状态变化事件this.gattServer.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {console.info('bluetooth connect state changed');let connectState: ble.ProfileConnectionState = state.state;});// 订阅特征值读取请求this.gattServer.on('readCharacteristic', (request: ble.ReadRequest) => {console.info('readCharacteristic request: ' + JSON.stringify(request));});// 订阅特征值写入请求this.gattServer.on('writeCharacteristic', (request: ble.WriteRequest) => {console.info('writeCharacteristic request: ' + JSON.stringify(request));});// 订阅描述符读取请求this.gattServer.on('readDescriptor', (request: ble.ReadRequest) => {console.info('readDescriptor request: ' + JSON.stringify(request));});// 订阅描述符写入请求this.gattServer.on('writeDescriptor', (request: ble.WriteRequest) => {console.info('writeDescriptor request: ' + JSON.stringify(request));});}// 添加服务public addService(service: ble.GattService): Promise<boolean> {return new Promise((resolve, reject) => {try {this.gattServer.addService(service, (err, status) => {if (err) {reject(err);} else {resolve(status === ble.GattServiceStatus.SERVICE_ADDED);}});} catch (err) {reject(err);}});}// 移除服务public removeService(serviceUuid: string): Promise<boolean> {return new Promise((resolve, reject) => {try {this.gattServer.removeService(serviceUuid, (err, status) => {if (err) {reject(err);} else {resolve(status === ble.GattServiceStatus.SERVICE_REMOVED);}});} catch (err) {reject(err);}});}// 清除所有服务public clearServices(): Promise<void> {return new Promise((resolve, reject) => {try {this.gattServer.clearServices((err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 发送响应public sendResponse(response: ble.ServerResponse): Promise<void> {return new Promise((resolve, reject) => {try {this.gattServer.sendResponse(response, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 通知特征值变化public notifyCharacteristicChanged(notify: ble.NotifyCharacteristicChanged): Promise<void> {return new Promise((resolve, reject) => {try {this.gattServer.notifyCharacteristicChanged(notify, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 启动广播public startAdvertising(setting: ble.AdvertiseSetting, advData: ble.AdvertiseData, scanResponse?: ble.AdvertiseData): Promise<void> {return new Promise((resolve, reject) => {try {this.gattServer.startAdvertising(setting, advData, scanResponse, (err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}// 停止广播public stopAdvertising(): Promise<void> {return new Promise((resolve, reject) => {try {this.gattServer.stopAdvertising((err) => {if (err) {reject(err);} else {resolve();}});} catch (err) {reject(err);}});}
}

开发实践与注意事项

蓝牙通信安全考虑

  1. 数据加密

    • 使用蓝牙内置加密机制
    • 对敏感数据进行应用层加密
    • 定期更新加密密钥
  2. 身份认证

    • 实现设备身份验证机制
    • 使用安全配对方式
    • 避免使用固定PIN码
  3. 访问控制

    • 实现细粒度的权限控制
    • 限制对敏感服务的访问
    • 记录和审计访问日志

蓝牙开发常见问题

  1. 连接不稳定

    • 检查设备距离和干扰源
    • 调整连接参数
    • 实现自动重连机制
  2. 数据传输异常

    • 检查数据包大小限制
    • 实现数据分包和重组
    • 添加校验机制
  3. 兼容性问题

    • 测试不同品牌设备兼容性
    • 遵循蓝牙规范实现
    • 提供降级兼容方案

蓝牙技术发展趋势

  1. 蓝牙5.x系列

    • 更远的传输距离(可达300米)
    • 更高的传输速度(2Mbps)
    • 更大的广播数据容量
    • 方向定位功能
  2. 蓝牙音频技术

    • LC3编解码器
    • 多音频流同时传输
    • 助听器支持
  3. 蓝牙网络技术

    • 蓝牙网状网络(Mesh)
    • 大规模设备互联
    • 自组织网络
  4. 蓝牙与物联网融合

    • 低功耗长距离传输
    • 边缘计算集成
    • 5G与蓝牙协同工作
http://www.dtcms.com/a/531888.html

相关文章:

  • 解压版MySQL的安装与卸载
  • C++编程基础(五):字符数组和字符串
  • 在线旅游网站平台有哪些山东泰安房价2023最新价格
  • [3D Max 基础知识分享]—多孔结构模型编辑
  • 【C++篇】C++11入门:踏入C++新世界的大门
  • 爬虫数据清洗可视化案例之全球灾害数据
  • QT(c++)开发自学笔记:4.Qt 3D简易实现
  • Vue3 自定义事件
  • 上海住房和城乡建设厅网站个人备案网站可以做产品推广
  • Android OpenGLES视频剪辑示例源码
  • 做淘宝客导购网站推广wordpress 明星
  • WebForms 页面
  • Leetcode 39
  • 【STM32项目开源】基于STM32的智能水质检测系统
  • 设计模式-迭代器模式(Iterator)
  • GitHub等平台形成的开源文化正在重塑天热e
  • 做网站需要用什么开发软件有哪些制作视频的软件
  • github中获得Personal Access Token
  • 从RDPDD!DrvEscape到RDPWD!ShareClass::UPSendOrders
  • RiPro数据转换CeoMax插件
  • IA复习笔记4 路由
  • 邯郸手机网站建设服务常见的网络推广工具
  • NTRU 加密系统原理及示例:NTRU、CTRU以及ITRU
  • k8s高频面试题汇总
  • 一篇文章理解LRC校验:
  • 石家庄免费网站建设百度收录入口提交查询
  • 专业提供网站建设服务培训学校 网站费用
  • 找做网站公司需要注意什么条件国外网站建设什么价格
  • 阮一峰《TypeScript 教程》学习笔记——tsconfig.json 文件
  • python如何做声音识别