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文件中声明必要的权限:

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

蓝牙状态管理

获取蓝牙状态
ts 复制代码
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);
}
订阅蓝牙状态变化
ts 复制代码
// 定义蓝牙状态变化回调函数
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);
}
开启/关闭蓝牙
ts 复制代码
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来封装这些底层过程:

ts 复制代码
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等)
    • 面向特定应用场景的通信
配对设备
ts 复制代码
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客户端实现示例:

ts 复制代码
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服务端实现示例:

ts 复制代码
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来封装这些底层过程:

ts 复制代码
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客户端实现示例:

ts 复制代码
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服务端实现
ts 复制代码
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与蓝牙协同工作
相关推荐
shenshizhong7 小时前
鸿蒙HDF框架源码分析
前端·源码·harmonyos
宇宙最强的无天佛祖11 小时前
鸿蒙开发中快速获取相册图片的缩略图
harmonyos
冰冷的bin12 小时前
【Harmony】鸿蒙相机拍照使用简单示例
数码相机·华为·harmonyos
七夜zippoe13 小时前
仓颉语言核心特性详解:类型系统与内存安全
人工智能·算法·鸿蒙·仓颉·核心实践
爱笑的眼睛1116 小时前
HarmonyOS RemoteWindow远程窗口组件的分布式能力深度解析
华为·harmonyos
爱笑的眼睛111 天前
HarmonyOS Badge徽标组件:深入消息提示的实现与优化
华为·harmonyos
爱笑的眼睛111 天前
HarmonyOS List组件性能优化:从基础到高级实践
华为·harmonyos
ifeng09181 天前
HarmonyOS实战项目:打造智能家居控制中心(设备发现与控制)
wpf·智能家居·harmonyos
ifeng09181 天前
HarmonyOS分布式数据管理——跨设备数据同步实战
harmonyos