Android_BLE开发——连接

本文结合 BLE 开发核心原理与实战经验,深入剖析 Android 蓝牙连接的实现细节,涵盖连接管理、连接超时控制、自动重连机制,助你打造简洁高效的实现方案。

一、连接核心流程架构

1.1、 连接状态机(示例代码)

kotlin 复制代码
sealed class ConnectionState {
    object Disconnected : ConnectionState()
    data class Connecting(val device: BluetoothDevice) : ConnectionState()
    data class Connected(val gatt: BluetoothGatt) : ConnectionState()
    data class ServicesDiscovered(val services: List<BluetoothGattService>) : ConnectionState()
    data class Error(val message: String) : ConnectionState()
}

1.2、连接管理器基础实现(示例代码)

kotlin 复制代码
class BleConnector(
    private val context: Context,
    private val scope: CoroutineScope
) {
    private var bluetoothGatt: BluetoothGatt? = null
    
    // 使用 Channel 管理连接事件
    private val connectionEventChannel = Channel<ConnectionState>()
    val connectionEvents = connectionEventChannel.receiveAsFlow()

    // 设备连接入口
    fun connect(device: BluetoothDevice) = scope.launch {
        connectionEventChannel.send(ConnectionState.Connecting(device))
        
        bluetoothGatt = device.connectGatt(
            context, 
            false, 
            object : BluetoothGattCallback() {
                override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
                    when (newState) {
                        BluetoothProfile.STATE_CONNECTED -> {
                            connectionEventChannel.trySend(ConnectionState.Connected(gatt))
                            gatt.discoverServices()
                        }
                        BluetoothProfile.STATE_DISCONNECTED -> {
                            connectionEventChannel.trySend(ConnectionState.Error("连接断开"))
                            close()
                        }
                    }
                }

                override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
                    gatt.services?.let { 
                        connectionEventChannel.trySend(ConnectionState.ServicesDiscovered(it))
                    }
                }
            }
        )
    }

    fun close() {
        bluetoothGatt?.disconnect()
        bluetoothGatt?.close()
        connectionEventChannel.close()
    }
}

二、连接优化策略

2.1、连接超时控制(示例代码)

kotlin 复制代码
private suspend fun connectWithTimeout(device: BluetoothDevice, timeout: Long) {
    try {
        withTimeout(timeout) {
            connect(device)
            // 等待连接完成
            connectionEvents.first { 
                it is ConnectionState.Connected || it is ConnectionState.Error 
            }
        }
    } catch (e: TimeoutCancellationException) {
        connectionEventChannel.send(ConnectionState.Error("连接超时"))
        close()
    }
}

2.2、自动重连机制(示例代码)

kotlin 复制代码
class AutoReconnect(
    private val connector: BleConnector,
    private val maxRetries: Int = 3
) {
    private var retryCount = 0

    fun enable() {
        connector.connectionEvents.onEach { state ->
            when (state) {
                is ConnectionState.Error -> {
                    if (retryCount < maxRetries) {
                        delay(2000)
                        connector.connect(state.device)
                        retryCount++
                    }
                }
                is ConnectionState.Connected -> retryCount = 0
                else -> Unit
            }
        }.launchIn(connector.scope)
    }
}

三、GATT 操作封装

3.1、特征值读写扩展函数(示例代码)

kotlin 复制代码
// 安全写入特征值
suspend fun BluetoothGatt.safeWriteCharacteristic(
    characteristic: BluetoothGattCharacteristic,
    data: ByteArray
): Boolean = suspendCancellableCoroutine { continuation ->
    characteristic.value = data
    writeCharacteristic(characteristic)
    
    val callback = object : BluetoothGattCallback() {
        override fun onCharacteristicWrite(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            status: Int
        ) {
            continuation.resume(status == BluetoothGatt.GATT_SUCCESS) {}
        }
    }
    
    continuation.invokeOnCancellation { 
        close() 
    }
}

3.2、通知订阅管理(示例代码)

kotlin 复制代码
fun BluetoothGatt.enableNotifications(
    characteristic: BluetoothGattCharacteristic
): Flow<ByteArray> = callbackFlow {
    val cccdUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    
    // 启用通知
    setCharacteristicNotification(characteristic, true)
    
    // 配置 CCCD
    characteristic.getDescriptor(cccdUuid)?.let { descriptor ->
        descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
        writeDescriptor(descriptor)
    }

    // 监听数据变化
    val callback = object : BluetoothGattCallback() {
        override fun onCharacteristicChanged(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic
        ) {
            trySend(characteristic.value)
        }
    }
    
    awaitClose { 
        setCharacteristicNotification(characteristic, false)
        close()
    }
}

