从事Android蓝牙开发多年,最让人头疼的就是BLE连接稳定性问题。很多开发者习惯把BluetoothGatt.connectGatt()当作普通API调用,结果在实际项目中频繁遭遇连接失败、操作丢失、回调不触发等问题。今天我将分享一个经过生产环境验证的BLE稳定连接架构,这个方案已经在我们多个智能硬件项目中稳定运行3年以上。
传统BLE开发存在三大致命缺陷:
我们的连接管理器包含五大核心模块:
kotlin复制class BleManager {
// 状态管理
private val stateMachine = ConnectionStateMachine()
// 操作队列(核心)
private val operationQueue = OperationQueue()
// 重连策略
private val retryPolicy = ExponentialBackoffRetry()
// 设备会话
private var deviceSession: DeviceSession? = null
// GATT回调
private val gattCallback = SafeGattCallback()
}
BLE连接本质上是状态流转过程,我们使用密封类定义7种核心状态:
kotlin复制sealed class BleState {
object Disconnected : BleState()
object Scanning : BleState()
object Connecting : BleState()
object Connected : BleState()
object DiscoveringServices : BleState()
object Configuring : BleState() // MTU/Notification等配置
object Ready : BleState()
data class Error(val code: Int) : BleState()
}
状态转换规则必须遵循:
关键经验:在
onConnectionStateChange回调中必须立即更新状态机,避免后续操作基于错误状态执行
Android BLE协议栈存在这些限制:
我们的解决方案:
kotlin复制class SerialOperationQueue {
private val channel = Channel<BleOperation>(capacity = Channel.UNLIMITED)
init {
CoroutineScope(Dispatchers.IO).launch {
for (op in channel) {
try {
op.execute()
} catch (e: Exception) {
logError("Operation failed", e)
}
}
}
}
fun enqueue(op: BleOperation) {
channel.trySend(op)
}
}
以特征值写入为例:
kotlin复制class WriteOperation(
private val characteristic: BluetoothGattCharacteristic,
private val data: ByteArray
) : BleOperation {
override suspend fun execute(gatt: BluetoothGatt): Boolean {
return suspendCancellableCoroutine { cont ->
characteristic.value = data
gatt.writeCharacteristic(characteristic)
// 注册结果回调
gattCallback.setOnWriteCompleteListener { success ->
cont.resume(success)
}
// 设置超时
cont.invokeOnCancellation {
gattCallback.removeWriteListener()
}
}
}
}
kotlin复制class ExponentialBackoffRetry(
private val maxRetries: Int = 5,
private val baseDelay: Long = 1000
) {
private var attempt = 0
fun scheduleRetry(block: () -> Unit): Boolean {
if (attempt >= maxRetries) return false
val delay = minOf(baseDelay * (1L shl attempt), 30000)
attempt++
CoroutineScope(Dispatchers.IO).launch {
delay(delay)
block()
}
return true
}
fun reset() { attempt = 0 }
}
默认MTU 23字节效率极低,建议连接后立即协商:
kotlin复制fun negotiateMtu(gatt: BluetoothGatt, size: Int = 247) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
operationQueue.enqueue {
val success = suspendCancellableCoroutine<Boolean> { cont ->
gattCallback.setOnMtuChangedListener { mtu, status ->
cont.resume(status == BluetoothGatt.GATT_SUCCESS)
}
gatt.requestMtu(size)
}
if (!success) throw IOException("MTU negotiation failed")
}
}
}
| 错误码 | 原因 | 处理方案 |
|---|---|---|
| 133 | 协议栈过载 | 降低操作频率 |
| 257 | 特征值不支持 | 检查属性配置 |
| 8 | 超时 | 增加等待时间 |
必须遵循的释放顺序:
kotlin复制fun release() {
operationQueue.cancelAll()
bluetoothGatt?.disconnect()
bluetoothGatt?.close()
bluetoothGatt = null
stateMachine.reset()
}
生产环境必备的日志格式:
kotlin复制private fun logEvent(event: String, data: Map<String, Any?> = emptyMap()) {
val logEntry = buildString {
append("[${System.currentTimeMillis()}]")
append(" [BLE] $event")
data.forEach { (k, v) ->
append(" $k=$v")
}
}
Log.d("BLE", logEntry)
writeToFile(logEntry) // 持久化存储
}
典型日志示例:
code复制[1625097600000] [BLE] state_changed from=Disconnected to=Connecting
[1625097600100] [BLE] gatt_callback type=connection_state status=0
[1625097600200] [BLE] operation_started type=write_char uuid=00002a00-0000-1000-8000-00805f9b34fb
初始化阶段
设备发现
连接建立
服务配置
运行维护
kotlin复制if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
gatt.requestConnectionPriority(
BluetoothGatt.CONNECTION_PRIORITY_HIGH
)
}
kotlin复制fun batchWrite(characteristic: BluetoothGattCharacteristic, packets: List<ByteArray>) {
operationQueue.enqueue {
packets.forEach { data ->
characteristic.value = data
if (!gatt.writeCharacteristic(characteristic)) {
throw IOException("Write failed")
}
delay(15) // 协议栈冷却时间
}
}
}
kotlin复制private fun startHeartbeat() {
CoroutineScope(Dispatchers.IO).launch {
while (isConnected()) {
pingDevice()
delay(30000) // 30秒心跳间隔
}
}
}
| API Level | 差异点 | 兼容方案 |
|---|---|---|
| <21 | 无自动连接 | 手动实现重连 |
| <23 | 无扫描过滤 | 软件层过滤 |
| <26 | 无连接参数 | 使用默认值 |
| >=29 | 位置权限 | 动态请求 |
特别提醒:Android 12+需要新增BLUETOOTH_SCAN权限
在我们的智能家居项目中:
关键优化手段:
这套架构最核心的价值在于:把脆弱的BLE连接变成了可靠的通信管道。在实际项目中,稳定性的提升直接带来了用户投诉率下降90%的效果。