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开发------优化
相关推荐
TeleostNaCl16 小时前
如何安装 Google 通用的驱动以便使用 ADB 和 Fastboot 调试(Bootloader)设备
android·经验分享·adb·android studio·android-studio·android runtime
fatiaozhang952717 小时前
中国移动浪潮云电脑CD1000-系统全分区备份包-可瑞芯微工具刷机-可救砖
android·网络·电脑·电视盒子·刷机固件·机顶盒刷机
低调小一17 小时前
Swift 语法学习指南 - 与 Kotlin 对比
微信·kotlin·swift
2501_9159184118 小时前
iOS 开发全流程实战 基于 uni-app 的 iOS 应用开发、打包、测试与上架流程详解
android·ios·小程序·https·uni-app·iphone·webview
lichong95118 小时前
【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之dist打包发布在Android工程asserts里
android·vue.js·iphone
Android出海18 小时前
Android 15重磅升级:16KB内存页机制详解与适配指南
android·人工智能·新媒体运营·产品运营·内容运营
一只修仙的猿18 小时前
毕业三年后,我离职了
android·面试
编程乐学19 小时前
安卓非原创--基于Android Studio 实现的新闻App
android·ide·android studio·移动端开发·安卓大作业·新闻app
雅雅姐20 小时前
Android14 init.rc中on boot阶段操作4
android
fatiaozhang952720 小时前
中国移动中兴云电脑W132D-RK3528-2+32G-刷机固件包(非原机制作)
android·xml·电脑·电视盒子·刷机固件·机顶盒刷机