27、低功耗蓝牙(BLE)开发:BLE基础、扫描优化、连接参数、广播策略

各位同学,今天我们来聊聊低功耗蓝牙(BLE)开发。说实话,BLE 在 Android 开发里是个挺有意思的模块——它不像 WiFi 那样大功率传输,也不像 NFC 那样只能贴一下。BLE 的核心就是「低功耗」三个字,但很多新手一上来就踩坑。

我个人习惯把 BLE 开发分成四个模块:基础概念、扫描优化、连接参数、广播策略。咱们一个一个来拆解。

27.1 BLE 基础:你得先知道它怎么工作的

BLE 和经典蓝牙最大的区别是什么?说白了,经典蓝牙是「一直在线」,而 BLE 是「睡一会,醒一下」。它大部分时间都在休眠,只有需要传输数据时才短暂唤醒。这就是它省电的秘密。

在 Android 上做 BLE 开发,核心 API 就几个:BluetoothAdapterBluetoothLeScannerBluetoothGatt。嗯,这里要注意:从 Android 6.0 开始,扫描 BLE 设备需要位置权限;从 Android 12 开始,还需要 BLUETOOTH_SCANBLUETOOTH_CONNECT 这两个运行时权限。

⚠️ 权限坑: 我曾经在项目里遇到过,明明加了权限,但扫描就是没结果。后来发现是 Android 12 的权限模型变了,BLUETOOTH_ADMIN 不再覆盖扫描权限。必须单独申请 BLUETOOTH_SCAN

BLE 通信模型是「中心设备 - 外围设备」模式。手机通常是中心设备,智能手环、传感器是外围设备。外围设备通过广播包告诉别人「我在这里」,中心设备扫描到后发起连接。

27.2 扫描优化:别让你的手机变成电老虎

很多同学写 BLE 扫描,上来就是一个 while(true) 循环。你想想看,手机一直在扫描,电量哗哗地掉。我建议的做法是:按需扫描,扫到就停

扫描参数优化主要看三个东西:

参数 说明 我常用的值
扫描间隔 两次扫描之间的间隔时间 100ms(快速发现) / 1000ms(省电模式)
扫描窗口 每次扫描持续的时间 50ms(窗口越短越省电)
扫描模式 低功耗、平衡、低延迟 低延迟用于连接前,低功耗用于后台

举个例子,如果你在做门锁应用,用户靠近时自动解锁。这时候扫描间隔可以设短一点,比如 50ms,让手机快速发现门锁。但如果是后台温度传感器,一小时上报一次数据,那扫描间隔拉到 5 秒都行。

💡 我的小技巧: 使用 ScanFilter 过滤掉不需要的设备。比如只扫描特定 Service UUID 的设备,这样能大幅减少回调次数,省电又省 CPU。

27.3 连接参数:调好了体验飞起,调不好疯狂断连

连接参数是 BLE 开发里最容易忽略但又最关键的部分。它决定了手机和外围设备之间怎么「对话」。核心参数有四个:

  • 连接间隔(Connection Interval):设备之间多久交换一次数据。范围 7.5ms ~ 4s。
  • 延迟(Slave Latency):外围设备可以跳过多少次连接事件。比如设成 3,表示可以连续跳过 3 次不回复。
  • 超时(Supervision Timeout):超过这个时间没收到数据,就认为连接断了。
  • MTU 大小:一次能传多少字节。默认 23 字节,可以协商到 512 字节。

我记得有一次做运动手环项目,用户反馈说「手机放口袋就走几步路,手环就断连了」。查了半天,发现是连接间隔设成了 100ms,但手机在口袋里信号不好,丢包率一高就超时了。后来我把连接间隔调到 30ms,超时时间从 5 秒调到 10 秒,问题就解决了。

连接参数不是随便设的。Android 系统会检查你请求的参数是否合理。比如连接间隔不能小于 7.5ms,超时时间必须大于连接间隔的 4 倍。如果参数不合理,系统会拒绝,使用默认值。

🔑 核心原则: 需要低延迟(如实时控制)→ 短连接间隔;需要省电(如传感器)→ 长连接间隔 + 高延迟。

27.4 广播策略:让设备被正确发现

外围设备通过广播包告诉手机「我在这里,我能做什么」。广播包分两种:

  • 广播包(Advertising Data):31 字节,必须包含,用于快速发现。
  • 扫描响应包(Scan Response Data):31 字节,可选,手机主动请求后返回。

广播策略的核心是:在 31 字节里塞最重要的信息。比如设备名称、Service UUID、Tx Power Level。别把完整的数据都塞进去,你想想看,31 字节能塞多少东西?

我建议的做法是:广播包里只放 Service UUID 和少量标识信息,完整的设备名称和额外数据放到扫描响应包里。这样手机扫描时,先通过 UUID 过滤,再请求扫描响应获取详细信息。

广播间隔也很重要。间隔越短,设备被发现得越快,但越耗电。我一般这样设:

  • 设备待连接时:广播间隔 100ms(快速被发现)
  • 设备已连接时:停止广播(省电)
  • 设备在后台:广播间隔 1000ms(省电模式)
⚠️ 广播功率: 我曾经在项目里把广播功率调到最大,结果设备 3 小时就没电了。后来发现,广播功率每增加 3dBm,功耗翻倍。除非你需要超远距离发现(比如 50 米以上),否则用默认功率就行。

27.5 知识体系总览

下面这张图是我自己整理的 BLE 开发知识体系,你可以把它当作一个检查清单:

BLE 开发核心模块 BLE 基础 权限、API、模型 扫描优化 间隔、窗口、过滤 连接参数 间隔、延迟、超时 广播策略 数据、间隔、功率 • 中心/外围模型 • GATT 协议 • Service/Characteristic • 权限管理 • ScanFilter 使用 • 扫描间隔调优 • 回调频率控制 • 后台扫描策略 • Connection Interval • Slave Latency • Supervision Timeout • MTU 协商 • 广播包 vs 扫描响应 • 广播间隔设置 • 广播功率控制 • 定向广播 核心目标:在省电和性能之间找到平衡点 没有万能参数,只有针对场景的调优

27.6 避坑指南:我踩过的那些坑

最后分享几个我实际项目中遇到的坑,希望能帮你少走弯路:

  • 扫描回调不触发:检查一下是不是忘了在 Android 12+ 上申请 BLUETOOTH_SCAN 权限。我曾经因为这个排查了整整一天。
  • 连接后频繁断连:先看连接参数是否合理。我遇到过外围设备只支持 30ms 以上的连接间隔,但手机请求了 20ms,结果系统直接拒绝。
  • 广播包发不出去:检查广播包是否超过 31 字节。很多新手把设备名称、所有 Service UUID、厂商数据全塞进去,超了还不知道。
  • MTU 协商失败:不是所有设备都支持 512 字节 MTU。我建议先请求 512,如果失败再回退到 128 或 64。

好了,关于 BLE 开发的基础内容就讲到这里。记住一句话:BLE 开发没有银弹,每个参数都要根据你的实际场景去调。多测试、多踩坑,慢慢就有感觉了。


公众号:蓝海资料掘金营,微信deep3321