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).