• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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```