Skip to content
Back to skills

Hmos Connectivity Kit Ble Device Find

ASecurity

实现BLE设备扫描和广播功能,支持多路扫描和广播,需蓝牙权限,适用于查找周边BLE设备和被其他设备发现的场景

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
developmenttypescriptapi

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add IsKenKenYa/skills --skill hmos-connectivity-kit-ble-device-find --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hmos Connectivity Kit Ble Device Find?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hmos Connectivity Kit Ble Device Find
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iskenkenya-hmos-connectivity-kit-ble-device-find/badge)](https://www.skillsdirectory.com/skills/iskenkenya-hmos-connectivity-kit-ble-device-find)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hmos-connectivity-kit-ble-device-find
description: 实现BLE设备扫描和广播功能,支持多路扫描和广播,需蓝牙权限,适用于查找周边BLE设备和被其他设备发现的场景
---

# BLE设备查找技能

## 功能描述

本技能提供了基于低功耗蓝牙(BLE)技术的设备扫描和广播功能实现。通过本技能可以:

1. **BLE扫描**:扫描周边BLE设备,发现目标设备
2. **BLE广播**:发送BLE广播报文,让其他设备发现本机设备

支持API version 15开始的多路扫描和API version 11+的多路广播,提供完整的扫描结果解析和广播数据构造能力。

## 使用场景

### 触发词
- "BLE扫描"
- "BLE广播"
- "查找BLE设备"
- "扫描周边蓝牙设备"
- "发送BLE广播"
- "被其他设备发现"

### 能做
- 扫描周边BLE设备并解析广播报文
- 发送BLE广播报文让其他设备发现本机
- 支持多路扫描和广播管理
- 解析BLE广播报文的各种数据类型(UUID、制造商数据、服务数据等)
- 构造自定义的BLE广播数据

### 绝不做
- 不处理BLE设备连接和数据传输(参考GATT连接技能)
- 不处理经典蓝牙扫描和广播
- 不处理蓝牙配对和认证
- 不处理超出31字节的广播数据(会导致启动失败)

### 补充
- 必须申请ohos.permission.ACCESS_BLUETOOTH权限
- 推荐使用API version 15的多路扫描方式
- 广播数据长度不能超过31字节
- 扫描会消耗硬件资源和影响功耗,需主动停止

## 调用规范和规则

### 输入约束
- 扫描过滤器数量:建议不超过3个(避免资源耗尽)
- 广播数据长度:不超过31字节
- 扫描间隔:最小0ms,推荐值根据功耗要求调整
- 广播间隔:最小20ms,推荐160ms(平衡功耗和发现率)

### 执行约束
- 最大扫描持续时间:建议不超过60秒(避免高功耗)
- 最大广播持续时间:根据业务需求,建议设置duration参数
- API调用频次:避免频繁启动/停止扫描或广播
- 扫描结果上报频次:根据matchMode调整上报频率

### 内容约束
- 禁止生成超过31字节的广播数据
- 禁止使用无效的UUID格式
- 禁止扫描时使用null过滤器(可能扫描到非预期设备)
- 禁止混用不同API version的接口(如API v10的startAdvertising和API v11的stopAdvertising)

### 降级约束
- 权限不足:提示用户申请权限,参考权限申请文档
- 硬件资源耗尽:减少过滤器数量或停止其他扫描流程
- 广播数据过长:压缩数据或移除includeDeviceName
- 蓝牙服务停止:提示用户检查蓝牙开关状态

## 调用流程和步骤

### 步骤1:申请蓝牙权限

**前置校验**:
1. 检查是否已声明ohos.permission.ACCESS_BLUETOOTH权限
2. 检查是否已向用户申请授权
3. 验证权限申请流程是否完成

**权限申请示例**:
```typescript
// 在module.json5中声明权限
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.ACCESS_BLUETOOTH",
        "reason": "$string:ble_permission_reason"
      }
    ]
  }
}
```

参考文档:
- [声明权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions)
- [向用户申请授权](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/request-user-authorization)

### 步骤2:导入API模块

```typescript
import { ble } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
```

### 步骤3:BLE扫描流程(推荐API version 15)

#### 3.1 创建扫描实例

```typescript
let bleScanner: ble.BleScanner = ble.createBleScanner();
console.info('create bleScanner success');
```

#### 3.2 订阅扫描结果上报事件

```typescript
function onReceiveEvent(scanReport: ble.ScanReport) {
  console.info('BLE scan device find result: ' + JSON.stringify(scanReport));
  if (scanReport.scanResult.length > 0) {
    console.info('BLE scan result deviceId: ' + scanReport.scanResult[0].deviceId);
    // 解析广播报文数据
    parseScanResult(scanReport.scanResult[0].data);
  }
}

try {
  bleScanner.on('BLEDeviceFind', onReceiveEvent);
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 3.3 构造扫描过滤器

```typescript
let manufactureId = 4567;
let manufactureData: Uint8Array = new Uint8Array([1, 2, 3, 4]);
let manufactureDataMask: Uint8Array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]);

