Appearance
ble-gatt-playground
1. 实验目标与工程要点
这个 Android host 实验不依赖真实 BLE 外设,而是用可稳定运行的状态机面板把 BLE 最容易出事故的链路显式化:
- Android 12+ 权限申请分支怎么收口
- 扫描 → 连接 → 服务发现 → MTU → Notification 的时序如何组织
- 为什么 GATT 操作必须进串行队列
disconnect()和close()为什么要分开处理status=133、通知收不到、断线重连时第一步该查什么
它真正验证的不是“我的电脑现在有没有蓝牙外设”,而是:你是否已经把 BLE 的核心状态机与排障心智建模清楚。
2. 深入原理与生活浅显比喻
2.1 生活浅显比喻
把 BLE 想成“门禁访客系统”:
- 扫描像门口保安认人:先看有没有这类访客。
- 连接像把访客带进大堂:只说明人进来了,还没开始办业务。
- 服务发现像确认他能去哪些楼层。
- Characteristic 读写像递交表单、拿回执。
- Notification像访客后续主动给前台发消息。
- GATT 队列像“一次只让一个人办一项业务”,否则窗口会乱。
所以 BLE 最容易踩的坑,不是“门有没有打开”,而是“同一时间窗口里塞了太多人办不同手续”。
2.2 底层原理分析
BLE 工程通常分两层:
- GAP:广播、扫描、过滤、建立连接。
- GATT:服务发现、特征读写、Descriptor、通知订阅。
Android BLE 栈的大坑是:同一时间往往只允许一个 GATT 操作在途。因此真实业务里至少要有:
- 操作队列
- 回调推进
- 超时与失败收口
- 断线后的资源释放和重连策略
本实验页面把这些阶段做成日志化状态机,而不是直接绑死在真实硬件回调上。这样即使没有外设,也能复习“正确链路长什么样”。
2.3 方案对比矩阵
| 方案 | 通俗比喻 | 底层原理 | 保证特性 | 吞吐性能 | 运行开销 | 适用场景 |
|---|---|---|---|---|---|---|
| 按按钮直接调 GATT | 看见窗口空着就随手塞业务 | 不建队列,回调里临时串逻辑 | 开发快,但状态不可控 | 高(看起来) | 低 | Demo、一次性验证 |
| 状态机 + 串行队列 | 窗口一次只办一件事,办完再叫下一个 | 明确阶段、回调推进、失败收口 | 顺序稳定、排障清晰 | 中 | 中 | 真正上线的 BLE 控制链路 |
| 完整设备协议层 | 前台 + 后台 + 财务联动的整套业务系统 | 在状态机外再叠协议编码/ACK/重试/分包 | 稳定性最高 | 中 | 高 | 量产设备、固件升级、复杂指令集 |
「吞吐性能」和「运行开销」分开看:不建队列表面上最轻,实际上最容易把问题转移成线上失败与难排障成本。
3. Android / 移动端实战场景与误配事故
3.1 实战场景
本实验模拟的最小稳定链路:
- 先检查 Android 12+ 的扫描/连接权限
- 点击“开始扫描”后进入发现设备阶段
- 选中设备后进入连接与服务发现阶段
- 连接建立后演示 MTU、Notification、写命令的典型顺序
- 支持模拟
status=133、通知未开启、断线重连三类常见故障
3.2 常见误配与事故注意事项
- 并发发 GATT 操作:最典型,直接导致
false/133/ 回调错乱。 - 只
disconnect不close:旧句柄残留,重连越来越不稳定。 - 只开本地 notification,不写 CCCD:页面显示“已订阅”,设备侧却不推送。
- 盲目无限重连:耗电高、系统限制命中,用户看到的是“App 一直转圈”。
3.3 排障思路
先不要急着怀疑外设,先问这四件事:
- 当前卡在扫描、连接、服务发现、订阅,还是写命令?
- 是否真的按“一个操作完成后再发下一个”推进?
- 断线后是否执行了
close()并清空旧状态? - 当前问题是“真实硬件不可达”,还是“本地状态机就已经写错”?
4. 实验源码与运行验证
关键源码
关键参数 / 开关
grantPermissions:模拟 Android 12+ 扫描/连接权限是否已授权。simulateStatus133:模拟连接后收到status=133,观察是否进入 close + 退避重连。simulateNotificationFailure:模拟只开本地监听、不完成远端订阅的失败分支。operationQueue:模拟 GATT 操作串行队列,用于观察 MTU / Notification / Write 的推进顺序。
运行方式
bash
cd labs/android/host
./gradlew :app:installDebug
adb shell am start -n com.shayn.engineeringreviewlab.androidhost/.MainActivity启动后进入 打开 BLE / GATT 最小状态机实验室。
预期控制台运行输出
text
[idle] 等待开始 BLE 实验
[checkingPermissions] 校验 Android 12+ 蓝牙权限
[scanning] 已开始扫描,等待发现目标设备
[connecting] 已发现设备,开始 connectGatt
[discoveringServices] 连接建立,准备 discoverServices
[requestingMtu] 申请更大的 MTU,准备传输长指令
[enablingNotification] 写 CCCD,准备接收设备主动通知
[ready] BLE 最小链路已就绪,可安全发送业务命令切换故障开关后可看到:
- 权限关闭 → 直接 failed
status=133→ failed + 给出 close / 重连建议- Notification 失败 → failed + 指向 CCCD 检查
- 手动断开 → disconnected + 指数退避重连建议
5. 对应知识库文档
- 理论主文档:01. 蓝牙与 BLE 硬件交互
这份 README 负责承载 Android host 的真实入口、运行方式与故障分支;BLE 概念、Android / Flutter 对照、误配解释请回主文档看。