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开发------优化
相关推荐
顾林海17 分钟前
Flutter Dart 运算符全面解析
android·前端
小白马丶19 分钟前
Jetpack源码解读(一)——Lifecycle
android·android jetpack
&有梦想的咸鱼&36 分钟前
Android Glide 请求构建与管理模块原理深入剖析
android·glide
苏苏码不动了38 分钟前
Android MVC、MVP、MVVM三种架构的介绍和使用。
android·架构·mvc
万里鹏程转瞬至1 小时前
开源项目介绍:Native-LLM-for-Android
android·深度学习·开源·大模型
QING6183 小时前
Android_BLE 基于Jetpack Bluetooth实现文件传输指南。
android·kotlin·app
_一条咸鱼_4 小时前
Android Glide 的显示与回调模块原理分析
android
_一条咸鱼_4 小时前
Android Glide 图片解码与转换模块原理分析
android
QING6184 小时前
Android_BLE开发——扫描
android·kotlin·app
QING6184 小时前
Android_BLE开发——绑定
android·kotlin·app