鸿蒙学习实战之路-蓝牙设备查找完全指南

最近好多朋友问我:“西兰花啊,我想在鸿蒙应用里查找周边的蓝牙设备,咋整啊?” 害,这问题可问对人了!今天我就把官方文档里的设备查找功能,用咱前端厨子的方式给你掰扯明白~


🥦 先唠唠为啥需要这功能

你想想,做个智能家居 app 得连蓝牙音箱吧?做个体脂秤 app 得连设备吧?甚至做个简单的文件传输 app 也得先找到对方设备啊!所以"查找设备"就是蓝牙功能的基础,相当于咱们做饭前得先把食材找出来~

第一步:配齐"锅碗瓢盆"(申请权限+导入模块)

1.1 先搞定权限

就像做饭得先洗手一样,用蓝牙功能得先申请权限。在你的 module.json5 里加上这个:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.ACCESS_BLUETOOTH"
      }
    ]
  }
}

1.2 导入必要的模块

做饭得先把锅碗瓢盆摆好,写代码也得先把模块导进来:

import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

第二步:开始"买菜"(扫描周边设备)

扫描设备就像在菜市场找特定的菜,得先支个摊(订阅结果),再吆喝(开始扫描),找到菜了就收摊(停止扫描)。

2.1 先支个摊:订阅扫描结果

鸿蒙 API 18+ 支持更详细的设备信息(地址、信号强度、名称、类型),推荐用这个:

// 定义扫描结果上报回调函数
function on扫描结果上报(data: Array<connection.DiscoveryResult>) {
  console.info('发现蓝牙设备: ' + JSON.stringify(data)); // 包含设备地址、信号强度等详情
}

