文章目录
- [1. 什么是蓝牙 GATT 协议?](#1. 什么是蓝牙 GATT 协议?)
-
- [1.1 GATT 的核心组件](#1.1 GATT 的核心组件)
- [1.2 GATT 的主要操作](#1.2 GATT 的主要操作)
- [2. GATT 协议在 Android 上的实现](#2. GATT 协议在 Android 上的实现)
- [3. 常见问题与解决方案](#3. 常见问题与解决方案)
-
- [3.1 连接成功,但无法读取或写入特征](#3.1 连接成功,但无法读取或写入特征)
- [3.2 特征通知延迟或丢失](#3.2 特征通知延迟或丢失)
- [3.3 设备无法支持高频率通知](#3.3 设备无法支持高频率通知)
- 总结
1. 什么是蓝牙 GATT 协议?
蓝牙 GATT(Generic Attribute Profile,通用属性配置文件)是基于低功耗蓝牙(Bluetooth Low Energy, BLE)的一个重要协议,用于定义如何在设备之间传输数据。它是 BLE 的核心协议之一,广泛应用于智能手环、蓝牙传感器等 IoT 设备。
1.1 GATT 的核心组件
- Server(服务端):提供数据的设备(如蓝牙传感器)。
- Client(客户端):读取或写入数据的设备(如手机)。
- Service(服务):表示某个功能,如 Heart Rate Service(心率服务),包含多个特征。
- Characteristic(特征):特征是服务中的数据单元,包含数据和权限(如读、写、通知)。
- Descriptor(描述符):用于描述特征的元数据,例如单位、范围等。
1.2 GATT 的主要操作
- Discover Services:发现可用服务。
- Read/Write Characteristic:读取或写入特征值。
- Enable Notifications/Indications:订阅特征的通知。
- Execute Write:执行批量写操作。
2. GATT 协议在 Android 上的实现
下面是一个详细的 GATT 协议在 Android 上的实现示例,包括相关的注释。这个实现涵盖了连接蓝牙设备、发现服务、读取和写入特征、启用通知等操作。为了确保代码清晰,我将会详细解释每一部分的作用。
kotlin
class BluetoothGattManager(private val context: Context) {
private var bluetoothGatt: BluetoothGatt? = null
private var bluetoothDevice: BluetoothDevice? = null
// GATT 回调,用于处理与蓝牙设备的交互
private val gattCallback = object : BluetoothGattCallback() {
// 连接状态发生变化时的回调
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("BluetoothGatt", "Connected to GATT server")
// 连接后开始发现服务
gatt.discoverServices()
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("BluetoothGatt", "Disconnected from GATT server")
// 连接断开时关闭 GATT
gatt.close()
}
}
// 服务发现时的回调
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("BluetoothGatt", "Services discovered")
// 在此可以选择读取服务或特征
// 例如读取心率测量特征
val heartRateService = gatt.getService(UUID.fromString(HEART_RATE_SERVICE_UUID))
val heartRateMeasurement = heartRateService?.getCharacteristic(UUID.fromString(HEART_RATE_MEASUREMENT_UUID))
gatt.readCharacteristic(heartRateMeasurement)
} else {
Log.e("BluetoothGatt", "Service discovery failed, status: $status")
}
}
// 读取特征值时的回调
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("BluetoothGatt", "Characteristic read successfully: ${characteristic.value}")
// 可以处理读取的数据
} else {
Log.e("BluetoothGatt", "Read failed, status: $status")
}
}
// 写入特征值时的回调
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("BluetoothGatt", "Characteristic written successfully: ${characteristic.value}")
} else {
Log.e("BluetoothGatt", "Write failed, status: $status")
}
}
// 特征值的通知回调
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
Log.d("BluetoothGatt", "Characteristic changed: ${characteristic.value}")
// 可以处理通知数据
}
// 描述符的写入回调
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d("BluetoothGatt", "Descriptor written successfully")
} else {
Log.e("BluetoothGatt", "Descriptor write failed, status: $status")
}
}
}
// 蓝牙设备连接
fun connectToDevice(device: BluetoothDevice) {
bluetoothDevice = device
bluetoothGatt = device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
}
// 断开与设备的连接
fun disconnect() {
bluetoothGatt?.disconnect()
}
// 开始读取特征数据
fun readHeartRateMeasurement() {
val heartRateService = bluetoothGatt?.getService(UUID.fromString(HEART_RATE_SERVICE_UUID))
val heartRateMeasurement = heartRateService?.getCharacteristic(UUID.fromString(HEART_RATE_MEASUREMENT_UUID))
bluetoothGatt?.readCharacteristic(heartRateMeasurement)
}
// 开始写入特征数据
fun writeHeartRateMeasurement(value: ByteArray) {
val heartRateService = bluetoothGatt?.getService(UUID.fromString(HEART_RATE_SERVICE_UUID))
val heartRateMeasurement = heartRateService?.getCharacteristic(UUID.fromString(HEART_RATE_MEASUREMENT_UUID))
heartRateMeasurement?.value = value
bluetoothGatt?.writeCharacteristic(heartRateMeasurement)
}
// 启用特征通知
fun enableHeartRateNotifications() {
val heartRateService = bluetoothGatt?.getService(UUID.fromString(HEART_RATE_SERVICE_UUID))
val heartRateMeasurement = heartRateService?.getCharacteristic(UUID.fromString(HEART_RATE_MEASUREMENT_UUID))
bluetoothGatt?.setCharacteristicNotification(heartRateMeasurement, true)
// 启用通知描述符
val descriptor = heartRateMeasurement?.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG_UUID))
descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
bluetoothGatt?.writeDescriptor(descriptor)
}
// UUID 常量定义
companion object {
const val HEART_RATE_SERVICE_UUID = "0000180D-0000-1000-8000-00805f9b34fb" // 心率服务 UUID
const val HEART_RATE_MEASUREMENT_UUID = "00002A37-0000-1000-8000-00805f9b34fb" // 心率测量特征 UUID
const val CLIENT_CHARACTERISTIC_CONFIG_UUID = "00002902-0000-1000-8000-00805f9b34fb" // 通知描述符 UUID
}
}
代码解释
2.1. BluetoothGattManager 类
该类封装了与蓝牙 GATT 设备交互的基本操作,包括连接、断开连接、读取/写入特征、启用通知等。
- BluetoothGatt:用于与远程设备的 GATT 服务器进行交互。
- BluetoothGattCallback:所有 GATT 操作的回调,包括连接状态、服务发现、特征操作等。
2.2. 连接蓝牙设备
通过调用 connectToDevice 方法,我们可以通过 BluetoothDevice 对象来连接到远程设备。连接过程是异步的,结果会通过 BluetoothGattCallback 回调来处理。
kotlin
bluetoothGatt = device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
- 参数:
context : 当前应用的上下文。
false : 不使用自动连接。
gattCallback : 回调,用于处理 GATT 事件。
TRANSPORT_LE: 指定蓝牙低功耗模式。
2.3.服务发现
连接设备后,调用 gatt.discoverServices() 发现远程设备提供的所有服务。发现完成后,onServicesDiscovered 回调会被触发。
2.4. 读取特征
通过 readCharacteristic 读取特征值。特征是通过服务来获取的,必须先通过 UUID 获取对应的服务,再获取特征。
kotlin
val heartRateMeasurement = heartRateService?.getCharacteristic(UUID.fromString(HEART_RATE_MEASUREMENT_UUID))
bluetoothGatt?.readCharacteristic(heartRateMeasurement)
2.5. 写入特征
通过 writeCharacteristic 向设备写入数据。例如,将某个测量值写入心率测量特征。
kotlin
bluetoothGatt?.writeCharacteristic(heartRateMeasurement)
2.6. 启用通知
通过 setCharacteristicNotification 启用特征通知,并通过描述符使能通知。
这意味客户端(如 Android 设备)希望接收该特征的通知
kotlin
bluetoothGatt?.setCharacteristicNotification(heartRateMeasurement, true)
val descriptor = heartRateMeasurement?.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG_UUID))
descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
bluetoothGatt?.writeDescriptor(descriptor)
2.7. 错误处理与资源管理
- 使用 onConnectionStateChange 处理连接和断开的状态。
- 使用 onCharacteristicRead, onCharacteristicWrite, onCharacteristicChanged 处理特征的读写和通知。
- 在连接断开时,调用 gatt.close() 来释放 GATT 连接资源。
3. 常见问题与解决方案
3.1 连接成功,但无法读取或写入特征
问题描述:
连接到设备后,客户端可以成功连接,但无法读取或写入特征。
解决方案:
1、检查 GATT 特征是否正确支持读取/写入 :确保在 GATT 服务的特征中定义了适当的权限(例如 READ 或 WRITE)。
2、检查特征的通知和描述符:如果启用了通知,需要确保已设置正确的描述符来启用通知(例如 Client Characteristic Configuration Descriptor)。
kotlin
val descriptor = characteristic?.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG_UUID))
descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
bluetoothGatt?.writeDescriptor(descriptor)
3、延迟操作:读取和写入操作可能会被异步处理,确保在操作完成后再进行后续操作。使用 BluetoothGattCallback 来监控操作的结果。
3.2 特征通知延迟或丢失
问题描述:
设备启用了特征通知,但客户端应用接收到的数据有延迟或丢失。
解决方案:
1、检查蓝牙连接稳定性 :不稳定的蓝牙连接可能导致通知丢失或延迟。保持设备与客户端之间的距离适当,并确保没有干扰源。
2、优化 GATT 特征的通知频率 :有些设备在频繁发送通知时会出现延迟或丢失,尝试减少通知频率或增加缓冲时间。
3、使用可靠的通知机制:在某些情况下,可以通过增加 writeCharacteristic 的可靠性(例如启用重试机制)来减少数据丢失。
3.3 设备无法支持高频率通知
问题描述:
某些低功耗蓝牙设备(如传感器)可能无法支持非常频繁的通知,导致连接质量差或丢失。
解决方案:
1、降低通知频率 :对于不支持高频通知的设备,尝试降低通知频率,避免过高的请求频率对设备性能的影响。
2、优化通信协议:使用适当的通信协议来缓解高频率通知带来的负担,如分批发送数据。
总结
蓝牙 GATT 协议在低功耗蓝牙通信 中至关重要。
Android BLE 实现提供了丰富的接口,可以灵活实现扫描、连接、数据交互等功能。
开发过程中需重点关注设备兼容性 、权限 及通信稳定性 。
通过掌握以上内容,你可以轻松实现基于 BLE 的智能设备交互!