四、实战问题和解决方案

4.1、MTU 协商优化(示例代码)

kotlin 复制代码
private const val DEFAULT_MTU = 23
private const val MAX_MTU = 512

suspend fun BluetoothGatt.negotiateMtu(): Int = suspendCoroutine { continuation ->
    requestMtu(MAX_MTU)
    
    val callback = object : BluetoothGattCallback() {
        override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
            continuation.resume(mtu)
        }
    }
}

4.2、大数据分包处理(示例代码)

kotlin 复制代码
suspend fun BluetoothGatt.writeLargeData(
    characteristic: BluetoothGattCharacteristic,
    data: ByteArray,
    chunkSize: Int = 512
) {
    data.toList().chunked(chunkSize).forEachIndexed { index, chunk ->
        val chunkData = chunk.toByteArray()
        val isLastChunk = index == data.size / chunkSize
        
        // 添加分包标识
        val packet = if (isLastChunk) {
            chunkData + 0x00.toByte()
        } else {
            chunkData + 0x01.toByte()
        }
        
        safeWriteCharacteristic(characteristic, packet)
    }
}

五、最佳实践建议

5.1、生命周期绑定(示例代码)

kotlin 复制代码
class BleConnectionFragment : Fragment() {
    private val connector by lazy { 
        BleConnector(requireContext(), lifecycleScope) 
    }

    override fun onStart() {
        connector.connectionEvents
            .onEach { updateUi(it) }
            .launchIn(lifecycleScope)
    }

    override fun onStop() {
        connector.close()
    }
}

5.2、连接参数优化(示例代码)

kotlin 复制代码
fun optimizeConnectionParameters(gatt: BluetoothGatt) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH)
        gatt.requestMtu(512)
    }
}

5.3、错误统一处理(示例代码)

kotlin 复制代码
private fun handleGattError(status: Int): String = when (status) {
    BluetoothGatt.GATT_SUCCESS -> "操作成功"
    BluetoothGatt.GATT_READ_NOT_PERMITTED -> "无读取权限"
    BluetoothGatt.GATT_WRITE_NOT_PERMITTED -> "无写入权限"
    BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION -> "认证失败"
    else -> "未知错误 (code: $status)"
}

六、调试与监控

6.1、连接状态监控

kotlin 复制代码
fun monitorConnectionQuality() {
    scope.launch {
        while (true) {
            bluetoothGatt?.readRemoteRssi()
            delay(5000)
        }
    }
}

override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
    Log.d("BLE", "当前信号强度: $rssi dBm")
}

6.2、使用调试工具

推荐工具:

  • nRF Connect:可视化查看 GATT 层级
  • Wireshark:抓包分析协议交互
  • Android Bluetooth HCI Log:查看底层日志

七、开发过程中需要注意的点

  • 开发的过程中要尽量避免133错误。

  • 如果连接调用只是挂起,没有发生超时onConnectionStateChange 回调也从未调用过。可能是外围设备快没电了或者是超出设备的可操作范围。

  • 确保在连接之前停止扫描。

  • 所有与连接和断开连接的相关调用都是 异步 的。蓝牙栈执行它们需要一些时间。避免在极短的时间做出大量BLE的相关操作。

建议结合 Android BLE KTX 官方扩展库进一步简化开发流程。

更多分享

  1. Android_BLE开发------初识BLE
  2. Android_BLE开发------扫描
  3. Android_BLE开发------读写
  4. Android_BLE开发------绑定
  5. Android_BLE开发------优化
相关推荐
androidwork2 小时前
Kotlin与Android Studio开发环境配置指南
开发语言·kotlin·android studio
stevenzqzq2 小时前
kotlin 01flow-StateFlow 完整教程
android·开发语言·kotlin·flow
androidwork2 小时前
使用Kotlin Flow实现Android应用的响应式编程
android·开发语言·kotlin
stevenzqzq2 小时前
kotlin 数据类
android·开发语言·kotlin
每次的天空2 小时前
Android单例模式知识总结
android·单例模式
追随远方3 小时前
Android平台FFmpeg视频解码全流程指南
android·ffmpeg·音视频
姜行运4 小时前
数据结构【二叉搜索树(BST)】
android·数据结构·c++·c#
JhonKI12 小时前
【MySQL】存储引擎 - CSV详解
android·数据库·mysql
开开心心_Every12 小时前
手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复
android·windows·python·搜索引擎·智能手机·pdf·音视频
大G哥13 小时前
Kotlin Lambda语法错误修复
android·java·开发语言·kotlin