4. 解析蓝牙设备广播数据并获取设备信息

4.1 原理概述

低功耗蓝牙(BLE)与经典蓝牙在设备发现阶段都会通过系统广播发送 BluetoothDevice.ACTION_FOUND 事件。应用通过注册 BroadcastReceiver 接收该广播,从 Intent 的 EXTRA_DEVICE 中取出 BluetoothDevice 对象,再调用其 API 获取名称和 MAC 地址。RSSI(信号强度)可通过 EXTRA_RSSI 获取,辅助判断距离。

4.2 实现流程

步骤操作关键 API / 字段
1注册 ReceiverIntentFilter(BluetoothDevice.ACTION_FOUND)
2重写 onReceive()intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
3获取设备名称device.name ?: “未知设备”
4获取 MAC 地址device.address
5获取 RSSIintent.getShortExtra(BluetoothDevice.EXTRA_RSSI, 0.toShort())
6封装数据对象自定义 BluetoothDeviceInfo 数据类

4.3 核心代码实现

4.3.1 数据模型

data class BluetoothDeviceInfo(
    val name: String,
    val address: String,
    val rssi: Int
)

4.3.2 BroadcastReceiver 完整实现

class BluetoothFoundReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        if (action != BluetoothDevice.ACTION_FOUND) return

        val device: BluetoothDevice? =
            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)

        val rssi = intent.getShortExtra(
            BluetoothDevice.EXTRA_RSSI, 0.toShort()
        ).toInt()

        device?.let {
            val name = it.name ?: "未知设备"
            val address = it.address
            val info = BluetoothDeviceInfo(name, address, rssi)

            // 回调或存入集合,供 UI 更新
            onDeviceFound?.invoke(info)
        }
    }

    // 回调函数,在 Activity / Fragment 中赋值
    var onDeviceFound: ((BluetoothDeviceInfo) -> Unit)? = null
}

4.3.3 注册与反注册(推荐在 onResume / onPause 中执行)

private val receiver = BluetoothFoundReceiver()
private val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)

// 注册
registerReceiver(receiver, filter)

// 反注册
unregisterReceiver(receiver)

4.4 调试技巧

  • 在 onReceive 中添加日志,输出设备名称和地址:Log.d(“BT_DEBUG”, “Found: $name, $address”)
  • 使用 adb shell dumpsys bluetooth_manager 查看系统蓝牙状态
  • 模拟器不支持蓝牙发现,请在真机上测试
  • Android 12+ 需动态请求 BLUETOOTH_SCAN 权限,否则广播可能被拦截

4.5 常见错误与解决方案

错误现象可能原因解决
onReceive 不被触发未注册 Receiver 或 IntentFilter 错误检查 BluetoothDevice.ACTION_FOUND 字符串拼写
device 为 nullIntent 未包含 EXTRA_DEVICE检查系统版本限制:Android 12+ 需 BLUETOOTH_SCAN 权限
应用闪退在主线程做耗时操作Receiver 运行在主线程,只做简单封装,通过 Handler / LiveData 更新 UI
获取名称始终为“未知设备”BLE 设备有时不广播名称使用 scanRecord 解析本地名称,或依赖 GAP 数据

4.6 性能与稳定性优化

  • 避免阻塞:onReceive 在主线程执行,不要做网络请求、数据库写入或复杂计算;只做数据封装和轻量回调。
  • 使用集合去重:相同 MAC 的设备多次出现时,用 HashSet 或 ConcurrentHashMap 过滤重复。
  • 及时注销:Activity/Fragment 销毁后未取消注册会导致内存泄漏,务必在 onPause 或 onDestroy 中 unregisterReceiver。
  • RSSI 平滑:若需要信号强度稳定性,可对多次 RSSI 求滑动平均,避免单次抖动。

4.7 广播数据解析流程

下图展示了从系统蓝牙广播到数据对象封装的完整路径:

蓝牙设备发现数据流 系统蓝牙发现广播 ACTION_FOUND 被触发 onReceive 解析 Intent getParcelableExtra → BluetoothDevice device.name / device.address / EXTRA_RSSI 封装为 BluetoothDeviceInfo 对象 注意 主线程运行, 勿做耗时操作

4.8 封装后的数据使用建议