1# BLE Development
2
3## Introduction
4Bluetooth 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.
5
6## When to Use
7You can use the APIs provided by the **ble** module to:
8
9- Start and stop BLE advertising.
10- Start and stop BLE scanning.
11
12## Available APIs
13
14For details about the APIs and sample code, see [@ohos.bluetooth.ble](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md).
15
16The following table describes the APIs used in this topic.
17
18| API                            | Description                                                                      |
19| ---------------------------------- | ------------------------------------------------------------------------------ |
20| startBLEScan()                     | Starts BLE scanning.                                                              |
21| stopBLEScan()                      | Stops BLE scanning.                                                               |
22| startAdvertising()                 | Starts BLE advertising.                                                               |
23| disableAdvertising()                | Disables BLE advertising temporarily.                                                               |
24| enableAdvertising()                | Enables BLE advertising temporarily.                                                               |
25| stopAdvertising()                  | Stops BLE advertising.                                                               |
26| on(type: 'advertisingStateChange') | Subscribes to BLE advertising state changes.                                                               |
27| off(type: 'advertisingStateChange')| Unsubscribes from BLE advertising state changes.                                                           |
28| on(type: 'BLEDeviceFind')          | Subscribes to the BLE device discovery event.                                                       |
29| off(type: 'BLEDeviceFind')         | Unsubscribes from the BLE device discovery event.                                                    |
30
31## How to Develop
32
33### Starting and Stopping BLE Advertising
341. Import the **ble** module.
352. Enable Bluetooth on the device.
363. Check that the SystemCapability.Communication.Bluetooth.Core capability is available.
374. Start BLE advertising. The peer device scans the advertisement.
385. Stop BLE advertising.
39
40Example:
41
42```ts
43import { ble } from '@kit.ConnectivityKit';
44import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
45
46const TAG: string = 'BleAdvertisingManager';
47
48export class BleAdvertisingManager {
49  private advHandle: number = 0xFF; // default invalid value
50
51  // 1. Subscribe to BLE advertising state changes.
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. Start BLE advertising the first time.
64  public async startAdvertising() {
65    // 2.1 Set BLE advertising parameters.
66    let setting: ble.AdvertiseSetting = {
67      interval: 160,
68      txPower: 0,
69      connectable: true
70    };
71    // 2.2 Construct the data to be advertised.
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 // 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.
95    };
96    let advResponse: ble.AdvertiseData = {
97      serviceUuids: ["00001888-0000-1000-8000-00805f9b34fb"],
98      manufactureData: [manufactureDataUnit],
99      serviceData: [serviceDataUnit]
100    };
101    // 2.3 Construct AdvertisingParams for starting the BLE advertising.
102    let advertisingParams: ble.AdvertisingParams = {
103      advertisingSettings: setting,
104      advertisingData: advData,
105      advertisingResponse: advResponse,
106      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.
107    }
108
109    // 2.4 Start BLE advertising the first time. The ID of the BLE advertising is returned.
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. Disable the BLE advertising temporarily. The advertising resources still exist.
119  public async disableAdvertising() {
120    // 4.1 Construct parameters for temporarily disabling the BLE advertising.
121    let advertisingDisableParams: ble.AdvertisingDisableParams = {
122      advertisingId: this.advHandle // Use the ID of the first BLE advertising.
123    }
124    // 4.2 Disable the BLE advertising temporarily.
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. Enable the BLE advertising again.
133  public async enableAdvertising(enableDuration: number) {
134    // 5.1 Construct the parameters for temporarily enabling the advertising.
135    let advertisingEnableParams: ble.AdvertisingEnableParams = {
136      advertisingId: this.advHandle // Use the ID of the first BLE advertising.
137      duration: enableDuration
138    }
139    // 5.2 Enable BLE advertising again.
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. Stop BLE advertising and release related resources.
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
160let bleAdvertisingManager = new BleAdvertisingManager();
161export default bleAdvertisingManager as BleAdvertisingManager;
162```
163
164For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).
165
166### Starting and Stop BLE Scanning
1671. Import the **ble** module.
1682. Enable Bluetooth on the device.
1693. Check that the SystemCapability.Communication.Bluetooth.Core capability is available.
1704. Start BLE advertising on the peer device.
1715. Start BLE scanning on the local device.
1726. Stop BLE scanning.
173
174Example:
175
176```ts
177import { ble } from '@kit.ConnectivityKit';
178import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
179
180const TAG: string = 'BleScanManager';
181const BLE_ADV_TYPE_FLAG = 0x01;
182const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_INCOMPLETE = 0x02;
183const BLE_ADV_TYPE_16_BIT_SERVICE_UUIDS_COMPLETE = 0x03;
184const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_INCOMPLETE = 0x04;
185const BLE_ADV_TYPE_32_BIT_SERVICE_UUIDS_COMPLETE = 0x05;
186const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_INCOMPLETE = 0x06;
187const BLE_ADV_TYPE_128_BIT_SERVICE_UUIDS_COMPLETE = 0x07;
188const BLE_ADV_TYPE_LOCAL_NAME_SHORT = 0x08;
189const BLE_ADV_TYPE_LOCAL_NAME_COMPLETE = 0x09;
190const BLE_ADV_TYPE_TX_POWER_LEVEL = 0x0A;
191const BLE_ADV_TYPE_16_BIT_SERVICE_SOLICITATION_UUIDS = 0x14;
192const BLE_ADV_TYPE_128_BIT_SERVICE_SOLICITATION_UUIDS = 0x15;
193const BLE_ADV_TYPE_32_BIT_SERVICE_SOLICITATION_UUIDS = 0x1F;
194const BLE_ADV_TYPE_16_BIT_SERVICE_DATA = 0x16;
195const BLE_ADV_TYPE_32_BIT_SERVICE_DATA = 0x20;
196const BLE_ADV_TYPE_128_BIT_SERVICE_DATA = 0x21;
197const BLE_ADV_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
198
199const BLUETOOTH_UUID_16_BIT_LENGTH = 2;
200const BLUETOOTH_UUID_32_BIT_LENGTH = 4;
201const BLUETOOTH_UUID_128_BIT_LENGTH = 16;
202
203const BLUETOOTH_MANUFACTURE_ID_LENGTH = 2;
204
205export class BleScanManager {
206  // 1. Subscribe to the scanning result.
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. Start scanning.
351  public startScan() {
352    // 2.1 Construct a scan filter that matches the expected advertising packet content.
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 = {// Define the filter based on service requirements.
357      manufactureId: manufactureId,
358      manufactureData: manufactureData.buffer,
359      manufactureDataMask: manufactureDataMask.buffer
360    };
361
362    // 2.2 Construct scanning parameters.
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(); // Subscribe to the scanning result.
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. Stop scanning.
378  public stopScan() {
379    try {
380      ble.off('BLEDeviceFind', (data: Array<ble.ScanResult>) => { // Unsubscribe from the scanning result.
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
391let bleScanManager = new BleScanManager();
392export default bleScanManager as BleScanManager;
393```
394
395For details about the error codes, see [Bluetooth Error Codes](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md).