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的特征值和描述符。
645. 向gattServer写入特征值和描述符。
656. 断开连接,销毁gattClient实例。
667. 示例代码:
67
68    ```ts
69    import { ble } from '@kit.ConnectivityKit';
70    import { constant } from '@kit.ConnectivityKit';
71    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
72
73    const TAG: string = 'GattClientManager';
74
75    export class GattClientManager {
76      device: string | undefined = undefined;
77      gattClient: ble.GattClientDevice | undefined = undefined;
78      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
79      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
80      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
81      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902一般用于notification或者indication
82      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
83      found: boolean = false;
84
85      // 构造BLEDescriptor
86      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
87        let descriptor: ble.BLEDescriptor = {
88          serviceUuid: this.myServiceUuid,
89          characteristicUuid: this.myCharacteristicUuid,
90          descriptorUuid: des,
91          descriptorValue: value
92        };
93        return descriptor;
94      }
95
96      // 构造BLECharacteristic
97      private initCharacteristic(): ble.BLECharacteristic {
98        let descriptors: Array<ble.BLEDescriptor> = [];
99        let descBuffer = new ArrayBuffer(2);
100        let descValue = new Uint8Array(descBuffer);
101        descValue[0] = 11;
102        descValue[1] = 12;
103        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
104        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
105        let charBuffer = new ArrayBuffer(2);
106        let charValue = new Uint8Array(charBuffer);
107        charValue[0] = 1;
108        charValue[1] = 2;
109        let characteristic: ble.BLECharacteristic = {
110          serviceUuid: this.myServiceUuid,
111          characteristicUuid: this.myCharacteristicUuid,
112          characteristicValue: charBuffer,
113          descriptors: descriptors
114        };
115        return characteristic;
116      }
117
118      private logCharacteristic(char: ble.BLECharacteristic) {
119        let message = 'logCharacteristic uuid:' + char.characteristicUuid + '\n';
120        let value = new Uint8Array(char.characteristicValue);
121        message += 'logCharacteristic value: ';
122        for (let i = 0; i < char.characteristicValue.byteLength; i++) {
123          message += value[i] + ' ';
124        }
125        console.info(TAG, message);
126      }
127
128      private logDescriptor(des: ble.BLEDescriptor) {
129        let message = 'logDescriptor uuid:' + des.descriptorUuid + '\n';
130        let value = new Uint8Array(des.descriptorValue);
131        message += 'logDescriptor value: ';
132        for (let i = 0; i < des.descriptorValue.byteLength; i++) {
133          message += value[i] + ' ';
134        }
135        console.info(TAG, message);
136      }
137
138      private checkService(services: Array<ble.GattService>): boolean {
139        for (let i = 0; i < services.length; i++) {
140          if (services[i].serviceUuid != this.myServiceUuid) {
141            continue;
142          }
143          for (let j = 0; j < services[i].characteristics.length; j++) {
144            if (services[i].characteristics[j].characteristicUuid != this.myCharacteristicUuid) {
145              continue;
146            }
147            for (let k = 0; k < services[i].characteristics[j].descriptors.length; k++) {
148              if (services[i].characteristics[j].descriptors[k].descriptorUuid == this.myFirstDescriptorUuid) {
149                console.info(TAG, 'find expected service from server');
150                return true;
151              }
152            }
153          }
154        }
155        console.error(TAG, 'no expected service from server');
156        return false;
157      }
158
159      // 1. 订阅连接状态变化事件
160      public onGattClientStateChange() {
161        if (!this.gattClient) {
162          console.error(TAG, 'no gattClient');
163          return;
164        }
165        try {
166          this.gattClient.on('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
167            let state = '';
168            switch (stateInfo.state) {
169              case 0:
170                state = 'DISCONNECTED';
171                break;
172              case 1:
173                state = 'CONNECTING';
174                break;
175              case 2:
176                state = 'CONNECTED';
177                break;
178              case 3:
179                state = 'DISCONNECTING';
180                break;
181              default:
182                state = 'undefined';
183                break;
184            }
185            console.info(TAG, 'onGattClientStateChange: device=' + stateInfo.deviceId + ', state=' + state);
186            if (stateInfo.deviceId == this.device) {
187              this.connectState = stateInfo.state;
188            }
189          });
190        } catch (err) {
191          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
192        }
193      }
194
195      // 2. client端主动连接时调用
196      public startConnect(peerDevice: string) { // 对端设备一般通过ble scan获取到
197        if (this.connectState != constant.ProfileConnectionState.STATE_DISCONNECTED) {
198          console.error(TAG, 'startConnect failed');
199          return;
200        }
201        console.info(TAG, 'startConnect ' + peerDevice);
202        this.device = peerDevice;
203        // 2.1 使用device构造gattClient,后续的交互都需要使用该实例
204        this.gattClient = ble.createGattClientDevice(peerDevice);
205        try {
206          this.onGattClientStateChange(); // 2.2 订阅连接状态
207          this.gattClient.connect(); // 2.3 发起连接
208        } catch (err) {
209          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
210        }
211      }
212
213      // 3. client端连接成功后,需要进行服务发现
214      public discoverServices() {
215        if (!this.gattClient) {
216          console.info(TAG, 'no gattClient');
217          return;
218        }
219        console.info(TAG, 'discoverServices');
220        try {
221          this.gattClient.getServices().then((result: Array<ble.GattService>) => {
222            console.info(TAG, 'getServices success: ' + JSON.stringify(result));
223            this.found = this.checkService(result); // 要确保server端的服务内容有业务所需要的服务
224          });
225        } catch (err) {
226          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
227        }
228      }
229
230      // 4. 在确保拿到了server端的服务结果后,读取server端特定服务的特征值时调用
231      public readCharacteristicValue() {
232        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
233          console.error(TAG, 'no gattClient or not connected');
234          return;
235        }
236        if (!this.found) { // 要确保server端有对应的characteristic
237          console.error(TAG, 'no characteristic from server');
238          return;
239        }
240
241        let characteristic = this.initCharacteristic();
242        console.info(TAG, 'readCharacteristicValue');
243        try {
244          this.gattClient.readCharacteristicValue(characteristic).then((outData: ble.BLECharacteristic) => {
245            this.logCharacteristic(outData);
246          })
247        } catch (err) {
248          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
249        }
250      }
251
252      // 5. 在确保拿到了server端的服务结果后,写入server端特定服务的特征值时调用
253      public writeCharacteristicValue() {
254        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
255          console.error(TAG, 'no gattClient or not connected');
256          return;
257        }
258        if (!this.found) { // 要确保server端有对应的characteristic
259          console.error(TAG, 'no characteristic from server');
260          return;
261        }
262
263        let characteristic = this.initCharacteristic();
264        console.info(TAG, 'writeCharacteristicValue');
265        try {
266          this.gattClient.writeCharacteristicValue(characteristic, ble.GattWriteType.WRITE, (err) => {
267            if (err) {
268              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
269              return;
270            }
271            console.info(TAG, 'writeCharacteristicValue success');
272          });
273        } catch (err) {
274          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
275        }
276      }
277
278      // 6. 在确保拿到了server端的服务结果后,读取server端特定服务的描述符时调用
279      public readDescriptorValue() {
280        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
281          console.error(TAG, 'no gattClient or not connected');
282          return;
283        }
284        if (!this.found) { // 要确保server端有对应的descriptor
285          console.error(TAG, 'no descriptor from server');
286          return;
287        }
288
289        let descBuffer = new ArrayBuffer(0);
290        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
291        console.info(TAG, 'readDescriptorValue');
292        try {
293          this.gattClient.readDescriptorValue(descriptor).then((outData: ble.BLEDescriptor) => {
294            this.logDescriptor(outData);
295          });
296        } catch (err) {
297          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
298        }
299      }
300
301      // 7. 在确保拿到了server端的服务结果后,写入server端特定服务的描述符时调用
302      public writeDescriptorValue() {
303        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
304          console.error(TAG, 'no gattClient or not connected');
305          return;
306        }
307        if (!this.found) { // 要确保server端有对应的descriptor
308          console.error(TAG, 'no descriptor from server');
309          return;
310        }
311
312        let descBuffer = new ArrayBuffer(2);
313        let descValue = new Uint8Array(descBuffer);
314        descValue[0] = 11;
315        descValue[1] = 12;
316        let descriptor = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
317        console.info(TAG, 'writeDescriptorValue');
318        try {
319          this.gattClient.writeDescriptorValue(descriptor, (err) => {
320            if (err) {
321              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
322              return;
323            }
324            console.info(TAG, 'writeDescriptorValue success');
325          });
326        } catch (err) {
327          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
328        }
329      }
330
331      // 8.client端主动断开时调用
332      public stopConnect() {
333        if (!this.gattClient || this.connectState != constant.ProfileConnectionState.STATE_CONNECTED) {
334          console.error(TAG, 'no gattClient or not connected');
335          return;
336        }
337
338        console.info(TAG, 'stopConnect ' + this.device);
339        try {
340          this.gattClient.disconnect(); // 8.1 断开连接
341          this.gattClient.off('BLEConnectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
342          });
343          this.gattClient.close() // 8.2 如果不再使用此gattClient,则需要close
344        } catch (err) {
345          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
346        }
347      }
348    }
349
350    let gattClientManager = new GattClientManager();
351    export default gattClientManager as GattClientManager;
352    ```
353
3549. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。
355
356
357### server端操作services和通知客户端信息
3581. import需要的ble模块。
3592. 创建gattServer实例对象。
3603. 添加services信息。
3614. 当向gattServer写入特征值通知gattClient。
3625. 移除services信息。
3636. 注销gattServer实例。
3647. 示例代码:
365
366    ```ts
367    import { ble } from '@kit.ConnectivityKit';
368    import { constant } from '@kit.ConnectivityKit';
369    import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
370
371    const TAG: string = 'GattServerManager';
372
373    export class GattServerManager {
374      gattServer: ble.GattServer | undefined = undefined;
375      connectState: ble.ProfileConnectionState = constant.ProfileConnectionState.STATE_DISCONNECTED;
376      myServiceUuid: string = '00001810-0000-1000-8000-00805F9B34FB';
377      myCharacteristicUuid: string = '00001820-0000-1000-8000-00805F9B34FB';
378      myFirstDescriptorUuid: string = '00002902-0000-1000-8000-00805F9B34FB'; // 2902一般用于notification或者indication
379      mySecondDescriptorUuid: string = '00002903-0000-1000-8000-00805F9B34FB';
380
381      // 构造BLEDescriptor
382      private initDescriptor(des: string, value: ArrayBuffer): ble.BLEDescriptor {
383        let descriptor: ble.BLEDescriptor = {
384          serviceUuid: this.myServiceUuid,
385          characteristicUuid: this.myCharacteristicUuid,
386          descriptorUuid: des,
387          descriptorValue: value
388        };
389        return descriptor;
390      }
391
392      // 构造BLECharacteristic
393      private initCharacteristic(): ble.BLECharacteristic {
394        let descriptors: Array<ble.BLEDescriptor> = [];
395        let descBuffer = new ArrayBuffer(2);
396        let descValue = new Uint8Array(descBuffer);
397        descValue[0] = 31;
398        descValue[1] = 32;
399        descriptors[0] = this.initDescriptor(this.myFirstDescriptorUuid, new ArrayBuffer(2));
400        descriptors[1] = this.initDescriptor(this.mySecondDescriptorUuid, descBuffer);
401        let charBuffer = new ArrayBuffer(2);
402        let charValue = new Uint8Array(charBuffer);
403        charValue[0] = 21;
404        charValue[1] = 22;
405        let characteristic: ble.BLECharacteristic = {
406          serviceUuid: this.myServiceUuid,
407          characteristicUuid: this.myCharacteristicUuid,
408          characteristicValue: charBuffer,
409          descriptors: descriptors
410        };
411        return characteristic;
412      }
413
414      // 1. 订阅连接状态变化事件
415      public onGattServerStateChange() {
416        if (!this.gattServer) {
417          console.error(TAG, 'no gattServer');
418          return;
419        }
420        try {
421          this.gattServer.on('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => {
422            let state = '';
423            switch (stateInfo.state) {
424              case 0:
425                state = 'DISCONNECTED';
426                break;
427              case 1:
428                state = 'CONNECTING';
429                break;
430              case 2:
431                state = 'CONNECTED';
432                break;
433              case 3:
434                state = 'DISCONNECTING';
435                break;
436              default:
437                state = 'undefined';
438                break;
439            }
440            console.info(TAG, 'onGattServerStateChange: device=' + stateInfo.deviceId + ', state=' + state);
441          });
442        } catch (err) {
443          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
444        }
445      }
446
447      // 2. server端注册服务时调用
448      public registerServer() {
449        let characteristics: Array<ble.BLECharacteristic> = [];
450        let characteristic = this.initCharacteristic();
451        characteristics.push(characteristic);
452        let gattService: ble.GattService = {
453          serviceUuid: this.myServiceUuid,
454          isPrimary: true,
455          characteristics: characteristics
456        };
457
458        console.info(TAG, 'registerServer ' + this.myServiceUuid);
459        try {
460          this.gattServer = ble.createGattServer(); // 2.1 构造gattServer,后续的交互都需要使用该实例
461          this.onGattServerStateChange(); // 2.2 订阅连接状态
462          this.gattServer.addService(gattService);
463        } catch (err) {
464          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
465        }
466      }
467
468      // 3. 订阅来自gattClient的读取特征值请求时调用
469      public onCharacteristicRead() {
470        if (!this.gattServer) {
471          console.error(TAG, 'no gattServer');
472          return;
473        }
474
475        console.info(TAG, 'onCharacteristicRead');
476        try {
477          this.gattServer.on('characteristicRead', (charReq: ble.CharacteristicReadRequest) => {
478            let deviceId: string = charReq.deviceId;
479            let transId: number = charReq.transId;
480            let offset: number = charReq.offset;
481            console.info(TAG, 'receive characteristicRead');
482            let rspBuffer = new ArrayBuffer(2);
483            let rspValue = new Uint8Array(rspBuffer);
484            rspValue[0] = 21;
485            rspValue[1] = 22;
486            let serverResponse: ble.ServerResponse = {
487              deviceId: deviceId,
488              transId: transId,
489              status: 0, // 0表示成功
490              offset: offset,
491              value: rspBuffer
492            };
493
494            try {
495              this.gattServer.sendResponse(serverResponse);
496            } catch (err) {
497              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
498            }
499          });
500        } catch (err) {
501          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
502        }
503      }
504
505      // 4. 订阅来自gattClient的写入特征值请求时调用
506      public onCharacteristicWrite() {
507        if (!this.gattServer) {
508          console.error(TAG, 'no gattServer');
509          return;
510        }
511
512        console.info(TAG, 'onCharacteristicWrite');
513        try {
514          this.gattServer.on('characteristicWrite', (charReq: ble.CharacteristicWriteRequest) => {
515            let deviceId: string = charReq.deviceId;
516            let transId: number = charReq.transId;
517            let offset: number = charReq.offset;
518            console.info(TAG, 'receive characteristicWrite: needRsp=' + charReq.needRsp);
519            if (!charReq.needRsp) {
520              return;
521            }
522            let rspBuffer = new ArrayBuffer(0);
523            let serverResponse: ble.ServerResponse = {
524              deviceId: deviceId,
525              transId: transId,
526              status: 0, // 0表示成功
527              offset: offset,
528              value: rspBuffer
529            };
530
531            try {
532              this.gattServer.sendResponse(serverResponse);
533            } catch (err) {
534              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
535            }
536          });
537        } catch (err) {
538          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
539        }
540      }
541
542      // 5. 订阅来自gattClient的读取描述符请求时调用
543      public onDescriptorRead() {
544        if (!this.gattServer) {
545          console.error(TAG, 'no gattServer');
546          return;
547        }
548
549        console.info(TAG, 'onDescriptorRead');
550        try {
551          this.gattServer.on('descriptorRead', (desReq: ble.DescriptorReadRequest) => {
552            let deviceId: string = desReq.deviceId;
553            let transId: number = desReq.transId;
554            let offset: number = desReq.offset;
555            console.info(TAG, 'receive descriptorRead');
556            let rspBuffer = new ArrayBuffer(2);
557            let rspValue = new Uint8Array(rspBuffer);
558            rspValue[0] = 31;
559            rspValue[1] = 32;
560            let serverResponse: ble.ServerResponse = {
561              deviceId: deviceId,
562              transId: transId,
563              status: 0, // 0表示成功
564              offset: offset,
565              value: rspBuffer
566            };
567
568            try {
569              this.gattServer.sendResponse(serverResponse);
570            } catch (err) {
571              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
572            }
573          });
574        } catch (err) {
575          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
576        }
577      }
578
579      // 6. 订阅来自gattClient的写入描述符请求时调用
580      public onDescriptorWrite() {
581        if (!this.gattServer) {
582          console.error(TAG, 'no gattServer');
583          return;
584        }
585
586        console.info(TAG, 'onDescriptorWrite');
587        try {
588          this.gattServer.on('descriptorWrite', (desReq: ble.DescriptorWriteRequest) => {
589            let deviceId: string = desReq.deviceId;
590            let transId: number = desReq.transId;
591            let offset: number = desReq.offset;
592            console.info(TAG, 'receive descriptorWrite: needRsp=' + desReq.needRsp);
593            if (!desReq.needRsp) {
594              return;
595            }
596            let rspBuffer = new ArrayBuffer(0);
597            let serverResponse: ble.ServerResponse = {
598              deviceId: deviceId,
599              transId: transId,
600              status: 0, // 0表示成功
601              offset: offset,
602              value: rspBuffer
603            };
604
605            try {
606              this.gattServer.sendResponse(serverResponse);
607            } catch (err) {
608              console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
609            }
610          });
611        } catch (err) {
612          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
613        }
614      }
615
616      // 7. server端删除服务,不再使用时调用
617      public unRegisterServer() {
618        if (!this.gattServer) {
619          console.error(TAG, 'no gattServer');
620          return;
621        }
622
623        console.info(TAG, 'unRegisterServer ' + this.myServiceUuid);
624        try {
625          this.gattServer.removeService(this.myServiceUuid); // 7.1 删除服务
626          this.gattServer.off('connectionStateChange', (stateInfo: ble.BLEConnectionChangeState) => { // 7.2 取消订阅连接状态
627          });
628          this.gattServer.close() // 7.3 如果不再使用此gattServer,则需要close
629        } catch (err) {
630          console.error(TAG, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
631        }
632      }
633    }
634
635    let gattServerManager = new GattServerManager();
636    export default gattServerManager as GattServerManager;
637    ```
638
6398. 错误码请参见[蓝牙服务子系统错误码](../../reference/apis-connectivity-kit/errorcode-bluetoothManager.md)。