• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# BLE Advertising and Scanning
2
3## Introduction
4
5Bluetooth advertising and scanning help discover Bluetooth-enabled devices and implement BLE communication. This topic walks you through on how to start and stop Bluetooth advertising and scanning.
6
7## When to Use
8
9You can use the APIs provided by the **ble** module to:
10
11- Start and stop BLE advertising.
12- Start and stop BLE scanning.
13
14## Available APIs
15
16For details about the APIs and sample code, see [@ohos.bluetooth.ble](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md).
17
18The following table describes the related APIs.
19
20| API                            | Description                                                                      |
21| ---------------------------------- | ------------------------------------------------------------------------------ |
22| startBLEScan()                     | Starts BLE scanning.                                                              |
23| stopBLEScan()                      | Stops BLE scanning.                                                               |
24| startAdvertising()                 | Starts BLE advertising.                                                               |
25| disableAdvertising()                | Disables BLE advertising temporarily.                                                               |
26| enableAdvertising()                | Enables BLE advertising temporarily.                                                               |
27| stopAdvertising()                  | Stops BLE advertising.                                                               |
28| on(type: 'advertisingStateChange') | Subscribes to BLE advertising state changes.                                                               |
29| off(type: 'advertisingStateChange')| Unsubscribes from BLE advertising state changes.                                                           |
30| on(type: 'BLEDeviceFind')          | Subscribes to the BLE device discovery event.                                                       |
31| off(type: 'BLEDeviceFind')         | Unsubscribes from the BLE device discovery event.                                                    |
32
33## How to Develop
34
35### Starting and Stopping BLE Advertising
361. Import the **ble** module.
372. Enable Bluetooth on the device.
383. Apply for the **ohos.permission.ACCESS_BLUETOOTH** permission.
394. Check that the SystemCapability.Communication.Bluetooth.Core capability is available.
405. Start BLE advertising. The peer device scans the advertisement.
416. Stop BLE advertising.
427. Example:
43
44    ```ts
45    import { ble } from '@kit.ConnectivityKit';
46    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
47
48    const TAG: string = 'BleAdvertisingManager';
49
50    export class BleAdvertisingManager {
51      private advHandle: number = 0xFF; // default invalid value
52
53      // 1. Subscribe to BLE advertising state changes.
54      public onAdvertisingStateChange() {
55        try {
56          ble.on('advertisingStateChange', (data: ble.AdvertisingStateChangeInfo) => {
57            console.info(TAG, 'bluetooth advertising state = ' + JSON.stringify(data));
58            AppStorage.setOrCreate('advertiserState', data.state);
59          });
60        } catch (err) {
61          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
62        }
63      }
64
65      // 2. Start BLE advertising the first time.
66      public async startAdvertising() {
67        // 2.1 Set BLE advertising parameters.
68        let setting: ble.AdvertiseSetting = {
69          interval: 160,
70          txPower: 0,
71          connectable: true
72        };
73        // 2.2 Construct the data to be advertised.
74        let manufactureValueBuffer = new Uint8Array(4);
75        manufactureValueBuffer[0] = 1;
76        manufactureValueBuffer[1] = 2;
77        manufactureValueBuffer[2] = 3;
78        manufactureValueBuffer[3] = 4;
79        let serviceValueBuffer = new Uint8Array(4);
80        serviceValueBuffer[0] = 5;
81        serviceValueBuffer[1] = 6;
82        serviceValueBuffer[2] = 7;
83        serviceValueBuffer[3] = 8;
84        let manufactureDataUnit: ble.ManufactureData = {
85          manufactureId: 4567,
86          manufactureValue: manufactureValueBuffer.buffer
87        };
88        let serviceDataUnit: ble.ServiceData = {
89          serviceUuid: "00001888-0000-1000-8000-00805f9b34fb",
90          serviceValue: serviceValueBuffer.buffer
91        };
92        let advData: ble.AdvertiseData = {
93          serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
94          manufactureData: [manufactureDataUnit],
95          serviceData: [serviceDataUnit],
96          includeDeviceName: false // Whether the device name is carried. This parameter is optional. Note that the length of an advertising packet including the device name cannot exceed 31 bytes.
97        };
98        let advResponse: ble.AdvertiseData = {
99          serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
100          manufactureData: [manufactureDataUnit],
101          serviceData: [serviceDataUnit]
102        };
103        // 2.3 Construct AdvertisingParams for starting the BLE advertising.
104        let advertisingParams: ble.AdvertisingParams = {
105          advertisingSettings: setting,
106          advertisingData: advData,
107          advertisingResponse: advResponse,
108          duration: 0 // This parameter is optional. If the value is greater than 0, the advertising stops temporarily after a period of time. You can restart it as required.
109        }
110
111        // 2.4 Start BLE advertising the first time. The ID of the BLE advertising is returned.
112        try {
113          this.onAdvertisingStateChange();
114          this.advHandle = await ble.startAdvertising(advertisingParams);
115        } catch (err) {
116          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
117        }
118      }
119
120      // 4. Disable the BLE advertising temporarily. The advertising resources still exist.
121      public async disableAdvertising() {
122        // 4.1 Construct parameters for temporarily disabling the BLE advertising.
123        let advertisingDisableParams: ble.AdvertisingDisableParams = {
124          advertisingId: this.advHandle // Use the ID of the first BLE advertising.
125        }
126        // 4.2 Disable the BLE advertising temporarily.
127        try {
128          await ble.disableAdvertising(advertisingDisableParams);
129        } catch (err) {
130          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
131        }
132      }
133
134      // 5. Enable the BLE advertising again.
135      public async enableAdvertising(enableDuration: number) {
136        // 5.1 Construct the parameters for temporarily enabling the advertising.
137        let advertisingEnableParams: ble.AdvertisingEnableParams = {
138          advertisingId: this.advHandle // Use the ID of the first BLE advertising.
139          duration: enableDuration
140        }
141        // 5.2 Enable BLE advertising again.
142        try {
143          await ble.enableAdvertising(advertisingEnableParams);
144        } catch (err) {
145          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
146        }
147      }
148
149      // 6. Stop BLE advertising and release related resources.
150      public async stopAdvertising() {
151        try {
152          await ble.stopAdvertising(this.advHandle);
153          ble.off('advertisingStateChange', (data: ble.AdvertisingStateChangeInfo) => {
154            console.info(TAG, 'bluetooth advertising state = ' + JSON.stringify(data));
155          });
156        } catch (err) {
157          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
158        }
159      }
160    }
161
162    let bleAdvertisingManager = new BleAdvertisingManager();
163    export default bleAdvertisingManager as BleAdvertisingManager;
164    ```
165
1667. For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
167
168### Starting and Stop BLE Scanning
1691. Import the **ble** module.
1702. Enable Bluetooth on the device.
1713. Apply for the **ohos.permission.ACCESS_BLUETOOTH** permission.
1724. Check that the SystemCapability.Communication.Bluetooth.Core capability is available.
1735. Start BLE advertising on the peer device.
1746. Start BLE scanning on the local device.
1757. Stop BLE scanning.
1768. Example:
177
178    ```ts
179    import { ble } from '@kit.ConnectivityKit';
180    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
181
182    const TAG: string = 'BleScanManager';
183    const BLE_ADV_TYPE_FLAG = 0x01;
184    const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_INCOMPLETE = 0x02;
185    const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_COMPLETE = 0x03;
186    const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_INCOMPLETE = 0x04;
187    const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_COMPLETE = 0x05;
188    const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_INCOMPLETE = 0x06;
189    const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_COMPLETE = 0x07;
190    const BLE_ADV_TYPE_LOCAL_NAME_SHORT = 0x08;
191    const BLE_ADV_TYPE_LOCAL_NAME_COMPLETE = 0x09;
192    const BLE_ADV_TYPE_TX_POWER_LEVEL = 0x0A;
193    const BLE_ADV_TYPE_16_BIT_SERVICE_SOLICITATION_UUIDS = 0x14;
194    const BLE_ADV_TYPE_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15;
195    const BLE_ADV_TYPE_32_BIT_SERVICE_SOLICITATION_UUIDS = 0x1F;
196    const BLE_ADV_TYPE_16_BIT_SERVICE_DATA = 0x16;
197    const BLE_ADV_TYPE_32_BIT_SERVICE_DATA = 0x20;
198    const BLE_ADV_TYPE_128_BIT_SERVICE_DATA = 0x21;
199    const BLE_ADV_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
200
201    const BLUETOOTH_UUID_16_BIT_LENGTH = 2;
202    const BLUETOOTH_UUID_32_BIT_LENGTH = 4;
203    const BLUETOOTH_UUID_128_BIT_LENGTH = 16;
204
205    const BLUETOOTH_MANUFACTURE_ID_LENGTH = 2;
206
207    export class BleScanManager {
208      // 1. Subscribe to the scanning result.
209      public onScanResult() {
210        ble.on('BLEDeviceFind', (data: Array<ble.ScanResult>) => {
211          if (data.length > 0) {
212            console.info(TAG, 'BLE scan result = ' + data[0].deviceId);
213            this.parseScanResult(data[0].data);
214          }
215        });
216      }
217
218      private parseScanResult(data: ArrayBuffer) {
219        let advData = new Uint8Array(data);
220        if (advData.byteLength == 0) {
221          console.warn(TAG, 'nothing, adv data length is 0');
222          return;
223        }
224        console.info(TAG, 'advData: ' + JSON.stringify(advData));
225
226        let advFlags: number = -1;
227        let txPowerLevel: number = -1;
228        let localName: string = "";
229        let serviceUuids: string[] = [];
230        let serviceSolicitationUuids: string[] = [];
231        let serviceDatas: Record<string, Uint8Array> = {};
232        let manufactureSpecificDatas: Record<number, Uint8Array> = {};
233
234        let curPos = 0;
235        while (curPos < advData.byteLength) {
236          let length = advData[curPos++];
237          if (length == 0) {
238            break;
239          }
240          let advDataLength = length - 1;
241          let advDataType = advData[curPos++];
242          switch (advDataType) {
243            case BLE_ADV_TYPE_FLAG:
244              advFlags = advData[curPos];
245              break;
246            case BLE_ADV_TYPE_LOCAL_NAME_SHORT:
247            case BLE_ADV_TYPE_LOCAL_NAME_COMPLETE:
248              localName = advData.slice(curPos, curPos + advDataLength).toString();
249              break;
250            case BLE_ADV_TYPE_TX_POWER_LEVEL:
251              txPowerLevel = advData[curPos];
252              break;
253            case BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_INCOMPLETE:
254            case BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_COMPLETE:
255              this.parseServiceUuid(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
256              break;
257            case BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_INCOMPLETE:
258            case BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_COMPLETE:
259              this.parseServiceUuid(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
260              break;
261            case BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_INCOMPLETE:
262            case BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_COMPLETE:
263              this.parseServiceUuid(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength, advData, serviceUuids);
264              break;
265            case BLE_ADV_TYPE_16_BIT_SERVICE_SOLICITATION_UUIDS:
266              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength,
267                advData, serviceSolicitationUuids);
268              break;
269            case BLE_ADV_TYPE_32_BIT_SERVICE_SOLICITATION_UUIDS:
270              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength,
271                advData, serviceSolicitationUuids);
272              break;
273            case BLE_ADV_TYPE_128_BIT_SERVICE_SOLICITATION_UUIDS:
274              this.parseServiceSolicitationUuid(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength,
275                advData, serviceSolicitationUuids);
276              break;
277            case BLE_ADV_TYPE_16_BIT_SERVICE_DATA:
278              this.parseServiceData(BLUETOOTH_UUID_16_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
279              break;
280            case BLE_ADV_TYPE_32_BIT_SERVICE_DATA:
281              this.parseServiceData(BLUETOOTH_UUID_32_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
282              break;
283            case BLE_ADV_TYPE_128_BIT_SERVICE_DATA:
284              this.parseServiceData(BLUETOOTH_UUID_128_BIT_LENGTH, curPos, advDataLength, advData, serviceDatas);
285              break;
286            case BLE_ADV_TYPE_MANUFACTURER_SPECIFIC_DATA:
287              this.parseManufactureData(curPos, advDataLength, advData, manufactureSpecificDatas);
288              break;
289            default:
290              break;
291          }
292          curPos += advDataLength;
293        }
294      }
295
296      private parseServiceUuid(uuidLength: number, curPos: number, advDataLength: number,
297        advData: Uint8Array, serviceUuids: string[]) {
298        while (advDataLength > 0) {
299          let tmpData: Uint8Array = advData.slice(curPos, curPos + uuidLength);
300          serviceUuids.push(this.getUuidFromUint8Array(uuidLength, tmpData));
301          advDataLength -= uuidLength;
302          curPos += uuidLength;
303        }
304      }
305
306      private parseServiceSolicitationUuid(uuidLength: number, curPos: number, advDataLength: number,
307        advData: Uint8Array, serviceSolicitationUuids: string[]) {
308        while (advDataLength > 0) {
309          let tmpData: Uint8Array = advData.slice(curPos, curPos + uuidLength);
310          serviceSolicitationUuids.push(this.getUuidFromUint8Array(uuidLength, tmpData));
311          advDataLength -= uuidLength;
312          curPos += uuidLength;
313        }
314      }
315
316      private getUuidFromUint8Array(uuidLength: number, uuidData: Uint8Array): string {
317        let uuid = "";
318        let temp: string = "";
319        for (let i = uuidLength - 1; i > -1; i--) {
320          temp += uuidData[i].toString(16).padStart(2, "0");
321        }
322        switch (uuidLength) {
323          case BLUETOOTH_UUID_16_BIT_LENGTH:
324            uuid = `0000${temp}-0000-1000-8000-00805F9B34FB`;
325            break;
326          case BLUETOOTH_UUID_32_BIT_LENGTH:
327            uuid = `${temp}-0000-1000-8000-00805F9B34FB`;
328            break;
329          case BLUETOOTH_UUID_128_BIT_LENGTH:
330            uuid = `${temp.substring(0, 8)}-${temp.substring(8, 12)}-${temp.substring(12, 16)}-${temp.substring(16, 20)}-${temp.substring(20, 32)}`;
331            break;
332          default:
333            break;
334        }
335        return uuid;
336      }
337
338      private parseServiceData(uuidLength: number, curPos: number, advDataLength: number,
339        advData: Uint8Array, serviceDatas: Record<string, Uint8Array>) {
340        let tmpUuid: Uint8Array = advData.slice(curPos, curPos + uuidLength);
341        let tmpValue: Uint8Array = advData.slice(curPos + uuidLength, curPos + advDataLength);
342        serviceDatas[tmpUuid.toString()] = tmpValue;
343      }
344
345      private parseManufactureData(curPos: number, advDataLength: number,
346        advData: Uint8Array, manufactureSpecificDatas: Record<number, Uint8Array>) {
347        let manufactureId: number = (advData[curPos + 1] << 8) + advData[curPos];
348        let tmpValue: Uint8Array = advData.slice(curPos + BLUETOOTH_MANUFACTURE_ID_LENGTH, curPos + advDataLength);
349        manufactureSpecificDatas[manufactureId] = tmpValue;
350      }
351
352      // 2. Start scanning.
353      public startScan() {
354        // 2.1 Construct a scan filter that matches the expected advertising packet content.
355        let manufactureId = 4567;
356        let manufactureData: Uint8Array = new Uint8Array([1, 2, 3, 4]);
357        let manufactureDataMask: Uint8Array = new Uint8Array([0xFF, 0xFF, 0xFF, 0xFF]);
358        let scanFilter: ble.ScanFilter = {// Define the filter based on service requirements.
359          manufactureId: manufactureId,
360          manufactureData: manufactureData.buffer,
361          manufactureDataMask: manufactureDataMask.buffer
362        };
363
364        // 2.2 Construct scanning parameters.
365        let scanOptions: ble.ScanOptions = {
366          interval: 0,
367          dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
368          matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE
369        }
370        try {
371          this.onScanResult(); // Subscribe to the scanning result.
372          ble.startBLEScan([scanFilter], scanOptions);
373          console.info(TAG, 'startBleScan success');
374        } catch (err) {
375          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
376        }
377      }
378
379      // 3. Stop scanning.
380      public stopScan() {
381        try {
382          ble.off('BLEDeviceFind', (data: Array<ble.ScanResult>) => { // Unsubscribe from the scanning result.
383            console.info(TAG, 'off success');
384          });
385          ble.stopBLEScan();
386          console.info(TAG, 'stopBleScan success');
387        } catch (err) {
388          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
389        }
390      }
391    }
392
393    let bleScanManager = new BleScanManager();
394    export default bleScanManager as BleScanManager;
395    ```
396
3978. For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
398