• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 查找设备开发指导
2
3## 简介
4广播与扫描,主要提供了蓝牙设备的开启广播、关闭广播、开启扫描、关闭扫描方法,通过广播和扫描发现对端蓝牙设备,实现低功耗的通信。
5
6## 场景介绍
7主要场景有:
8
9- 开启、关闭广播
10- 开启、关闭扫描
11
12## 接口说明
13
14完整的 JS API 说明以及实例代码请参考:[BLE 接口](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md)。
15
16具体接口说明如下表。
17
18| 接口名                             | 功能描述                                                                       |
19| ---------------------------------- | ------------------------------------------------------------------------------ |
20| startBLEScan()                     | 发起BLE扫描流程。                                                               |
21| stopBLEScan()                      | 停止BLE扫描流程。                                                                |
22| startAdvertising()                 | 开始发送BLE广播。                                                                |
23| disableAdvertising()                | 临时停止BLE广播。                                                                |
24| enableAdvertising()                | 临时启动BLE广播。                                                                |
25| stopAdvertising()                  | 停止发送BLE广播。                                                                |
26| on(type: 'advertisingStateChange') | 订阅BLE广播状态。                                                                |
27| off(type: 'advertisingStateChange')| 取消订阅BLE广播状态。                                                            |
28| on(type: 'BLEDeviceFind')          | 订阅BLE设备发现上报事件。                                                        |
29| off(type: 'BLEDeviceFind')         | 取消订阅BLE设备发现上报事件。                                                     |
30
31## 主要场景开发步骤
32
33### 开启、关闭广播
341. import需要的ble模块。
352. 开启设备的蓝牙。
363. 需要申请权限ohos.permission.ACCESS_BLUETOOTH374. 需要SystemCapability.Communication.Bluetooth.Core系统能力。
385. 开启广播,对端设备扫描该广播。
396. 关闭广播。
407. 示例代码:
41
42    ```ts
43    import { ble } from '@kit.ConnectivityKit';
44    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
45
46    const TAG: string = 'BleAdvertisingManager';
47
48    export class BleAdvertisingManager {
49      private advHandle: number = 0xFF; // default invalid value
50
51      // 1 订阅广播状态
52      public onAdvertisingStateChange() {
53        try {
54          ble.on('advertisingStateChange', (data: ble.AdvertisingStateChangeInfo) => {
55            console.info(TAG, 'bluetooth advertising state = ' + JSON.stringify(data));
56            AppStorage.setOrCreate('advertiserState', data.state);
57          });
58        } catch (err) {
59          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
60        }
61      }
62
63      // 2 首次启动广播
64      public async startAdvertising() {
65        // 2.1 设置广播发送的参数
66        let setting: ble.AdvertiseSetting = {
67          interval: 160,
68          txPower: 0,
69          connectable: true
70        };
71        // 2.2 构造广播数据
72        let manufactureValueBuffer = new Uint8Array(4);
73        manufactureValueBuffer[0] = 1;
74        manufactureValueBuffer[1] = 2;
75        manufactureValueBuffer[2] = 3;
76        manufactureValueBuffer[3] = 4;
77        let serviceValueBuffer = new Uint8Array(4);
78        serviceValueBuffer[0] = 5;
79        serviceValueBuffer[1] = 6;
80        serviceValueBuffer[2] = 7;
81        serviceValueBuffer[3] = 8;
82        let manufactureDataUnit: ble.ManufactureData = {
83          manufactureId: 4567,
84          manufactureValue: manufactureValueBuffer.buffer
85        };
86        let serviceDataUnit: ble.ServiceData = {
87          serviceUuid: "00001888-0000-1000-8000-00805f9b34fb",
88          serviceValue: serviceValueBuffer.buffer
89        };
90        let advData: ble.AdvertiseData = {
91          serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
92          manufactureData: [manufactureDataUnit],
93          serviceData: [serviceDataUnit],
94          includeDeviceName: false // 表示是否携带设备名,可选参数。注意带上设备名时广播包长度不能超出31个字节。
95        };
96        let advResponse: ble.AdvertiseData = {
97          serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
98          manufactureData: [manufactureDataUnit],
99          serviceData: [serviceDataUnit]
100        };
101        // 2.3 构造广播启动完整参数AdvertisingParams
102        let advertisingParams: ble.AdvertisingParams = {
103          advertisingSettings: setting,
104          advertisingData: advData,
105          advertisingResponse: advResponse,
106          duration: 0 // 可选参数,若大于0,则广播发送一段时间后,则会临时停止,可重新启动发送
107        }
108
109        // 2.4 首次启动广播,且获取所启动广播的标识ID
110        try {
111          this.onAdvertisingStateChange();
112          this.advHandle = await ble.startAdvertising(advertisingParams);
113        } catch (err) {
114          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
115        }
116      }
117
118      // 4 临时停止广播,该广播资源仍然存在
119      public async disableAdvertising() {
120        // 4.1 构造临时停止广播参数
121        let advertisingDisableParams: ble.AdvertisingDisableParams = {
122          advertisingId: this.advHandle // 使用首次启动广播时获取到的广播标识ID
123        }
124        // 4.2 临时停止
125        try {
126          await ble.disableAdvertising(advertisingDisableParams);
127        } catch (err) {
128          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
129        }
130      }
131
132      // 5 再次启动广播
133      public async enableAdvertising(enableDuration: number) {
134        // 5.1 构造临时启动广播参数
135        let advertisingEnableParams: ble.AdvertisingEnableParams = {
136          advertisingId: this.advHandle, // 使用首次启动广播时获取到的广播标识ID
137          duration: enableDuration
138        }
139        // 5.2 再次启动
140        try {
141          await ble.enableAdvertising(advertisingEnableParams);
142        } catch (err) {
143          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
144        }
145      }
146
147      // 6 完全关闭广播,释放广播资源
148      public async stopAdvertising() {
149        try {
150          await ble.stopAdvertising(this.advHandle);
151          ble.off('advertisingStateChange', (data: ble.AdvertisingStateChangeInfo) => {
152            console.info(TAG, 'bluetooth advertising state = ' + JSON.stringify(data));
153          });
154        } catch (err) {
155          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
156        }
157      }
158    }
159
160    let bleAdvertisingManager = new BleAdvertisingManager();
161    export default bleAdvertisingManager as BleAdvertisingManager;
162    ```
163
1647. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。
165
166### 开启、关闭扫描
1671. import需要的ble模块。
1682. 开启设备的蓝牙。
1693. 需要申请权限ohos.permission.ACCESS_BLUETOOTH1704. 需要SystemCapability.Communication.Bluetooth.Core系统能力。
1715. 对端设备开启广播。
1726. 本端设备开启扫描,获取扫描结果。
1737. 关闭扫描。
1748. 示例代码:
175
176    ```ts
177    import { ble } from '@kit.ConnectivityKit';
178    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
179
180    const TAG: string = 'BleScanManager';
181    const BLE_ADV_TYPE_FLAG = 0x01;
182    const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_INCOMPLETE = 0x02;
183    const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_COMPLETE = 0x03;
184    const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_INCOMPLETE = 0x04;
185    const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_COMPLETE = 0x05;
186    const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_INCOMPLETE = 0x06;
187    const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_COMPLETE = 0x07;
188    const BLE_ADV_TYPE_LOCAL_NAME_SHORT = 0x08;
189    const BLE_ADV_TYPE_LOCAL_NAME_COMPLETE = 0x09;
190    const BLE_ADV_TYPE_TX_POWER_LEVEL = 0x0A;
191    const BLE_ADV_TYPE_16_BIT_SERVICE_SOLICITATION_UUIDS = 0x14;
192    const BLE_ADV_TYPE_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15;
193    const BLE_ADV_TYPE_32_BIT_SERVICE_SOLICITATION_UUIDS = 0x1F;
194    const BLE_ADV_TYPE_16_BIT_SERVICE_DATA = 0x16;
195    const BLE_ADV_TYPE_32_BIT_SERVICE_DATA = 0x20;
196    const BLE_ADV_TYPE_128_BIT_SERVICE_DATA = 0x21;
197    const BLE_ADV_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
198
199    const BLUETOOTH_UUID_16_BIT_LENGTH = 2;
200    const BLUETOOTH_UUID_32_BIT_LENGTH = 4;
201    const BLUETOOTH_UUID_128_BIT_LENGTH = 16;
202
203    const BLUETOOTH_MANUFACTURE_ID_LENGTH = 2;
204
205    export class BleScanManager {
206      // 1 订阅扫描结果
207      public onScanResult() {
208        ble.on('BLEDeviceFind', (data: Array<ble.ScanResult>) => {
209          if (data.length > 0) {
210            console.info(TAG, 'BLE scan result = ' + data[0].deviceId);
211            this.parseScanResult(data[0].data);
212          }
213        });
214      }
215
216      private parseScanResult(data: ArrayBuffer) {
217        let advData = new Uint8Array(data);
218        if (advData.byteLength == 0) {
219          console.warn(TAG, 'nothing, adv data length is 0');
220          return;
221        }
222        console.info(TAG, 'advData: ' + JSON.stringify(advData));
223
224        let advFlags: number = -1;
225        let txPowerLevel: number = -1;
226        let localName: string = "";
227        let serviceUuids: string[] = [];
228        let serviceSolicitationUuids: string[] = [];
229        let serviceDatas: Record<string, Uint8Array> = {};
230        let manufactureSpecificDatas: Record<number, Uint8Array> = {};
231
232        let curPos = 0;
233        while (curPos < advData.byteLength) {
234          let length = advData[curPos++];
235          if (length == 0) {
236            break;
237          }
238          let advDataLength = length - 1;
239          let advDataType = advData[curPos++];
240          switch (advDataType) {
241            case BLE_ADV_TYPE_FLAG:
242              advFlags = advData[curPos];
243              break;
244            case BLE_ADV_TYPE_LOCAL_NAME_SHORT:
245            case BLE_ADV_TYPE_LOCAL_NAME_COMPLETE:
246              localName = advData.slice(curPos, curPos + advDataLength).toString();
247              break;
248            case BLE_ADV_TYPE_TX_POWER_LEVEL:
249              txPowerLevel = advData[curPos];
250              break;
251            case BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_INCOMPLETE:
252            case BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_COMPLETE:
253              this.parseServiceUuid(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
254              break;
255            case BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_INCOMPLETE:
256            case BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_COMPLETE:
257              this.parseServiceUuid(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
258              break;
259            case BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_INCOMPLETE:
260            case BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_COMPLETE:
261              this.parseServiceUuid(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
262              break;
263            case BLE_ADV_TYPE_16_BIT_SERVICE_SOLICITATION_UUIDS:
264              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength,
265                advData, serviceSolicitationUuids);
266              break;
267            case BLE_ADV_TYPE_32_BIT_SERVICE_SOLICITATION_UUIDS:
268              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength,
269                advData, serviceSolicitationUuids);
270              break;
271            case BLE_ADV_TYPE_128_BIT_SERVICE_SOLICITATION_UUIDS:
272              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength,
273                advData, serviceSolicitationUuids);
274              break;
275            case BLE_ADV_TYPE_16_BIT_SERVICE_DATA:
276              this.parseServiceData(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
277              break;
278            case BLE_ADV_TYPE_32_BIT_SERVICE_DATA:
279              this.parseServiceData(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
280              break;
281            case BLE_ADV_TYPE_128_BIT_SERVICE_DATA:
282              this.parseServiceData(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
283              break;
284            case BLE_ADV_TYPE_MANUFACTURER_SPECIFIC_DATA:
285              this.parseManufactureData(curPos, advDataLength, advData, manufactureSpecificDatas);
286              break;
287            default:
288              break;
289          }
290          curPos += advDataLength;
291        }
292      }
293
294      private parseServiceUuid(uuidLength: number, curPos: number, advDataLength: number,
295        advData: Uint8Array, serviceUuids: string[]) {
296        while (advDataLength > 0) {
297          let tmpData: Uint8Array = advData.slice(curPos, curPos + uuidLength);
298          serviceUuids.push(this.getUuidFromUint8Array(uuidLength, tmpData));
299          advDataLength -= uuidLength;
300          curPos += uuidLength;
301        }
302      }
303
304      private parseServiceSolicitationUuid(uuidLength: number, curPos: number, advDataLength: number,
305        advData: Uint8Array, serviceSolicitationUuids: string[]) {
306        while (advDataLength > 0) {
307          let tmpData: Uint8Array = advData.slice(curPos, curPos + uuidLength);
308          serviceSolicitationUuids.push(this.getUuidFromUint8Array(uuidLength, tmpData));
309          advDataLength -= uuidLength;
310          curPos += uuidLength;
311        }
312      }
313
314      private getUuidFromUint8Array(uuidLength: number, uuidData: Uint8Array): string {
315        let uuid = "";
316        let temp: string = "";
317        for (let i = uuidLength - 1; i > -1; i--) {
318          temp += uuidData[i].toString(16).padStart(2, "0");
319        }
320        switch (uuidLength) {
321          case BLUETOOTH_UUID_16_BIT_LENGTH:
322            uuid = `0000${temp}-0000-1000-8000-00805F9B34FB`;
323            break;
324          case BLUETOOTH_UUID_32_BIT_LENGTH:
325            uuid = `${temp}-0000-1000-8000-00805F9B34FB`;
326            break;
327          case BLUETOOTH_UUID_128_BIT_LENGTH:
328            uuid = `${temp.substring(0, 8)}-${temp.substring(8, 12)}-${temp.substring(12, 16)}-${temp.substring(16, 20)}-${temp.substring(20, 32)}`;
329            break;
330          default:
331            break;
332        }
333        return uuid;
334      }
335
336      private parseServiceData(uuidLength: number, curPos: number, advDataLength: number,
337        advData: Uint8Array, serviceDatas: Record<string, Uint8Array>) {
338        let tmpUuid: Uint8Array = advData.slice(curPos, curPos + uuidLength);
339        let tmpValue: Uint8Array = advData.slice(curPos + uuidLength, curPos + advDataLength);
340        serviceDatas[tmpUuid.toString()] = tmpValue;
341      }
342
343      private parseManufactureData(curPos: number, advDataLength: number,
344        advData: Uint8Array, manufactureSpecificDatas: Record<number, Uint8Array>) {
345        let manufactureId: number = (advData[curPos + 1] << 8) + advData[curPos];
346        let tmpValue: Uint8Array = advData.slice(curPos + BLUETOOTH_MANUFACTURE_ID_LENGTH, curPos + advDataLength);
347        manufactureSpecificDatas[manufactureId] = tmpValue;
348      }
349
350      // 2 开启扫描
351      public startScan() {
352        // 2.1 构造扫描过滤器,需要能够匹配预期的广播包内容
353        let manufactureId = 4567;
354        let manufactureData: Uint8Array = new Uint8Array([1, 2, 3, 4]);
355        let manufactureDataMask: Uint8Array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]);
356        let scanFilter: ble.ScanFilter = { // 根据业务实际情况定义过滤器
357          manufactureId: manufactureId,
358          manufactureData: manufactureData.buffer,
359          manufactureDataMask: manufactureDataMask.buffer
360        };
361
362        // 2.2 构造扫描参数
363        let scanOptions: ble.ScanOptions = {
364          interval: 0,
365          dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
366          matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE
367        }
368        try {
369          this.onScanResult(); // 订阅扫描结果
370          ble.startBLEScan([scanFilter], scanOptions);
371          console.info(TAG, 'startBleScan success');
372        } catch (err) {
373          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
374        }
375      }
376
377      // 3 关闭扫描
378      public stopScan() {
379        try {
380          ble.off('BLEDeviceFind', (data: Array<ble.ScanResult>) => { // 取消订阅扫描结果
381            console.info(TAG, 'off success');
382          });
383          ble.stopBLEScan();
384          console.info(TAG, 'stopBleScan success');
385        } catch (err) {
386          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
387        }
388      }
389    }
390
391    let bleScanManager = new BleScanManager();
392    export default bleScanManager as BleScanManager;
393    ```
394
3958. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。