let scanFilter: ble.ScanFilter = {
  manufactureId: manufactureId,
  manufactureData: manufactureData.buffer,
  manufactureDataMask: manufactureDataMask.buffer,
  // 可选参数
  deviceId: "XX:XX:XX:XX:XX:XX",  // 设备地址
  name: "test",                   // 设备名称
  serviceUuid: "00001888-0000-1000-8000-00805f9b34fb"  // 服务UUID
};
```

#### 3.4 构造扫描配置参数

```typescript
let scanOptions: ble.ScanOptions = {
  interval: 0,  // 扫描间隔,0表示连续扫描
  dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,  // 低功耗模式
  matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE  // 宽松匹配模式
};
```

#### 3.5 发起扫描

```typescript
try {
  await bleScanner.startScan([scanFilter], scanOptions);
  console.info('startBleScan success');
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 3.6 停止扫描

```typescript
try {
  bleScanner.off('BLEDeviceFind', onReceiveEvent);
  await bleScanner.stopScan();
  console.info('stopBleScan success');
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

### 步骤4:BLE广播流程(推荐API version 11+)

#### 4.1 订阅广播状态上报事件

```typescript
function onReceiveEvent(data: ble.AdvertisingStateChangeInfo) {
  console.info('bluetooth advertising state = ' + JSON.stringify(data));
  // 更新广播状态
  AppStorage.setOrCreate('advertiserState', data.state);
}

try {
  ble.on('advertisingStateChange', onReceiveEvent);
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 4.2 设置广播参数

```typescript
let setting: ble.AdvertiseSetting = {
  interval: 160,        // 广播间隔160ms
  txPower: 0,           // 发射功率
  connectable: true     // 可连接广播
};
```

#### 4.3 构造广播数据

```typescript
// 制造商数据
let manufactureValueBuffer = new Uint8Array(4);
manufactureValueBuffer[0] = 1;
manufactureValueBuffer[1] = 2;
manufactureValueBuffer[2] = 3;
manufactureValueBuffer[3] = 4;

let manufactureDataUnit: ble.ManufactureData = {
  manufactureId: 4567,
  manufactureValue: manufactureValueBuffer.buffer
};

// 服务数据
let serviceValueBuffer = new Uint8Array(4);
serviceValueBuffer[0] = 5;
serviceValueBuffer[1] = 6;
serviceValueBuffer[2] = 7;
serviceValueBuffer[3] = 8;

let serviceDataUnit: ble.ServiceData = {
  serviceUuid: "00001999-0000-1000-8000-00805f9b34fb",
  serviceValue: serviceValueBuffer.buffer
};

// 广播数据(不超过31字节)
let advData: ble.AdvertiseData = {
  serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
  manufactureData: [manufactureDataUnit],
  serviceData: [],
  includeDeviceName: false  // 不携带设备名(避免超长)
};

// 扫描回复数据(不超过31字节)
let advResponse: ble.AdvertiseData = {
  serviceUuids: [],
  manufactureData: [],
  serviceData: [serviceDataUnit]
};
```

#### 4.4 首次启动广播

```typescript
let advertisingParams: ble.AdvertisingParams = {
  advertisingSettings: setting,
  advertisingData: advData,
  advertisingResponse: advResponse,
  duration: 0  // 持续发送,不自动停止
};

try {
  let advHandle = await ble.startAdvertising(advertisingParams);
  console.info("advHandle: " + advHandle);
  // 保存广播标识用于后续管理
  this.advHandle = advHandle;
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 4.5 停止指定广播(保留资源)

```typescript
let advertisingDisableParams: ble.AdvertisingDisableParams = {
  advertisingId: this.advHandle
};

try {
  await ble.disableAdvertising(advertisingDisableParams);
  console.info("disable advertising success");
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 4.6 重新启动广播

```typescript
let advertisingEnableParams: ble.AdvertisingEnableParams = {
  advertisingId: this.advHandle,
  duration: 300  // 发送300秒后自动停止
};

try {
  await ble.enableAdvertising(advertisingEnableParams);
  console.info("enable advertising success");
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

#### 4.7 完全停止广播(释放资源)

```typescript
try {
  await ble.stopAdvertising(this.advHandle);
  ble.off('advertisingStateChange', onReceiveEvent);
  console.info("stop advertising success");
} catch (err) {
  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
```

### 步骤5:错误处理和降级方案

#### 5.1 权限错误处理

```typescript
try {
  await bleScanner.startScan([scanFilter], scanOptions);
} catch (err) {
  let businessError = err as BusinessError;
  if (businessError.code === 201) {
    console.error('Permission denied. Please apply for ohos.permission.ACCESS_BLUETOOTH');
    // 降级方案:提示用户申请权限
  }
}
```

#### 5.2 资源耗尽处理

```typescript
try {
  await bleScanner.startScan([scanFilter1, scanFilter2, scanFilter3], scanOptions);
} catch (err) {
  let businessError = err as BusinessError;
  if (businessError.code === 2900009) {
    console.error('Hardware resources exhausted. Reducing filters.');
    // 降级方案:减少过滤器数量
    await bleScanner.startScan([scanFilter1], scanOptions);
  }
}
```

#### 5.3 广播数据过长处理

```typescript
try {
  await ble.startAdvertising(advertisingParams);
} catch (err) {
  let businessError = err as BusinessError;
  if (businessError.code === 2902054) {
    console.error('Advertising data too long. Max 31 bytes.');
    // 降级方案:移除设备名或压缩数据
    advData.includeDeviceName = false;
    await ble.startAdvertising(advertisingParams);
  }
}
```

## 错误码说明

| 错误码 | 说明 | 解决方法 |
|-------|------|---------|
| 201 | Permission denied | 申请ohos.permission.ACCESS_BLUETOOTH权限 |
| 401 | Invalid parameter | 检查参数类型和取值范围,确保UUID格式正确 |
| 801 | Capability not supported | 检查设备是否支持BLE功能 |
| 2900001 | Service stopped | 检查蓝牙服务是否运行,尝试重新启动 |
| 2900003 | Bluetooth disabled | 提示用户打开蓝牙开关 |
| 2900009 | Operation failed / Hardware resources exhausted | 减少过滤器数量或停止其他扫描流程 |
| 2900010 | The number of advertising resources reaches the upper limit | 停止其他广播流程 |
| 2902050 | Ble scan is already started by the app | 先停止当前扫描再重新启动 |
| 2902054 | The length of advertising data exceeds the upper limit | 压缩广播数据,确保不超过31字节 |
| 2902055 | Invalid advertising id | 使用正确的广播标识 |
| 2900099 | Operation failed | 检查操作条件和参数 |

## 编译和修复问题

### 依赖声明

```json
{
  "dependencies": {
    "@kit.ConnectivityKit": "^1.0.0",
    "@kit.BasicServicesKit": "^1.0.0"
  }
}
```

### 环境要求
- HarmonyOS API version 10+(基础BLE功能)
- HarmonyOS API version 11+(推荐多路广播)
- HarmonyOS API version 15+(推荐多路扫描)
- DevEco Studio 3.1+

### 常见编译问题

**问题1:找不到ble模块**
```
Error: Cannot find module '@kit.ConnectivityKit'
```
**解决方法**:确保项目使用HarmonyOS SDK,并在oh-package.json5中添加依赖声明。

**问题2:类型定义错误**
```
Error: Property 'createBleScanner' does not exist on type 'ble'
```
**解决方法**:检查API version是否支持(createBleScanner需要API version 15+)。

**问题3:权限声明缺失**
```
Error: Permission denied
```
**解决方法**:在module.json5中声明ohos.permission.ACCESS_BLUETOOTH权限。

## 常见问题与解决方法

### Q1:扫描不到BLE设备
**原因**:
- 权限未申请或授权
- 蓝牙未开启
- 过滤器设置过于严格
- 目标设备未发送广播

**解决方法**:
- 检查权限申请流程是否完成
- 确认蓝牙开关已打开
- 调整过滤器参数,尝试放宽条件
- 确认目标设备正在发送BLE广播

### Q2:广播启动失败
**原因**:
- 广播数据超过31字节
- 广播资源已达上限
- 蓝牙服务异常

**解决方法**:
- 设置includeDeviceName为false
- 减少广播数据字段
- 先停止其他广播流程
- 检查蓝牙服务状态

### Q3:扫描功耗过高
**原因**:
- 扫描间隔设置为0(连续扫描)
- dutyMode设置为高功耗模式
- 扫描持续时间过长

**解决方法**:
- 设置interval参数为500ms或更大
- 使用SCAN_MODE_LOW_POWER模式
- 设置扫描超时时间,及时停止扫描

### Q4:无法同时启动多路扫描
**原因**:
- API version低于15
- 使用了旧版ble.startBLEScan接口

**解决方法**:
- 使用API version 15+的createBleScanner接口
- 每个BleScanner实例可独立管理扫描流程

### Q5:广播标识无效
**原因**:
- 广播已完全停止(资源已释放)
- 广播标识不匹配

**解决方法**:
- 确认广播流程未调用stopAdvertising完全停止
- 使用首次启动广播时获取的正确标识

## 输出结果报告

执行完成后输出以下信息:

```json
{
  "status": "success",
  "operationType": "BLE_SCAN | BLE_ADVERTISING",
  "deviceCount": 5,
  "advHandle": 123,
  "apiUsed": [
    "ble.createBleScanner",
    "bleScanner.startScan",
    "bleScanner.stopScan",
    "bleScanner.on",
    "bleScanner.off",
    "ble.startAdvertising",
    "ble.stopAdvertising",
    "ble.enableAdvertising",
    "ble.disableAdvertising"
  ],
  "executionTime": "10s",
  "powerConsumption": "low"
}
```

## 参考文档

- [BLE开发指南](references/ble-development-guide.md)
- [BLE API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-bluetooth-ble)

## 完整示例代码

- [BLE扫描完整示例](assets/ble_scan_example.ets)
- [BLE广播完整示例](assets/ble_advertising_example.ets)

## 测试用例

### 正向测试用例
- [BLE扫描测试](tests/test_ble_scan_positive.ets):测试正常扫描流程
- [BLE广播测试](tests/test_ble_advertising_positive.ets):测试正常广播流程

### 边界测试用例
- [最大过滤器数量测试](tests/test_ble_scan_max_filters.ets):测试3个过滤器场景
- [最大广播数据长度测试](tests/test_ble_advertising_max_length.ets):测试31字节广播数据

### 异常测试用例
- [权限缺失测试](tests/test_ble_permission_denied.ets):测试未申请权限场景
- [蓝牙服务异常测试](tests/test_ble_service_stopped.ets):测试蓝牙服务停止场景
- [广播数据超长测试](tests/test_ble_advertising_data_long.ets):测试超过31字节场景

Files in this skill

  • SUB_SKILL.md15.1 KB
  • assets/ble_advertising_example.ets3.6 KB
  • assets/ble_scan_example.ets8.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…