1# 通用属性协议开发指导 2 3## 简介 4通用属性协议是GATT(Generic Attribute)的缩写,它是一种用于在蓝牙低功耗设备之间传输数据的协议,定义了一套通用的属性和服务框架。通过GATT协议,蓝牙设备可以向其他设备提供服务,也可以从其他设备获取服务。 5 6## 场景介绍 7 8主要场景有: 9- 连接server端读取和写入信息。 10- server端操作services和通知客户端信息。 11 12## 接口说明 13 14完整的 JS API 说明以及实例代码请参考:[GATT 接口](../../reference/apis-connectivity-kit/js-apis-bluetooth-ble.md)。 15 16具体接口说明如下表。 17 18| 接口名 | 功能描述 | 19| ------------------------------------------ | ------------------------------------------------------------------------------------------------------ | 20| connect() | client端发起连接远端蓝牙低功耗设备。 | 21| disconnect() | client端断开与远端蓝牙低功耗设备的连接。 | 22| close() | 关闭客户端功能,注销client在协议栈的注册,调用该接口后GattClientDevice实例将不能再使用。| 23| getDeviceName() | client获取远端蓝牙低功耗设备名。 | 24| getServices() | client端获取蓝牙低功耗设备的所有服务,即服务发现 。 | 25| readCharacteristicValue() | client端读取蓝牙低功耗设备特定服务的特征值。 | 26| readDescriptorValue() | client端读取蓝牙低功耗设备特定的特征包含的描述符。 | 27| writeCharacteristicValue() | client端向低功耗蓝牙设备写入特定的特征值。 | 28| writeDescriptorValue() | client端向低功耗蓝牙设备特定的描述符写入二进制数据。 | 29| getRssiValue() | client获取远端蓝牙低功耗设备的信号强度 (Received Signal Strength Indication, RSSI),调用connect接口连接成功后才能使用。| 30| setBLEMtuSize() | client协商远端蓝牙低功耗设备的最大传输单元(Maximum Transmission Unit, MTU),调用connect接口连接成功后才能使用。| 31| setCharacteristicChangeNotification() | 向服务端发送设置通知此特征值请求。 | 32| setCharacteristicChangeIndication() | 向服务端发送设置通知此特征值请求。 | 33| on(type: 'BLECharacteristicChange') | 订阅蓝牙低功耗设备的特征值变化事件。需要先调用setNotifyCharacteristicChanged接口才能接收server端的通知。 | 34| off(type: 'BLECharacteristicChange') | 取消订阅蓝牙低功耗设备的特征值变化事件。 | 35| on(type: 'BLEConnectionStateChange') | client端订阅蓝牙低功耗设备的连接状态变化事件。 | 36| off(type: 'BLEConnectionStateChange') | 取消订阅蓝牙低功耗设备的连接状态变化事件。 | 37| on(type: 'BLEMtuChange') | client端订阅MTU状态变化事件。 | 38| off(type: 'BLEMtuChange') | client端取消订阅MTU状态变化事件。 | 39| addService() | server端添加服务。 | 40| removeService() | 删除已添加的服务。 | 41| close() | 关闭服务端功能,去注销server在协议栈的注册,调用该接口后GattServer实例将不能再使用。 | 42| notifyCharacteristicChanged() | server端特征值发生变化时,主动通知已连接的client设备。 | 43| sendResponse() | server端回复client端的读写请求。 | 44| on(type: 'characteristicRead') | server端订阅特征值读请求事件。 | 45| off(type: 'characteristicRead') | server端取消订阅特征值读请求事件。 | 46| on(type: 'characteristicWrite') | server端订阅特征值写请求事件。 | 47| off(type: 'characteristicWrite') | server端取消订阅特征值写请求事件。 | 48| on(type: 'descriptorRead') | server端订阅描述符读请求事件。 | 49| off(type: 'descriptorRead') | server端取消订阅描述符读请求事件。 | 50| on(type: 'descriptorWrite') | server端订阅描述符写请求事件。 | 51| off(type: 'descriptorWrite') | server端取消订阅描述符写请求事件。 | 52| on(type: 'connectionStateChange') | server端订阅BLE连接状态变化事件。 | 53| off(type: 'connectionStateChange') | server端取消订阅BLE连接状态变化事件。 | 54| on(type: 'BLEMtuChange') | server端订阅MTU状态变化事件。 | 55| off(type: 'BLEMtuChange') | server端取消订阅MTU状态变化事件。 | 56 57## 主要场景开发步骤 58 59### 连接server端读取和写入信息 601. import需要的ble模块。 612. 创建gattClient实例对象。 623. 连接gattServer。 634. 获取gattServer的设备名称、services信息、信号强度。 645. 读取gattServer的特征值和描述符。 656. 向gattServer写入特征值和描述符。 667. 断开连接,销毁gattClient实例。 678. 示例代码: 68 69```ts 70import ble from '@ohos.bluetooth.ble'; 71import { BusinessError } from '@ohos.base'; 72 73// serverDeviceId的值,是开启ble扫描获取gattServer的deviceId的值。 74let serverDeviceId = 'xx:xx:xx:xx:xx:xx'; 75 76// 创建客户端 77let clientDevice = ble.createGattClientDevice(serverDeviceId); 78 79// 连接GattServer服务 80clientDevice.connect(); 81 82// 订阅连接状态改变事件 83clientDevice.on('BLEConnectionStateChange', (bleConnectionState) => { 84 let bleConnectionStateInfo = ''; 85 switch (bleConnectionState.state) { 86 case 0: 87 bleConnectionStateInfo = 'DISCONNECTED'; 88 break; 89 case 1: 90 bleConnectionStateInfo = 'CONNECTING'; 91 break; 92 case 2: 93 bleConnectionStateInfo = 'STATE_CONNECTED'; 94 break; 95 case 3: 96 bleConnectionStateInfo = 'STATE_DISCONNECTING'; 97 break; 98 default: 99 bleConnectionStateInfo = 'undefined'; 100 break; 101 } 102 console.info('status: ' + bleConnectionStateInfo); 103}) 104 105// 获取gattServer设备名称 106clientDevice.getDeviceName((err: BusinessError, data: string) => { 107 console.info('getDeviceName success, deviceName = ' + JSON.stringify(data)); 108}) 109 110// 获取server的services信息 111clientDevice.getServices((code, gattServices) => { 112 let message = ''; 113 if (code != null) { 114 console.error('getServices error, errCode: ' + (code as BusinessError).code + ', errMessage: ' + (code as BusinessError).message); 115 } else { 116 for (let i = 0; i < gattServices.length; i++) { 117 message += 'serviceUuid is ' + gattServices[i].serviceUuid + '\n'; 118 } 119 console.info('getServices success, ' + message); 120 } 121}) 122 123// 读取信号强度 124clientDevice.getRssiValue((err, cbRssi) => { 125 console.info('return code = ' + JSON.stringify(err) + ', RSSI = ' + JSON.stringify(cbRssi)) 126}); 127 128// 设置最大传输单元,示例为256 129clientDevice.setBLEMtuSize(256); 130 131// 读取特征值 132// 下面字段的值,是getServices之后,从结果中拿到的 133let serviceUuid = 'xxx'; 134let characteristicUuid = 'xxx'; 135let descriptorUuid = 'xxx'; 136let descriptorValue = new Uint8Array('xxx'.length).buffer; 137let characteristicValue = new Uint8Array('xxx'.length).buffer; 138let descriptors: Array<ble.BLEDescriptor> = new Array<ble.BLEDescriptor>(); 139let descriptor: ble.BLEDescriptor = { 140 serviceUuid: serviceUuid, 141 characteristicUuid: characteristicUuid, 142 descriptorUuid: descriptorUuid, 143 descriptorValue: descriptorValue 144} 145descriptors.push(descriptor); 146let bleCharacteristicDataIn: ble.BLECharacteristic = { 147 serviceUuid: serviceUuid, 148 characteristicUuid: characteristicUuid, 149 characteristicValue: characteristicValue, 150 descriptors: descriptors 151}; 152clientDevice.readCharacteristicValue(bleCharacteristicDataIn, (err, bleCharacteristicDataOut) => { 153 if (err != null) { 154 console.error('readCharacteristicValue error, code = ' + (err as BusinessError).code) 155 return; 156 } 157 let message = 'characteristic value = '; 158 let value = new Uint8Array(bleCharacteristicDataOut.characteristicValue); 159 for (let i = 0; i < bleCharacteristicDataOut.characteristicValue.byteLength; i++) { 160 message += value[i]; 161 } 162 console.info(message); 163}); 164 165// 读取描述符 166let descriptorIn: ble.BLEDescriptor = { 167 serviceUuid: serviceUuid, 168 characteristicUuid: characteristicUuid, 169 descriptorUuid: descriptorUuid, 170 descriptorValue: descriptorValue 171}; 172clientDevice.readDescriptorValue(descriptorIn, (err, descriptorOut) => { 173 if (err != null) { 174 console.error('readDescriptorValue error, code: ' + (err as BusinessError).code) 175 return; 176 } 177 let message = 'descriptor value: '; 178 let value = new Uint8Array(descriptorOut.descriptorValue); 179 for (let i = 0; i < descriptorOut.descriptorValue.byteLength; i++) { 180 message += value[i]; 181 } 182 console.info(message); 183}); 184 185// 写入特征值 186let string2ArrayBuffer: (str: string) => ArrayBuffer = (str: string): ArrayBuffer => { 187 let array = new Uint8Array(str.length); 188 for (let i = 0; i < str.length; i++) { 189 array[i] = str.charCodeAt(i); 190 } 191 return array.buffer; 192} 193 194let bufferCCC = string2ArrayBuffer('V'); 195let characteristic: ble.BLECharacteristic = { 196 serviceUuid: serviceUuid, 197 characteristicUuid: characteristicUuid, 198 characteristicValue: bufferCCC, 199 descriptors: descriptors 200}; 201clientDevice.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE); 202 203// 写入描述符 204let message = ''; 205if (clientDevice.writeDescriptorValue(descriptor)) { 206 message = 'writeDescriptorValue success'; 207} else { 208 message = 'writeDescriptorValue failed'; 209} 210console.info(message); 211 212// 断开连接 213clientDevice.disconnect(); 214console.info('disconnect success') 215 216// 关闭GattClient实例 217clientDevice.close(); 218console.info('close gattClientDevice success'); 219``` 220 2219. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。 222 223 224### server端操作services和通知客户端信息 2251. import需要的ble模块。 2262. 创建gattServer实例对象。 2273. 添加services信息。 2284. 当向gattServer写入特征值通知gattClient。 2295. 移除services信息。 2306. 注销gattServer实例。 2317. 示例代码: 232 233```ts 234import ble from '@ohos.bluetooth.ble'; 235import { BusinessError } from '@ohos.base'; 236 237// 创建gattServer实例 238let gattServerInstance = ble.createGattServer(); 239 240// 添加services 241let string2ArrayBuffer: (str: string) => ArrayBuffer = (str: string): ArrayBuffer => { 242 let array = new Uint8Array(str.length); 243 for (let i = 0; i < str.length; i++) { 244 array[i] = str.charCodeAt(i); 245 } 246 return array.buffer; 247} 248 249let characteristicsArray: Array<ble.BLECharacteristic> = new Array<ble.BLECharacteristic>(); 250let descriptorsArray: Array<ble.BLEDescriptor> = new Array<ble.BLEDescriptor>(); 251let characteristics1: ble.BLECharacteristic = { 252 serviceUuid: '0000aaaa-0000-1000-8000-00805f9b34fb', 253 characteristicUuid: '00002a10-0000-1000-8000-00805f9b34fb', 254 characteristicValue: string2ArrayBuffer('I am charac1'), 255 descriptors: descriptorsArray 256}; 257characteristicsArray.push(characteristics1); 258 259let descriptors1: ble.BLEDescriptor = { 260 serviceUuid: '0000aaaa-0000-1000-8000-00805f9b34fb', 261 characteristicUuid: '00002a10-0000-1000-8000-00805f9b34fb', 262 descriptorUuid: '00002904-0000-1000-8000-00805f9b34fb', 263 descriptorValue: string2ArrayBuffer('I am Server Descriptor1') 264} 265let descriptors2: ble.BLEDescriptor = { 266 serviceUuid: '0000aaaa-0000-1000-8000-00805f9b34fb', 267 characteristicUuid: '00002a10-0000-1000-8000-00805f9b34fb', 268 descriptorUuid: '00002905-0000-1000-8000-00805f9b34fb', 269 descriptorValue: string2ArrayBuffer('I am Server Descriptor2') 270} 271descriptorsArray.push(descriptors1); 272descriptorsArray.push(descriptors2); 273 274let service: ble.GattService = { 275 serviceUuid: '0000aaaa-0000-1000-8000-00805f9b34fb', 276 isPrimary: true, 277 characteristics: characteristicsArray 278}; 279gattServerInstance.addService(service); 280console.info('addService success'); 281 282// 订阅写特征值事件,向gattClient发送response 283gattServerInstance.on('characteristicWrite', (characteristicWriteReq) => { 284 let deviceId = characteristicWriteReq.deviceId; 285 let transId = characteristicWriteReq.transId; 286 let offset = characteristicWriteReq.offset; 287 let needRsp = characteristicWriteReq.needRsp; 288 let arrayBufferCCC: ArrayBuffer = string2ArrayBuffer('characteristicWriteForResponse'); 289 let serverResponse: ble.ServerResponse = { 290 deviceId: deviceId, 291 transId: transId, 292 status: 0, 293 offset: offset, 294 value: arrayBufferCCC 295 }; 296 // 发送response 297 if (needRsp) { 298 gattServerInstance.sendResponse(serverResponse); 299 console.info('sendResponse success, response data: ' + JSON.stringify(serverResponse)); 300 } 301 // 关闭订阅写特征值事件 302 gattServerInstance.off('characteristicWrite'); 303}) 304 305// 订阅写特征值事件,特征值变化,通知gattClient 306gattServerInstance.on('characteristicWrite', (characteristicWriteReq) => { 307 let characteristicUuid = characteristicWriteReq.characteristicUuid; 308 let serviceUuid = characteristicWriteReq.serviceUuid; 309 let deviceId = characteristicWriteReq.deviceId; 310 let notifyCharacteristic: ble.NotifyCharacteristic = { 311 serviceUuid: serviceUuid, 312 characteristicUuid: characteristicUuid, 313 characteristicValue: string2ArrayBuffer('Value4notifyCharacteristic'), 314 confirm: false 315 } 316 // 特征值变化时,通知已连接的client设备 317 gattServerInstance.notifyCharacteristicChanged(deviceId, notifyCharacteristic); 318 console.info('notifyCharacteristicChanged success, deviceId = ' + deviceId); 319 // 关闭订阅写特征值事件 320 gattServerInstance.off('characteristicWrite'); 321}) 322 323// 移除service 324gattServerInstance.removeService('0000aaaa-0000-1000-8000-00805f9b34fb'); 325console.info('removeService success') 326 327// 注销gattServer实例 328gattServerInstance.close(); 329console.info('close gattServerInstance success'); 330``` 331 3328. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。