一、Gatt的概述
Bluetooth GATT (Generic Attribute Profile) 是蓝牙4.0新加入的一项协议,它规定了设备之间基于属性的通信方式。其主要作用是用于BLE(蓝牙低功耗)设备之间的数据传输。通过Gatt来完成对设备的控制、设置设备的属性、进行数据传输、监听设备的属性变化等。其主要的核心是通过UUID(通用唯一识别码)来区分不同的服务和特征(含多个属性)。Gatt的优势在于其低功耗、易于使用和大量使用的标准协议。
二、Gatt的体系架构
在Gatt的体系架构中包含了Service、Characteristic和Descriptor三个部分,它们构成了一个完整的Gatt服务。
Service:包含一个或多个Characteristic,一个Service可以包含多个Descriptor,可以理解为一个Service对应于一个设备模块(如温度计)或一组相关属性(如心率服务),每个Service均被分配了一个唯一的16位或128位的UUID。
Characteristic:由于service可能包含多个Characteristic,因此每一个Characteristic都应该包含一个唯一的UUID标识。Characteristic被用来表示一个数据的特征,一个Characteristic可能包含一个指针,指向当前Characteristic的值,也可能包含多个属性的集合。包括read(读取)、write(写入)、notify(通知)和indicate(指向)等操作。
Descriptor:为了描述一个Characteristics的属性,曲线求助 Descriptors。Descriptors也是包含一个唯一UUID标识,用来描述某个Characteristic中的一个特征,可以用于对Characteristic的Permissions(权限)和Characteristic的Value(数值)进行描述。
三、Gatt的实现方式
Gatt可以通过Android中的BluetoothGatt类进行实现。以下是Gatt实现的示例代码,其中主要包括了Gatt的连接、服务扫描、数据读写等操作。
/** * 确保该操作完成后,才进行下一步操作 */ private CountDownLatch countDownLatch = null; public void getMtvAllNotification() { ListsupportedGattServices = getSupportedGattServices(); Logger.i("服务数量 " + supportedGattServices.size()); for (BluetoothGattService bluetoothGattService : supportedGattServices) { if (bluetoothGattService != null) { Logger.i("服务uuid " + bluetoothGattService.getUuid().toString()); List characteristics = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic characteristic : characteristics) { if (characteristic != null) { Logger.i("特征uuid " + characteristic.getUuid().toString()); if (countDownLatch != null) { try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } final int charaProp = characteristic.getProperties(); Logger.d("当期操作属性 " + charaProp); if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) { // 据说按照4.4 版本core specification 规定,android 4.3需要做这个特殊处理 不然会出现133错误 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { Logger.d("readCharacteristic(characteristic) " + characteristic.getUuid()); readCharacteristic(characteristic); } }, 33); } if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { boolean isAdded = enableNotification(true, characteristic); if (isAdded) { // 设置同步工具类初始值为1 countDownLatch = new CountDownLatch(1); } } } } } } } private void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null) { return; } boolean isRead = bluetoothGatt.readCharacteristic(characteristic); Logger.d("readCharacteristic isRead:" + isRead); } /** * 注册/取消通知 */ private List characteristicNotificationList = new ArrayList<>(); public boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null || characteristic == null) { return false; } int properties = characteristic.getProperties(); boolean success = bluetoothGatt.setCharacteristicNotification(characteristic, enable); Logger.d("setCharacteristicNotification status = " + success); /* * 取得描述符 * 必须要有的代码,根据已有的uuid创建描述符,特征描述的UUID是固定的,根据业务逻辑定。 * 下面描述符的UUID固定为0x2902 */ BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(SampleGattAttributes.DESCRIPTOR_CONFIG)); if (descriptor != null) { if (enable) { descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); } else { descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } success = bluetoothGatt.writeDescriptor(descriptor); Logger.d("writeDescriptor status = " + success); if (success) { if (enable) { characteristicNotificationList.add(characteristic); } else { characteristicNotificationList.remove(characteristic); } } } return success; }
四、Gatt的相关注意事项
在使用Gatt时,需要注意以下事项:
1、Gatt的操作为异步操作,需要处理好操作完成后的回调;
2、Gatt的连接错误码较多,需要根据实际情况进行处理;
3、Gatt在传输数据时需要确保数据格式正确,如endian的问题;
4、Gatt的模式分为GATT、ATT,其中GATT区分操作和数据,ATT不区分操作和数据;
5、Gatt中的权限问题需要注意,需要确保应用有足够的权限进行Gatt操作。
五、Gatt的应用场景
Gatt主要应用于一些低功耗、易于连接和易于控制的设备中,如智能家居、智能穿戴、健康检测设备等。它可以通过传输数据来进行设备之间的通讯和控制,具有广泛的应用前景。