try {
  // 发起订阅 - 相当于支摊等菜来
  connection.on('discoveryResult', on扫描结果上报);
} catch (err) {
  console.error('订阅失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
}

🥦 西兰花小贴士
如果你的应用要兼容 API 17-,就用 connection.on('bluetoothDeviceFind', ...),不过只能获取到设备地址哦~

2.2 开始吆喝:发起设备扫描

try {
  // 先看看是不是已经在扫描了 - 别重复吆喝
  let isScanning = connection.isBluetoothDiscovering();
  if (!isScanning) {
    // 开始扫描 - 相当于吆喝"收菜啦"
    connection.startBluetoothDiscovery();
  }
} catch (err) {
  console.error('扫描失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
}

🥦 西兰花警告
扫描默认会持续约12秒自动停止,别以为它会一直扫哦!

2.3 找到菜了:停止扫描

扫描很费电,就像开着煤气灶不做饭一样浪费,找到设备赶紧停止:

try {
  // 看看是不是还在扫描
  let isScanning = connection.isBluetoothDiscovering();
  if (isScanning) {
    // 停止扫描 - 相当于收摊
    connection.stopBluetoothDiscovery();
  }
  // 不需要的话就取消订阅
  connection.off('discoveryResult', on扫描结果上报);
} catch (err) {
  console.error('停止扫描失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
}

第三步:决定"要不要让人发现"(设置本机扫描模式)

有时候咱们不仅要找别人,也要让别人找到咱们。这就像你在菜市场找菜,也可以举个牌子让卖家找到你~

try {
  // 获取当前扫描模式
  let currentMode: connection.ScanMode = connection.getBluetoothScanMode();
  console.info('当前扫描模式: ' + currentMode);
  
  // 如果不是"可被发现+可被连接"模式,就改成这个
  if (currentMode != connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE) {
    connection.setBluetoothScanMode(
      connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, 
      0
    );
  }
} catch (err) {
  console.error('设置扫描模式失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
}

🥦 西兰花小贴士

  • SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE:既可以被发现,也可以被连接(相当于举着牌子喊"我在这!")
  • SCAN_MODE_CONNECTABLE:只能被连接,不能被发现(相当于站在那但没举牌子)

第四步:看看"常去的摊位"(查找已配对设备)

有时候咱们不需要重新找,常买的菜(常用的设备)已经在咱们的"黑名单"里了(开玩笑,是配对列表)。直接去常去的摊位买更方便~

try {
  // 获取已配对的设备列表
  let pairedDevices = connection.getPairedDevices();
  console.info('已配对设备: ' + JSON.stringify(pairedDevices));
  
  // 如果已经知道设备地址,可以直接查配对状态
  if (pairedDevices.length > 0) {
    let firstDevice = pairedDevices[0];
    let pairState = connection.getPairState(firstDevice);
    console.info('设备 ' + firstDevice + ' 的配对状态是: ' + pairState);
  }
} catch (err) {
  console.error('查询配对设备失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
}

🥦 给你整个"预制菜"(完整工具类)

为了方便大家使用,我把上面的功能封装成了一个工具类,就像超市里的预制菜,拿回去直接炒就行~

import { connection } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class 设备发现管理器 {
  // 扫描结果回调
  on扫描结果上报 = (data: Array<connection.DiscoveryResult>) => {
    console.info('发现蓝牙设备: ' + JSON.stringify(data));
  };

  // 开始扫描
  public 开始扫描() {
    try {
      // 先订阅结果
      connection.on('discoveryResult', this.on扫描结果上报);
    } catch (err) {
      console.error('订阅扫描结果失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
    }

    try {
      // 检查是否正在扫描
      let isScanning = connection.isBluetoothDiscovering();
      if (!isScanning) {
        // 开始扫描
        connection.startBluetoothDiscovery();
      }
    } catch (err) {
      console.error('开始扫描失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
    }
  }

  // 停止扫描
  public 停止扫描() {
    try {
      // 检查是否正在扫描
      let isScanning = connection.isBluetoothDiscovering();
      if (isScanning) {
        // 停止扫描
        connection.stopBluetoothDiscovery();
      }
      // 取消订阅
      connection.off('discoveryResult', this.on扫描结果上报);
    } catch (err) {
      console.error('停止扫描失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
    }
  }

  // 设置本机为可被发现模式
  public 设置为可被发现() {
    try {
      // 获取当前模式
      let currentMode: connection.ScanMode = connection.getBluetoothScanMode();
      console.info('当前扫描模式: ' + currentMode);
      
      // 如果不是可被发现模式,就改
      if (currentMode != connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE) {
        connection.setBluetoothScanMode(
          connection.ScanMode.SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, 
          0
        );
      }
    } catch (err) {
      console.error('设置扫描模式失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
    }
  }

  // 获取已配对设备
  public 获取已配对设备() {
    try {
      // 获取已配对设备列表
      let pairedDevices = connection.getPairedDevices();
      console.info('已配对设备: ' + JSON.stringify(pairedDevices));
      
      // 检查第一个设备的配对状态
      if (pairedDevices.length > 0) {
        let firstDevice = pairedDevices[0];
        let pairState = connection.getPairState(firstDevice);
        console.info('设备 ' + firstDevice + ' 的配对状态是: ' + pairState);
      }
    } catch (err) {
      console.error('查询配对设备失败: ' + (err as BusinessError).code + ', ' + (err as BusinessError).message);
    }
  }
}

// 导出实例,方便全局使用
let 设备发现管理器实例 = new 设备发现管理器();
export default 设备发现管理器实例 as 设备发现管理器;

咋用这个工具类呢?

就像炒预制菜一样简单:

import 设备发现管理器 from './DeviceDiscoveryManager';

// 开始扫描周边设备
设备发现管理器.开始扫描();

// 过会儿停止扫描
设备发现管理器.停止扫描();

// 获取已配对设备
设备发现管理器.获取已配对设备();

// 设置本机为可被发现
设备发现管理器.设置为可被发现();

是不是超简单?^^

🥦 最后再啰嗦两句

  1. 扫描别太久:扫描很费蓝牙资源,找到设备就赶紧停
  2. 权限别忘要:没权限的话啥都干不了,就像没洗手做饭会被打一样
  3. API版本要注意:API 18+ 用 discoveryResult,API 17- 用 bluetoothDeviceFind
  4. 配对状态要检查:有时候设备虽然在列表里,但可能已经取消配对了

📚 推荐资料


我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