本文结合 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 官方扩展库进一步简化开发流程。