1# 连接和传输数据 2 3<!--Kit: Connectivity Kit--> 4<!--Subsystem: Communication--> 5<!--Owner: @enjoy_sunshine--> 6<!--Designer: @chengguohong; @tangjia15--> 7<!--Tester: @wangfeng517--> 8<!--Adviser: @zhang_yixin13--> 9 10## 简介 11本指南主要提供了基于通用属性协议(Generic Attribute Profile,GATT)实现BLE设备间连接和传输数据的开发指导。当两个设备间进行GATT通信交互时,依据设备功能的不同,可区分为GATT客户端和GATT服务端,本指南将分别介绍客户端与服务端的实现方法。 12 13GATT是低功耗蓝牙(BLE)的核心协议,定义了基于服务(Service)、特征值(Characteristic)和描述符(Descriptor)进行蓝牙通信和传输数据的机制。相关术语介绍请参考[Connectivity Kit术语](../terminology.md)。 14 15## 实现原理 16客户端获取到服务端的设备地址后,即可向服务端发起连接。服务端设备地址可以通过BLE扫描流程获取。待两端连接成功后,即可向服务端发起服务查询、读写特征值和接收通知等操作,从而实现向服务端发送数据或者接收服务端数据的功能。 17 18服务端需要发送BLE广播才能被客户端发现。服务端需要支持客户端需要连接的服务,等待客户端的连接请求即可。待两端连接成功后,即可接收客户端的读写特征值和发送通知等操作,从而实现接收客户端数据或者向客户端发送数据的功能。 19 20客户端的BLE扫描和服务端的BLE广播流程,请参考[查找设备](ble-development-guide.md)。 21 22## 开发步骤 23 24### 申请蓝牙权限 25需要申请权限ohos.permission.ACCESS_BLUETOOTH。如何配置和申请权限,请参考[声明权限](../../security/AccessToken/declare-permissions.md)和[向用户申请授权](../../security/AccessToken/request-user-authorization.md)。 26 27### 导入所需API模块 28导入ble、constant和错误码模块。 29```ts 30import { ble, constant } from '@kit.ConnectivityKit'; 31import { BusinessError } from '@kit.BasicServicesKit'; 32``` 33### 客户端 34 35**1. 创建客户端实例**<br> 36客户端通过查找设备流程搜索到目标设备后,即可构造客户端实例,后续所有操作都基于该客户端实例。 37```ts 38// 此处是伪代码 39let device = 'XX:XX:XX:XX:XX:XX'; 40 41try { 42 let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 43} catch (err) { 44 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 45} 46``` 47 48**2. 订阅连接状态变化事件**<br> 49通过订阅连接状态变化事件,可以获取实时的GATT连接状态。整个连接过程会涉及多种状态的跃迁,其中[STATE_CONNECTED](../../reference/apis-connectivity-kit/js-apis-bluetooth-constant.md#profileconnectionstate)表示已连接,[STATE_DISCONNECTED](../../reference/apis-connectivity-kit/js-apis-bluetooth-constant.md#profileconnectionstate)表示已断连。 50```ts 51// 此处是伪代码 52let device = 'XX:XX:XX:XX:XX:XX'; 53 54function clientConnectStateChanged(state: ble.BLEConnectionChangeState) { 55 console.info('bluetooth connect state changed'); 56 let connectState: ble.ProfileConnectionState = state.state; 57} 58 59try { 60 let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 61 gattClient.on('BLEConnectionStateChange', clientConnectStateChanged); 62} catch (err) { 63 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 64} 65``` 66 67**3. 发起连接**<br> 68通过创建的客户端实例,直接发起连接即可。通过连接状态变化事件判断是否已连接成功。 69```ts 70// 此处是伪代码 71let device = 'XX:XX:XX:XX:XX:XX'; 72 73try { 74 let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 75 gattClient.connect(); 76} catch (err) { 77 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 78} 79``` 80 81**4. 服务发现**<br> 82服务发现是获取服务端支持的所有服务能力集合的过程。客户端需要根据服务发现结果,判断服务端是否存在应用需要的服务能力。 83- 后续的读写特征值、读写描述符等操作都需要在服务发现操作完成后进行,否则会失败。 84- 后续的读写等操作中指定的特征值或描述符必须包含在服务能力集合中,否则会失败。 85```ts 86// 此处是伪代码 87let device = 'XX:XX:XX:XX:XX:XX'; 88 89try { 90 let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 91 // 此处是伪代码,需要连接上后,才可以调用 92 gattClient.getServices().then((result: Array<ble.GattService>) => { 93 console.info('getServices successfully:' + JSON.stringify(result)); 94 }); 95} catch (err) { 96 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 97} 98``` 99 100**5. 传输数据**<br> 101传输数据通过操作服务端的特征值或者描述符实现。 102 103**5.1 读取或写入特征值**<br> 104读取特征值操作,可以获取服务端特征值的数据内容。<br> 105写入特征值操作,可以更新服务端特征值的数据内容。<br> 106相关API请参考[readCharacteristicValue](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#readcharacteristicvalue)和[writeCharacteristicValue](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#writecharacteristicvalue)。 107```ts 108// 此处是伪代码 109let device = 'XX:XX:XX:XX:XX:XX'; 110let descriptors: Array<ble.BLEDescriptor> = []; 111let bufferDesc = new ArrayBuffer(2); 112let descV = new Uint8Array(bufferDesc); 113descV[0] = 11; 114let descriptor: ble.BLEDescriptor = { 115 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 116 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 117 descriptorUuid: '00008888-0000-1000-8000-00805F9B34FB', 118 descriptorValue: bufferDesc 119}; 120descriptors[0] = descriptor; 121let bufferCCC = new ArrayBuffer(2); 122let cccV = new Uint8Array(bufferCCC); 123cccV[0] = 1; 124let characteristic: ble.BLECharacteristic = { 125 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 126 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 127 characteristicValue: bufferCCC, 128 descriptors:descriptors 129}; 130 131let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 132 133// 读取特征值 134try { 135 gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => { 136 }); 137} catch (err) { 138 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 139} 140 141// 写入特征值 142try { 143 gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => { 144 if (err) { 145 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 146 return; 147 } 148 console.info(TAG, 'writeCharacteristicValue success'); 149 }); 150} catch (err) { 151 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 152} 153``` 154 155**5.2 读取或写入描述符**<br> 156读取描述符操作,可以获取服务端描述符的数据内容。<br> 157写入描述符操作,可以更新服务端描述符的数据内容。<br> 158相关API请参考[readDescriptorValue](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#readdescriptorvalue)和[writeDescriptorValue](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#writedescriptorvalue)。 159```ts 160// 此处是伪代码 161let device = 'XX:XX:XX:XX:XX:XX'; 162let bufferDesc = new ArrayBuffer(2); 163let descV = new Uint8Array(bufferDesc); 164descV[0] = 11; 165let descriptor: ble.BLEDescriptor = { 166 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 167 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 168 descriptorUuid: '00008888-0000-1000-8000-00805F9B34FB', 169 descriptorValue: bufferDesc 170}; 171let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 172 173// 读取描述符 174try { 175 gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => { 176 }); 177} catch (err) { 178 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 179} 180 181// 写入描述符 182try { 183 gattClient.writeDescriptorValue(descriptor, (err) => { 184 if (err) { 185 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 186 return; 187 } 188 }); 189} catch (err) { 190 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 191} 192``` 193 194**5.3 接收服务端特征值变化通知或指示**<br> 195当服务端特征值的数据内容发生变化时,客户端可以通过接收服务端的特征值变化通知或者指示来实现更新数据。该服务端特征值需包含蓝牙标准协议定义的Client Characteristic Configuration描述符UUID(00002902-0000-1000-8000-00805f9b34fb),才能支持通知或者指示能力。 196 197客户端收到服务端通知时,不需要回复确认;客户端收到服务端指示时,需要回复确认,蓝牙子系统会实现该操作,应用无需关注。 198 199- 先订阅服务端特征值变化事件,详情请见[on('BLECharacteristicChange')](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#onblecharacteristicchange)。 200- 再使能服务端特征值变化通知或者指示能力,应用根据实际场景选择一种方式即可。相关API请参考[setCharacteristicChangeNotification](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#setcharacteristicchangenotification)和[setCharacteristicChangeIndication](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#setcharacteristicchangeindication)。 201```ts 202// 此处是伪代码 203let device = 'XX:XX:XX:XX:XX:XX'; 204 205// 定义服务端特征值变化事件 206function characteristicChange(characteristicChangeReq: ble.BLECharacteristic) { 207 let serviceUuid: string = characteristicChangeReq.serviceUuid; 208 let characteristicUuid: string = characteristicChangeReq.characteristicUuid; 209 let value: Uint8Array = new Uint8Array(characteristicChangeReq.characteristicValue); 210} 211 212let descriptors: Array<ble.BLEDescriptor> = []; 213let arrayBuffer = new ArrayBuffer(2); 214let descV = new Uint8Array(arrayBuffer); 215descV[0] = 11; 216let descriptor: ble.BLEDescriptor = { 217 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 218 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 219 descriptorUuid: '00002902-0000-1000-8000-00805F9B34FB', 220 descriptorValue: arrayBuffer 221}; 222descriptors[0] = descriptor; 223let arrayBufferC = new ArrayBuffer(2); 224let characteristic: ble.BLECharacteristic = { 225 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 226 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 227 characteristicValue: arrayBufferC, 228 descriptors:descriptors 229}; 230 231let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 232 233// 发起订阅 234try { 235 gattClient.on('BLECharacteristicChange', characteristicChange); 236} catch (err) { 237 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 238} 239 240// 通知和指示,2选1即可 241// 设置特征值变化通知能力 242try { 243 // enable入参: true表示启用,false表示禁用 244 gattClient.setCharacteristicChangeNotification(characteristic, true, (err: BusinessError) => { 245 if (err) { 246 console.error('setCharacteristicChangeNotification callback failed'); 247 } else { 248 console.info('setCharacteristicChangeNotification callback successful'); 249 } 250 }); 251} catch (err) { 252 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 253} 254 255// 设置特征值变化指示能力 256try { 257 // enable入参: true表示启用,false表示禁用 258 gattClient.setCharacteristicChangeIndication(characteristic, true, (err: BusinessError) => { 259 if (err) { 260 console.error('setCharacteristicChangeIndication callback failed'); 261 } else { 262 console.info('setCharacteristicChangeIndication callback successful'); 263 } 264 }); 265} catch (err) { 266 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 267} 268``` 269 270**6. 断开连接**<br> 271当应用不再需要已建立的连接时,需主动断开连接。 272```ts 273// 此处是伪代码 274let device = 'XX:XX:XX:XX:XX:XX'; 275 276let gattClient: ble.GattClientDevice = ble.createGattClientDevice(device); 277try { 278 // 发起断连 279 gattClient.disconnect(); 280 281 // 如果应用不再使用此gattClient,则需要close,gattClient实例将不能再使用 282 gattClient.close() 283} catch (err) { 284 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 285} 286``` 287 288### 服务端 289 290**1. 创建服务端实例**<br> 291构造服务端实例,后续所有操作都基于该服务端实例。 292```ts 293try { 294 let gattServer: ble.GattServer = ble.createGattServer(); 295} catch (err) { 296 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 297} 298``` 299 300**2. 添加服务**<br> 301添加应用需要的服务,将在蓝牙子系统中注册指定的UUID服务。客户端会发起服务查询,判断服务端是否支持特定的服务。 302```ts 303// 创建descriptors 304let descriptors: Array<ble.BLEDescriptor> = []; 305let arrayBuffer = new ArrayBuffer(2); 306let descV = new Uint8Array(arrayBuffer); 307descV[0] = 11; 308let descriptor: ble.BLEDescriptor = { 309 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 310 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 311 descriptorUuid: '00002902-0000-1000-8000-00805F9B34FB', 312 descriptorValue: arrayBuffer}; 313descriptors[0] = descriptor; 314 315// 创建characteristics 316let characteristics: Array<ble.BLECharacteristic> = []; 317let arrayBufferC = new ArrayBuffer(2); 318let cccV = new Uint8Array(arrayBufferC); 319cccV[0] = 1; 320let characteristic: ble.BLECharacteristic = { 321 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 322 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 323 characteristicValue: arrayBufferC, 324 descriptors:descriptors 325}; 326characteristics[0] = characteristic; 327 328// 创建gattService 329let gattService: ble.GattService = { 330 serviceUuid:'00001810-0000-1000-8000-00805F9B34FB', 331 isPrimary: true, 332 characteristics:characteristics, 333 includeServices:[] 334}; 335 336try { 337 let gattServer: ble.GattServer = ble.createGattServer(); 338 gattServer.addService(gattService); 339} catch (err) { 340 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 341} 342``` 343 344**3. 订阅连接状态变化事件**<br> 345通过订阅连接状态变化事件,可以获取实时的GATT连接状态以及客户端的设备地址。整个连接过程涉及多种状态的跃迁,其中[STATE_CONNECTED](../../reference/apis-connectivity-kit/js-apis-bluetooth-constant.md#profileconnectionstate)表示已连接,[STATE_DISCONNECTED](../../reference/apis-connectivity-kit/js-apis-bluetooth-constant.md#profileconnectionstate)表示已断连。 346```ts 347function ServerConnectStateChanged(state: ble.BLEConnectionChangeState) { 348 console.info('bluetooth connect state changed'); 349 let connectState: ble.ProfileConnectionState = state.state; 350 let device = state.deviceId; 351} 352 353try { 354 let gattServer: ble.GattServer = ble.createGattServer(); 355 gattServer.on('connectionStateChange', ServerConnectStateChanged); 356} catch (err) { 357 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 358} 359``` 360 361**4. 传输数据**<br> 362传输数据可以通过客户端读写特征值数据内容、读写描述符数据内容、主动发送特征值数据内容变化通知或指示实现。 363 364**4.1 订阅特征值读取或写入事件**<br> 365通过订阅特征值读取或写入事件,获取客户端的操作请求,相关API请参考[on('characteristicRead')](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#oncharacteristicread)和[on('characteristicWrite')](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#oncharacteristicwrite)。 366 367- 收到读取特征值请求时,需要调用[sendResponse](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#sendresponse)进行回复对应特征值的数据内容。 368- 收到写入特征值请求时,可保存客户端写入的特征值数据内容。根据写入请求[CharacteristicWriteRequest](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#characteristicwriterequest)的needRsp判断是否需要调用[sendResponse](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#sendresponse)进行回复。 369```ts 370let gattServer: ble.GattServer = ble.createGattServer(); 371let arrayBufferCCC = new ArrayBuffer(2); 372let cccValue = new Uint8Array(arrayBufferCCC); 373cccValue[0] = 1; 374 375// 定义特征值读取回调函数 376function readCharacteristicReq(characteristicReadRequest: ble.CharacteristicReadRequest) { 377 let deviceId: string = characteristicReadRequest.deviceId; 378 let transId: number = characteristicReadRequest.transId; 379 let offset: number = characteristicReadRequest.offset; 380 let characteristicUuid: string = characteristicReadRequest.characteristicUuid; 381 382 let serverResponse: ble.ServerResponse = { 383 deviceId: deviceId, 384 transId: transId, 385 status: 0, 386 offset: offset, 387 value:arrayBufferCCC // 传入服务端对应特征值的数据内容,此处是伪代码 388 }; 389 390 try { 391 gattServer.sendResponse(serverResponse); 392 } catch (err) { 393 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 394 } 395} 396 397// 定义特征值写入回调函数 398function writeCharacteristicReq(characteristicWriteRequest: ble.CharacteristicWriteRequest) { 399 let deviceId: string = characteristicWriteRequest.deviceId; 400 let transId: number = characteristicWriteRequest.transId; 401 let offset: number = characteristicWriteRequest.offset; 402 let needRsp: boolean = characteristicWriteRequest.needRsp; 403 if (!needRsp) { // 判断是否需要回复客户端 404 return; 405 } 406 let value: Uint8Array = new Uint8Array(characteristicWriteRequest.value); // 可保存写入的数据内容 407 let characteristicUuid: string = characteristicWriteRequest.characteristicUuid; 408 cccValue[0] = value[0]; 409 let serverResponse: ble.ServerResponse = { 410 deviceId: deviceId, 411 transId: transId, 412 status: 0, 413 offset: offset, 414 value:arrayBufferCCC 415 }; 416 417 try { 418 gattServer.sendResponse(serverResponse); 419 } catch (err) { 420 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 421 } 422} 423 424// 订阅特征值读取事件 425gattServer.on('characteristicRead', readCharacteristicReq); 426 427// 订阅特征值写入事件 428gattServer.on('characteristicWrite', writeCharacteristicReq); 429``` 430 431**4.2 订阅描述符读取或写入事件**<br> 432通过订阅描述符读取或写入事件,获取客户端的操作请求,相关API请参考[on('descriptorRead')](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#ondescriptorread)和[on('descriptorWrite')](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#ondescriptorwrite)。 433 434- 收到读取描述符请求时,需要调用[sendResponse](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#sendresponse)进行回复对应描述符的数据内容。 435- 收到写入描述符请求时,可保存客户端写入的描述符数据内容。根据写入请求[DescriptorWriteRequest](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#descriptorwriterequest)的needRsp判断是否需要调用[sendResponse](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#sendresponse)进行回复。 436```ts 437let gattServer: ble.GattServer = ble.createGattServer(); 438 439// 定义描述符读取回调函数 440let arrayBufferDesc = new ArrayBuffer(2); 441let descValue = new Uint8Array(arrayBufferDesc); 442descValue[0] = 1; 443function readDescriptorReq(descriptorReadRequest: ble.DescriptorReadRequest) { 444 let deviceId: string = descriptorReadRequest.deviceId; 445 let transId: number = descriptorReadRequest.transId; 446 let offset: number = descriptorReadRequest.offset; 447 let descriptorUuid: string = descriptorReadRequest.descriptorUuid; 448 449 let serverResponse: ble.ServerResponse = { 450 deviceId: deviceId, 451 transId: transId, 452 status: 0, 453 offset: offset, 454 value:arrayBufferDesc 455 }; 456 457 try { 458 gattServer.sendResponse(serverResponse); 459 } catch (err) { 460 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 461 } 462} 463 464// 定义描述符写入回调函数 465function writeDescriptorReq(descriptorWriteRequest: ble.DescriptorWriteRequest) { 466 let deviceId: string = descriptorWriteRequest.deviceId; 467 let transId: number = descriptorWriteRequest.transId; 468 let offset: number = descriptorWriteRequest.offset; 469 let isPrepared: boolean = descriptorWriteRequest.isPrepared; 470 let needRsp: boolean = descriptorWriteRequest.needRsp; 471 if (!needRsp) { // 判断是否需要回复客户端 472 return; 473 } 474 475 let value: Uint8Array = new Uint8Array(descriptorWriteRequest.value); // 可保存写入的数据内容 476 let descriptorUuid: string = descriptorWriteRequest.descriptorUuid; 477 descValue[0] = value[0]; 478 let serverResponse: ble.ServerResponse = { 479 deviceId: deviceId, 480 transId: transId, 481 status: 0, 482 offset: offset, 483 value:arrayBufferDesc 484 }; 485 486 try { 487 gattServer.sendResponse(serverResponse); 488 } catch (err) { 489 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 490 } 491} 492 493// 订阅描述符读取事件 494gattServer.on('descriptorRead', readDescriptorReq); 495 496// 订阅描述符写入事件 497gattServer.on('descriptorWrite', writeDescriptorReq); 498``` 499 500**4.3 发送特征值变化通知或指示**<br> 501当服务端的特征值数据内容发生变化时,可以通过通知或者指示主动知会到客户端,相关API请参考[notifyCharacteristicChanged](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#notifycharacteristicchanged)。 502 503发送通知时,不需要客户端回复确认;发送指示时,需要客户端回复确认。应用根据[NotifyCharacteristic](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#notifycharacteristic)的confirm参数决定发送哪种类型。 504 505- 该特征值需包含蓝牙标准协议定义的Client Characteristic Configuration描述符UUID(00002902-0000-1000-8000-00805f9b34fb),才支持通知或者指示能力。 506- 使用通知或者指示能力需要使能。客户端可以通过[setCharacteristicChangeNotification](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#setcharacteristicchangenotification)或[setCharacteristicChangeIndication](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md#setcharacteristicchangeindication)使能该能力,应用根据实际场景选择一种方式即可。 507```ts 508let device = 'XX:XX:XX:XX:XX:XX'; // 该设备地址表示客户端地址,可以通过连接状态变化事件中获取 509let arrayBufferC = new ArrayBuffer(2); 510let notifyCharacter: ble.NotifyCharacteristic = { 511 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 512 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 513 characteristicValue: arrayBufferC, 514 confirm: true // 决定发送通知还是指示 515}; 516try { 517 let gattServer: ble.GattServer = ble.createGattServer(); 518 // 发送变更通知或指示 519 gattServer.notifyCharacteristicChanged(device, notifyCharacter, (err: BusinessError) => { 520 if (err) { 521 console.error('notifyCharacteristicChanged callback failed'); 522 } else { 523 console.info('notifyCharacteristicChanged callback successful'); 524 } 525 }); 526} catch (err) { 527 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 528} 529``` 530 531**5. 关闭服务端实例**<br> 532当应用不再需要创建的服务端实例时,需要主动关闭,并释放相关资源。例如:删除已添加的服务,取消已订阅事件。 533```ts 534try { 535 let gattServer: ble.GattServer = ble.createGattServer(); 536 gattServer.removeService('00001810-0000-1000-8000-00805F9B34FB'); // 删除此前注册的服务 537 gattServer.close() // 应用不再使用此gattServer,则需要close 538} catch (err) { 539 console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 540} 541``` 542 543## 完整示例 544 545### 客户端 546```ts 547import { ble, constant } from '@kit.ConnectivityKit'; 548import { BusinessError } from '@kit.BasicServicesKit'; 549 550const TAG: string = 'GattClientManager'; 551 552export class GattClientManager { 553 device: string = ''; 554 gattClient: ble.GattClientDevice | undefined = undefined; 555 connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED; 556 myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB'; 557 myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB'; 558 // 标准协议描述符Client Characteristic Configuration,用于特征值变化通知或指示 559 myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; 560 // 自定义描述符 561 mySecondDescriptorUuid: string = '00008888-0000-1000-8000-00805F9B34FB'; 562 563 myService: ble.GattService | undefined = undefined; 564 myCharacteristic: ble.BLECharacteristic | undefined = undefined; 565 myFirstDescriptor: ble.BLEDescriptor | undefined = undefined; 566 mySecondDescriptor: ble.BLEDescriptor | undefined = undefined; 567 568 foundService: boolean = false; 569 foundChar: boolean = false; 570 foundFirstDes: boolean = false; 571 foundSecondDes: boolean = false; 572 573 // 构造BLEDescriptor 574 private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor { 575 let descriptor: ble.BLEDescriptor = { 576 serviceUuid: this.myServiceUuid, 577 characteristicUuid: this.myCharacteristicUuid, 578 descriptorUuid: des, 579 descriptorValue: value 580 }; 581 return descriptor; 582 } 583 584 // 构造BLECharacteristic 585 private initCharacteristic(isWrite: boolean): ble.BLECharacteristic { 586 let descriptors: Array<ble.BLEDescriptor> = []; 587 let charBuffer = new ArrayBuffer(2); 588 if (isWrite) { 589 let charValue = new Uint8Array(charBuffer); 590 charValue[0] = 21; 591 charValue[1] = 22; 592 } 593 let characteristic: ble.BLECharacteristic = { 594 serviceUuid: this.myServiceUuid, 595 characteristicUuid: this.myCharacteristicUuid, 596 characteristicValue: charBuffer, 597 descriptors: descriptors 598 }; 599 return characteristic; 600 } 601 602 private logCharacteristic(char: ble.BLECharacteristic) { 603 let message = 'logCharacteristic uuid:' + char.characteristicUuid + ', value: '; 604 let value = new Uint8Array(char.characteristicValue); 605 message += 'logCharacteristic value: '; 606 for (let i = 0; i < char.characteristicValue.byteLength; i++) { 607 message += value[i] + ' '; 608 } 609 console.info(TAG, message); 610 } 611 612 private logDescriptor(des: ble.BLEDescriptor) { 613 let message = 'logDescriptor uuid:' + des.descriptorUuid + ', value: '; 614 let value = new Uint8Array(des.descriptorValue); 615 message += 'logDescriptor value: '; 616 for (let i = 0; i < des.descriptorValue.byteLength; i++) { 617 message += value[i] + ' '; 618 } 619 console.info(TAG, message); 620 } 621 622 private checkService(services: Array<ble.GattService>) { 623 for (let i = 0; i < services.length; i++) { 624 if (services[i].serviceUuid != this.myServiceUuid) { 625 continue; 626 } 627 this.myService = services[i]; 628 this.foundService = true; 629 for (let j = 0; j < services[i].characteristics.length; j++) { 630 if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) { 631 continue; 632 } 633 this.logCharacteristic(services[i].characteristics[j]); 634 this.myCharacteristic = services[i].characteristics[j]; 635 this.foundChar = true; 636 for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) { 637 if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) { 638 this.myFirstDescriptor= services[i].characteristics[j].descriptors[k]; 639 this.foundFirstDes = true; 640 continue; 641 } 642 if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.mySecondDescriptorUuid) { 643 this.mySecondDescriptor = services[i].characteristics[j].descriptors[k]; 644 this.foundSecondDes = true; 645 continue; 646 } 647 } 648 } 649 } 650 console.info(TAG, 'foundService: ' + this.foundService + ', foundChar: ' + this.foundChar + 651 ', foundFirDes: ' + this.foundFirstDes + ', foundSecDes: ' + this.foundSecondDes); 652 } 653 654 // 1. 定义连接状态变化回调函数 655 onGattClientStateChange = (stateInfo: ble.BLEConnectionChangeState) => { 656 let state = ''; 657 switch (stateInfo.state) { 658 case 0: 659 state = 'DISCONNECTED'; 660 break; 661 case 1: 662 state = 'CONNECTING'; 663 break; 664 case 2: 665 state = 'CONNECTED'; 666 break; 667 case 3: 668 state = 'DISCONNECTING'; 669 break; 670 default: 671 state = 'undefined'; 672 break; 673 } 674 console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state); 675 if (stateInfo.deviceId == this.device) { 676 this.connectState = stateInfo.state; 677 } 678 }; 679 680 // 2. client端主动连接时调用 681 public startConnect(peerDevice: string) { // 对端设备一般通过ble查找设备获取到 682 if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) { 683 console.error(TAG, 'startConnect failed'); 684 return; 685 } 686 console.info(TAG, 'startConnect ' + peerDevice); 687 this.device = peerDevice; 688 // 2.1 使用device构造gattClient,后续的交互都需要使用该实例 689 this.gattClient = ble.createGattClientDevice(peerDevice); 690 try { 691 // 2.2 订阅连接状态 692 this.gattClient.on('BLEConnectionStateChange', this.onGattClientStateChange); 693 694 // 2.3 发起连接 695 this.gattClient.connect(); 696 } catch (err) { 697 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 698 } 699 } 700 701 // 3. client端连接成功后,需要进行服务发现 702 public async discoverServices() { 703 if (!this.gattClient) { 704 console.error(TAG, 'gattClient does not exist'); 705 return; 706 } 707 console.info(TAG, 'discoverServices'); 708 try { 709 let serverService = await this.gattClient.getServices(); 710 this.checkService(serverService); // 要确保server端的服务内容有业务所需要的服务 711 if (typeof this.myService !== 'undefined') { 712 console.info(TAG, 'Service: ' + JSON.stringify(this.myService)); 713 } 714 if (typeof this.myCharacteristic !== 'undefined') { 715 this.logCharacteristic(this.myCharacteristic); 716 } 717 if (typeof this.myFirstDescriptor !== 'undefined') { 718 this.logDescriptor(this.myFirstDescriptor); 719 } 720 if (typeof this.mySecondDescriptor !== 'undefined') { 721 this.logDescriptor(this.mySecondDescriptor); 722 } 723 } catch (err) { 724 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 725 } 726 } 727 728 // 4. 在确保拿到了server端的服务结果后,读取server端特定服务的特征值时调用 729 public readCharacteristicValue() { 730 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 731 console.error(TAG, 'gattClient does not exist or state not connected'); 732 return; 733 } 734 if (!this.foundChar) { // 要确保server端有对应的characteristic 735 console.error(TAG, 'server characteristic does not exist'); 736 return; 737 } 738 739 let characteristic = this.initCharacteristic(false); 740 console.info(TAG, 'readCharacteristicValue'); 741 try { 742 this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => { 743 this.myCharacteristic = outData; 744 this.logCharacteristic(this.myCharacteristic); 745 }); 746 } catch (err) { 747 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 748 } 749 } 750 751 // 5. 在确保拿到了server端的服务结果后,写入server端特定服务的特征值时调用 752 public writeCharacteristicValue() { 753 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 754 console.error(TAG, 'gattClient does not exist or state not connected'); 755 return; 756 } 757 if (!this.foundChar) { // 要确保server端有对应的characteristic 758 console.error(TAG, 'server characteristic does not exist'); 759 return; 760 } 761 762 let characteristic = this.initCharacteristic(true); 763 console.info(TAG, 'writeCharacteristicValue'); 764 try { 765 this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => { 766 if (err) { 767 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 768 return; 769 } 770 console.info(TAG, 'writeCharacteristicValue success'); 771 }); 772 } catch (err) { 773 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 774 } 775 } 776 777 // 6. 在确保拿到了server端的服务结果后,读取server端特定服务的描述符时调用 778 public readDescriptorValue() { 779 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 780 console.error(TAG, 'gattClient does not exist or state not connected'); 781 return; 782 } 783 if (!this.foundSecondDes) { // 要确保server端有对应的descriptor 784 console.error(TAG, 'server descriptor does not exist'); 785 return; 786 } 787 788 let descBuffer = new ArrayBuffer(0); 789 let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer); 790 console.info(TAG, 'readDescriptorValue'); 791 try { 792 this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => { 793 this.logDescriptor(outData); 794 }); 795 } catch (err) { 796 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 797 } 798 } 799 800 // 7. 在确保拿到了server端的服务结果后,写入server端特定服务的描述符时调用 801 public writeDescriptorValue() { 802 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 803 console.error(TAG, 'gattClient does not exist or state not connected'); 804 return; 805 } 806 if (!this.foundSecondDes) { // 要确保server端有对应的descriptor 807 console.error(TAG, 'server descriptor does not exist'); 808 return; 809 } 810 811 let descBuffer = new ArrayBuffer(2); 812 let descValue = new Uint8Array(descBuffer); 813 descValue[0] = 41; 814 descValue[1] = 42; 815 let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer); 816 console.info(TAG, 'writeDescriptorValue'); 817 try { 818 this.gattClient.writeDescriptorValue(descriptor, (err) => { 819 if (err) { 820 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 821 return; 822 } 823 console.info(TAG, 'writeDescriptorValue success'); 824 }); 825 } catch (err) { 826 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 827 } 828 } 829 830 // 8. 定义特征值变化回调函数 831 onCharacteristicChange = (char: ble.BLECharacteristic) => { 832 console.info(TAG, 'onCharacteristicChange: uuid: ' + char.characteristicUuid + ', value: ' + JSON.stringify(new Uint8Array(char.characteristicValue))); 833 this.myCharacteristic = char; 834 this.logCharacteristic(this.myCharacteristic); 835 } 836 837 // 9. 使能或禁用接收服务端端特征值内容变更通知的能力时调用,一般通知或者指示,二选一 838 public Notify(enable: boolean) { 839 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 840 console.error(TAG, 'gattClient does not exist or state not connected'); 841 return; 842 } 843 844 if (!this.foundFirstDes) { // 要确保server端有对应的client configuration descriptor 845 console.error(TAG, 'server client configuration descriptor does not exist'); 846 return; 847 } 848 849 console.info(TAG, 'Notify ' + this.device + ' enable: ' + enable); 850 try { 851 // 订阅特征值变化 852 this.gattClient.on('BLECharacteristicChange', this.onCharacteristicChange); 853 // 设置特征值变化通知能力,enable: true表示启用,false表示禁用 854 this.gattClient.setCharacteristicChangeNotification(this.myCharacteristic, enable, (err: BusinessError) => { 855 if (err) { 856 console.error('setCharacteristicChangeNotification callback failed'); 857 } else { 858 console.info('setCharacteristicChangeNotification callback successful'); 859 } 860 }); 861 } catch (err) { 862 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 863 } 864 } 865 866 // 10. 使能或禁用接收服务端端特征值内容变更指示的能力时调用,一般通知或者指示,二选一 867 public Indicate(enable: boolean) { 868 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 869 console.error(TAG, 'gattClient does not exist or state not connected'); 870 return; 871 } 872 873 if (!this.foundFirstDes) { // 要确保server端有对应的client configuration descriptor 874 console.error(TAG, 'server client configuration descriptor does not exist'); 875 return; 876 } 877 878 console.info(TAG, 'Indicate ' + this.device + ' enable: ' + enable); 879 try { 880 // 订阅特征值变化 881 this.gattClient.on('BLECharacteristicChange', this.onCharacteristicChange); 882 // 设置特征值变化指示能力,enable: true表示启用,false表示禁用 883 this.gattClient.setCharacteristicChangeIndication(this.myCharacteristic, enable, (err: BusinessError) => { 884 if (err) { 885 console.error('setCharacteristicChangeIndication callback failed'); 886 } else { 887 console.info('setCharacteristicChangeIndication callback successful'); 888 } 889 }); 890 } catch (err) { 891 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 892 } 893 } 894 895 // 11.client端主动断开时调用 896 public stopConnect() { 897 if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) { 898 console.error(TAG, 'gattClient does not exist or state not connected'); 899 return; 900 } 901 902 console.info(TAG, 'stopConnect ' + this.device); 903 try { 904 this.gattClient.disconnect(); // 11.1 断开连接 905 this.gattClient.off('BLEConnectionStateChange', this.onGattClientStateChange); // 11.2 取消订阅连接状态 906 this.gattClient.off('BLECharacteristicChange', this.onCharacteristicChange); // 11.3 取消订阅特征值变化 907 this.gattClient.close() // 11.4 如果应用不再使用此gattClient,则需要close 908 } catch (err) { 909 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 910 } 911 } 912} 913 914let gattClientManager = new GattClientManager(); 915export default gattClientManager as GattClientManager; 916``` 917 918### 服务端 919```ts 920import { ble, constant } from '@kit.ConnectivityKit'; 921import { BusinessError } from '@kit.BasicServicesKit'; 922 923const TAG: string = 'GattServerManager'; 924 925export class GattServerManager { 926 device = ''; 927 gattServer: ble.GattServer | undefined = undefined; 928 connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED; 929 myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB'; 930 myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB'; 931 // 标准协议描述符Client Characteristic Configuration,用于特征值变化通知或指示 932 myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; 933 // 自定义描述符 934 mySecondDescriptorUuid: string = '00008888-0000-1000-8000-00805F9B34FB'; 935 936 charBuffer = new ArrayBuffer(2); 937 charValue = new Uint8Array(this.charBuffer); 938 939 firDescBuffer = new ArrayBuffer(2); 940 firDescValue = new Uint8Array(this.firDescBuffer); 941 942 secDescBuffer = new ArrayBuffer(2); 943 secDescValue = new Uint8Array(this.secDescBuffer); 944 945 // 构造BLEDescriptor 946 private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor { 947 let descriptor: ble.BLEDescriptor = { 948 serviceUuid: this.myServiceUuid, 949 characteristicUuid: this.myCharacteristicUuid, 950 descriptorUuid: des, 951 descriptorValue: value 952 }; 953 return descriptor; 954 } 955 956 // 构造BLECharacteristic 957 private initCharacteristic(): ble.BLECharacteristic { 958 let descriptors: Array<ble.BLEDescriptor> = []; 959 // 默认Client Characteristic Configuration描述符没有使能特征值变化通知或者指示能力 960 descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, this.firDescBuffer); 961 this.secDescValue[0] = 31; 962 this.secDescValue[1] = 32; 963 descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, this.secDescBuffer); 964 this.charValue[0] = 1; 965 this.charValue[1] = 2; 966 let characteristic: ble.BLECharacteristic = { 967 serviceUuid: this.myServiceUuid, 968 characteristicUuid: this.myCharacteristicUuid, 969 characteristicValue: this.charBuffer, 970 descriptors: descriptors 971 }; 972 return characteristic; 973 } 974 975 // 1. 定义连接状态变化回调函数 976 onGattServerStateChange = (stateInfo: ble.BLEConnectionChangeState) => { 977 let state = ''; 978 switch (stateInfo.state) { 979 case 0: 980 state = 'DISCONNECTED'; 981 break; 982 case 1: 983 state = 'CONNECTING'; 984 break; 985 case 2: 986 state = 'CONNECTED'; 987 break; 988 case 3: 989 state = 'DISCONNECTING'; 990 break; 991 default: 992 state = 'undefined'; 993 break; 994 } 995 console.info(TAG, 'onGattServerStateChange: device=' + stateInfo.deviceId + ', state=' + state); 996 this.device = stateInfo.deviceId; 997 } 998 999 // 2. 定义读取特征值请求回调函数 1000 onCharacteristicRead = (charReq: ble.CharacteristicReadRequest) => { 1001 let deviceId: string = charReq.deviceId; 1002 let transId: number = charReq.transId; 1003 let offset: number = charReq.offset; 1004 console.info(TAG, 'receive characteristicRead: uuid: ' + charReq.characteristicUuid + ', value: ' + JSON.stringify(this.charValue)); 1005 let serverResponse: ble.ServerResponse = { 1006 deviceId: deviceId, 1007 transId: transId, 1008 status: 0, // 0表示成功 1009 offset: offset, 1010 value: this.charBuffer 1011 }; 1012 1013 try { 1014 this.gattServer?.sendResponse(serverResponse); 1015 } catch (err) { 1016 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1017 } 1018 }; 1019 1020 // 检查client configuration descriptor的通知能力是否使能 1021 private checkDescriptorNotification(buffer: Uint8Array): boolean { 1022 const notify = new ArrayBuffer(2); 1023 let notifyValue = new Uint8Array(notify); 1024 notifyValue.set([1, 0]); // 使能client configuration descriptor notification的值 1025 return notifyValue.every((value, index) => value === buffer[index]); 1026 } 1027 1028 // 检查client configuration descriptor的指示能力是否使能 1029 private checkDescriptorIndication(buffer: Uint8Array): boolean { 1030 const notify = new ArrayBuffer(2); 1031 let notifyValue = new Uint8Array(notify); 1032 notifyValue.set([2, 0]); // 使能client configuration descriptor indication的值 1033 return notifyValue.every((value, index) => value === buffer[index]); 1034 } 1035 1036 // 3. 定义写入特征值请求回调函数 1037 onCharacteristicWrite = (charReq: ble.CharacteristicWriteRequest) => { 1038 let deviceId: string = charReq.deviceId; 1039 let transId: number = charReq.transId; 1040 let offset: number = charReq.offset; 1041 this.charBuffer = charReq.value; 1042 this.charValue = new Uint8Array(charReq.value); 1043 console.info(TAG, 'receive characteristicWrite: uuid: ' + charReq.characteristicUuid + ', needRsp=' + charReq.needRsp + ', value: ' + JSON.stringify(this.charValue)); 1044 if (!charReq.needRsp) { 1045 return; 1046 } 1047 let rspBuffer = new ArrayBuffer(0); 1048 let serverResponse: ble.ServerResponse = { 1049 deviceId: deviceId, 1050 transId: transId, 1051 status: 0, // 0表示成功 1052 offset: offset, 1053 value: rspBuffer 1054 }; 1055 1056 try { 1057 this.gattServer?.sendResponse(serverResponse); 1058 this.sendCharacterChange(); // 此处特征值变化了,模拟主动发送变化通知或者指示 1059 } catch (err) { 1060 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1061 } 1062 } 1063 1064 // 4. 定义读取描述符请求回调函数 1065 onDescriptorRead = (desReq: ble.DescriptorReadRequest) => { 1066 let deviceId: string = desReq.deviceId; 1067 let transId: number = desReq.transId; 1068 let offset: number = desReq.offset; 1069 let tmpBuffer = new ArrayBuffer(2); 1070 if (desReq.descriptorUuid == this.myFirstDescriptorUuid) { 1071 tmpBuffer = this.firDescBuffer; 1072 } else { 1073 tmpBuffer = this.secDescBuffer; 1074 } 1075 let tmpValue = new Uint8Array(tmpBuffer); 1076 console.info(TAG, 'receive descriptorRead: ' + desReq.descriptorUuid + ', tmpValue: ' + JSON.stringify(tmpValue)); 1077 let serverResponse: ble.ServerResponse = { 1078 deviceId: deviceId, 1079 transId: transId, 1080 status: 0, // 0表示成功 1081 offset: offset, 1082 value: tmpBuffer 1083 }; 1084 1085 try { 1086 this.gattServer?.sendResponse(serverResponse); 1087 } catch (err) { 1088 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1089 } 1090 } 1091 1092 // 5. 定义写入描述符请求回调函数 1093 onDescriptorWrite = (desReq: ble.DescriptorWriteRequest) => { 1094 let deviceId: string = desReq.deviceId; 1095 let transId: number = desReq.transId; 1096 let offset: number = desReq.offset; 1097 console.info(TAG, 'receive descriptorWrite: uuid: ' + desReq.descriptorUuid + ', needRsp: '+ desReq.needRsp + ', value: ' + JSON.stringify(new Uint8Array(desReq.value))); 1098 if (desReq.descriptorUuid == this.myFirstDescriptorUuid) { 1099 this.firDescBuffer = desReq.value; 1100 this.firDescValue = new Uint8Array(desReq.value); 1101 } else { 1102 this.secDescBuffer = desReq.value; 1103 this.secDescValue = new Uint8Array(desReq.value); 1104 } 1105 if (!desReq.needRsp) { 1106 return; 1107 } 1108 let rspBuffer = new ArrayBuffer(0); 1109 let serverResponse: ble.ServerResponse = { 1110 deviceId: deviceId, 1111 transId: transId, 1112 status: 0, // 0表示成功 1113 offset: offset, 1114 value: rspBuffer 1115 }; 1116 1117 try { 1118 this.gattServer?.sendResponse(serverResponse); 1119 } catch (err) { 1120 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1121 } 1122 } 1123 1124 // 6. server端注册服务时调用 1125 public registerServer() { 1126 let characteristics: Array<ble.BLECharacteristic> = []; 1127 let characteristic = this.initCharacteristic(); 1128 characteristics.push(characteristic); 1129 let gattService: ble.GattService = { 1130 serviceUuid: this.myServiceUuid, 1131 isPrimary: true, 1132 characteristics: characteristics 1133 }; 1134 1135 console.info(TAG, 'registerServer ' + this.myServiceUuid); 1136 try { 1137 this.gattServer = ble.createGattServer(); // 6.1 构造gattServer,后续的交互都需要使用该实例 1138 this.gattServer.addService(gattService); // 6.2 注册服务 1139 this.gattServer.on('connectionStateChange', this.onGattServerStateChange); // 6.3 订阅连接状态 1140 this.gattServer.on('characteristicRead', this.onCharacteristicRead); // 6.4 订阅特征值读事件 1141 this.gattServer.on('characteristicWrite', this.onCharacteristicWrite); // 6.5 订阅特征值读事件 1142 this.gattServer.on('descriptorRead', this.onDescriptorRead); // 6.6 订阅特征值读事件 1143 this.gattServer.on('descriptorWrite', this.onDescriptorWrite); // 6.7 订阅特征值读事件 1144 } catch (err) { 1145 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1146 } 1147 } 1148 1149 // 7. 特征值内容发生变化时调用 1150 public sendCharacterChange() { 1151 console.info(TAG, 'sendCharacterChange: uuid: ' + this.myCharacteristicUuid + ', value: ' + JSON.stringify(new Uint8Array(this.charBuffer))); 1152 if (this.checkDescriptorNotification(this.firDescValue)) { 1153 let notifyCharacter: ble.NotifyCharacteristic = { 1154 serviceUuid: this.myServiceUuid, 1155 characteristicUuid: this.myCharacteristicUuid, 1156 characteristicValue: this.charBuffer, 1157 confirm: false 1158 }; 1159 console.info(TAG, 'sendCharacterChange notification'); 1160 this.gattServer?.notifyCharacteristicChanged(this.device, notifyCharacter, (err: BusinessError) => { 1161 if (err) { 1162 console.error(TAG, 'notifyCharacteristicChanged notification callback failed'); 1163 } else { 1164 console.info(TAG, 'notifyCharacteristicChanged notification callback successful'); 1165 } 1166 }); 1167 } else if (this.checkDescriptorIndication(this.firDescValue)) { 1168 let notifyCharacter: ble.NotifyCharacteristic = { 1169 serviceUuid: '00001810-0000-1000-8000-00805F9B34FB', 1170 characteristicUuid: '00001820-0000-1000-8000-00805F9B34FB', 1171 characteristicValue: this.charBuffer, 1172 confirm: true 1173 }; 1174 console.info(TAG, 'sendCharacterChange indication'); 1175 this.gattServer?.notifyCharacteristicChanged(this.device, notifyCharacter, (err: BusinessError) => { 1176 if (err) { 1177 console.error(TAG, 'notifyCharacteristicChanged indication callback failed'); 1178 } else { 1179 console.info(TAG, 'notifyCharacteristicChanged indication callback successful'); 1180 } 1181 }); 1182 } else { 1183 console.info(TAG, 'notification/indication is disabled'); 1184 } 1185 } 1186 1187 // 8. server端删除服务,不再使用时调用 1188 public unRegisterServer() { 1189 if (!this.gattServer) { 1190 console.error(TAG, 'no gattServer'); 1191 return; 1192 } 1193 1194 console.info(TAG, 'unRegisterServer ' + this.myServiceUuid); 1195 try { 1196 this.gattServer.removeService(this.myServiceUuid); // 8.1 删除服务 1197 this.gattServer.off('connectionStateChange', this.onGattServerStateChange) // 8.2 取消订阅连接状态 1198 this.gattServer.on('characteristicRead', this.onCharacteristicRead); // 8.3 订阅特征值读事件 1199 this.gattServer.on('characteristicWrite', this.onCharacteristicWrite); // 8.4 订阅特征值读事件 1200 this.gattServer.on('descriptorRead', this.onDescriptorRead); // 8.5 订阅特征值读事件 1201 this.gattServer.on('descriptorWrite', this.onDescriptorWrite); // 8.6 订阅特征值读事件 1202 this.gattServer.close() // 8.7 如果应用不再使用此gattServer,则需要close 1203 } catch (err) { 1204 console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message); 1205 } 1206 } 1207} 1208 1209let gattServerManager = new GattServerManager(); 1210export default gattServerManager as GattServerManager; 1211```