协议配置常量
ATTConnect 示例工程中与 BLE 通讯协议相关的全部常量定义:包括 GATT 服务/特征 UUID、传输模式、连接与发送超时、Handler 消息码以及十六进制转换工具常量,是理解整个蓝牙数据通路行为的基础。
Purpose and Scope
本页面系统梳理 ATTConnect 工程(ATTConnect/app 模块)中与协议交互相关的配置常量:它们的定义位置、数值含义、设计意图以及如何被上层模块(如 BleManager)消费。
本页面覆盖:
- BLE GATT 服务与特征 UUID 常量(
BLE_UUID_SERVICE/BLE_UUID_WRITE/BLE_UUID_NOTIFICATION等) - GATT 物理传输模式常量(
TRANSPORT_AUTO/TRANSPORT_BREDR/TRANSPORT_LE) - 连接、扫描、发送、回调等超时与延时常量
BleManager内部 Handler 消息码(MSG_*)- 十六进制转换工具常量(
CHexConver/BluetoothUtil) Config单例常量类的职责与使用方式
以下内容属于兄弟页面、不在本页展开:BLE 连接管理流程与状态机(参见「BleManager 连接管理」)、数据发送线程与队列机制(参见「SendBleDataThread 数据发送」)、以及 APP 整体调试日志配置(参见「日志与调试配置」)。
Overview
在 Android BLE 开发中,协议常量是设备通讯的"契约":两端必须使用相同的服务 UUID、特征 UUID 与通知描述符 UUID 才能完成发现、读写与订阅通知。ATTConnect 工程将这些常量集中声明,并进一步把最核心的 UUID 下沉到 com.jieli.bt.att.data.constant.Config 单例对象中,通过 Config.INSTANCE.getBLE_SERVICE_UUID() 这类访问器对外提供。
选择"常量类 + 单例配置"两层结构的设计意图:
- 单一事实来源(Single Source of Truth):
Config集中持有协议 UUID,BleManager在类加载时即从Config.INSTANCE取值为public final static常量,全工程引用同一份定义,避免各模块各自硬编码 UUID 导致不匹配。 - 编译期稳定:
BleManager中的超时值与消息码以final static声明,编译后内联,热路径上零开销。 - 可维护性:时间类常量统一采用"数值 × 单位"的写法(如
8 * 1000),并附带中文注释说明业务语义(如"连接最小时间超时"、"建议搜索 BLE 最小时间"),使调参者一目了然。
Architecture
flowchart TD
subgraph sg_Config["配置层 (data/constant)"]
Config["Config 单例<br/>INSTANCE + getBLE_XXX_UUID()"]
end
subgraph sg_Ble["协议常量层 (tool/ble)"]
Transport["传输模式常量<br/>TRANSPORT_AUTO / BREDR / LE"]
Uuid["BLE UUID 常量<br/>SERVICE / WRITE / NOTIFICATION"]
Timeout["超时与延时常量<br/>SCAN / CONNECT / SEND / CALLBACK"]
Msg["Handler 消息码<br/>MSG_* (0x1010~0x1017)"]
end
subgraph sg_Util["工具常量层 (util)"]
CHex["CHexConver<br/>sHexStr / sHexChars"]
BtUtil["BluetoothUtil<br/>mChars"]
end
subgraph sg_Consumer["消费方"]
BleMgr["BleManager"]
SendThread["SendBleDataThread"]
Other["扫描 / 配对 / MTU 流程"]
end
Config -->|"getBLE_SERVICE_UUID() 等"| Uuid
Uuid --> BleMgr
Transport --> BleMgr
Timeout -->|"驱动 Handler 定时消息"| Msg
Msg --> BleMgr
BleMgr --> SendThread
CHex --> Other
BtUtil --> Other
BleMgr --> Other
架构说明:
- 配置层:
Config单例是 UUID 的最终来源。BleManager通过 importcom.jieli.bt.att.data.constant.Config(见 BleManager.java#L34)访问它,再将其值固化为自身的静态常量(见 BleManager.java#L77-L83)。 - 协议常量层:
BleManager类自身承载了四类协议常量——传输模式、UUID、超时、消息码。它们同处一个类,是因为这些常量服务于同一套 BLE 状态机(扫描 → 连接 → 发现服务 → 读写 → 断开)。 - 工具常量层:
CHexConver与BluetoothUtil提供协议报文常用的十六进制字符表,用于把字节数组与十六进制字符串互转(例如打印/解析协议数据)。 - 消费方:
BleManager既是常量声明者也是主要消费者;SendBleDataThread通过BleManager的发送超时机制完成数据投递。
常量分类详解
BLE GATT 服务与特征 UUID
BleManager 在类加载阶段从 Config 单例取回 BLE UUID 并固化为公开静态常量(BleManager.java#L76-L83):
//BLE服务UUID
public final static UUID BLE_UUID_SERVICE = Config.INSTANCE.getBLE_SERVICE_UUID();
//BLE的写特征UUID
public final static UUID BLE_UUID_WRITE = Config.INSTANCE.getBLE_WRITE_UUID();
//BLE的通知特征UUID
public final static UUID BLE_UUID_NOTIFICATION = Config.INSTANCE.getBLE_NOTIFY_UUID();
//BLE的通知特征的描述符UUID
public final static UUID BLE_UUID_NOTIFICATION_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
Source: BleManager.java#L76-L83
设计要点:
- 前三个 UUID 来自
Config:协议如有调整(例如适配新固件),只需修改Config单例中的配置值,无需改动BleManager业务代码——这是"配置与逻辑分离"的直接体现。 - 通知描述符 UUID 为硬编码标准值:
00002902-0000-1000-8000-00805F9B34FB是蓝牙核心规范定义的 Client Characteristic Configuration Descriptor(CCCD) 标准 UUID,所有 BLE 设备通用,因此无需下沉到Config。用它写入0x0001即可开启通知(Notification)使能。 - 由于是
static final,这些 UUID 在类加载时求值一次,之后不可变,天然线程安全。
GATT 物理传输模式
BleManager 声明了与 Android BluetoothDevice.connectGatt() 的 transport 参数对应的三个常量(BleManager.java#L62-L73):
/**
* No preference of physical transport for GATT connections to remote dual-mode devices
*/
public static final int TRANSPORT_AUTO = 0;
/**
* Constant representing the BR/EDR transport.
*/
public static final int TRANSPORT_BREDR = 1;
/**
* Constant representing the Bluetooth Low Energy (BLE) Transport.
*/
public static final int TRANSPORT_LE = 2;
Source: BleManager.java#L62-L73
设计意图:双模设备(同时支持经典蓝牙 BR/EDR 与 BLE)在建立 GATT 连接时需要显式指定物理传输通道。TRANSPORT_AUTO 交由系统自动选择,TRANSPORT_BREDR 强制走经典蓝牙,TRANSPORT_LE 强制走低功耗蓝牙。这些值直接透传给 Android 平台 API,因此必须与平台定义保持数值一致,不能随意修改。
超时与延时常量
BleManager 集中定义了连接生命周期各阶段的超时/延迟(BleManager.java#L75-L111):
private final static int MIN_CONNECT_TIME = 8 * 1000; //连接最小时间超时
public final static int SEND_DATA_MAX_TIMEOUT = 8000; //8 s
private final static int SCAN_BLE_TIMEOUT = 12 * 1000; //建议搜索BLE最小时间
private final static int CONNECT_BLE_TIMEOUT = 40 * 1000;
private final static int CALLBACK_TIMEOUT = 6000;
private final static int RECONNECT_BLE_DELAY = 2000;
private final static int BOUND_TIMEOUT = 30 * 1000;
Source: BleManager.java#L75-L111
各常量语义如下:
| 常量 | 值 | 语义 |
|---|---|---|
MIN_CONNECT_TIME | 8000 ms | 连接最小时间超时,用于判定连接建立是否过慢 |
SEND_DATA_MAX_TIMEOUT | 8000 ms | 单次发送数据的最大超时(公开常量,供发送线程使用) |
SCAN_BLE_TIMEOUT | 12000 ms | 扫描 BLE 设备的超时(注释建议的最小扫描时长) |
CONNECT_BLE_TIMEOUT | 40000 ms | 建立 GATT 连接的超时 |
CALLBACK_TIMEOUT | 6000 ms | 等待回调返回的超时 |
RECONNECT_BLE_DELAY | 2000 ms | 断线后自动重连的延迟 |
BOUND_TIMEOUT | 30000 ms | 绑定(配对)操作的超时 |
设计意图:BLE 链路本身不可靠(丢包、系统调度延迟),所有异步操作都必须有"超时兜底",否则 Handler 回调永远等不到,界面会卡死。这些超时值按操作类型分级(扫描 12s、连接 40s、发送 8s),在"给系统足够时间"与"及时反馈失败"之间取平衡。注意其中部分常量是 private final static,仅 BleManager 内部可见——这刻意限制了外部对超时的随意篡改,保证状态机行为可预期。
Handler 消息码
BleManager 内部用 Handler 驱动定时任务,每个超时对应一个消息码(BleManager.java#L113-L120):
private final static int MSG_SCAN_BLE_TIMEOUT = 0x1010;
private final static int MSG_CONNECT_BLE_TIMEOUT = 0x1011;
private final static int MSG_SCAN_HID_DEVICE = 0X1012;
private final static int MSG_NOTIFY_BLE_TIMEOUT = 0x1013;
private final static int MSG_CHANGE_BLE_MTU_TIMEOUT = 0x1014;
private final static int MSG_BLE_DISCOVER_SERVICES_CALLBACK_TIMEOUT = 0x1015;
private final static int MSG_DISCONNECT_BLE_TIMEOUT = 0x1016;
private final static int MSG_BOUND_DEVICE_TIMEOUT = 0x1017;
Source: BleManager.java#L113-L120
设计意图:消息码统一使用 0x10xx 段,与业务回调消息区分(避免与其它消息段冲突)。每个消息码与上述超时/延迟常量一一对应:超时计时器到期后 Handler 收到对应 MSG_*,在 handleMessage 中执行超时清理(停止扫描、断开连接、失败回调等)。MSG_SCAN_HID_DEVICE(0x1012)是唯一非超时类消息,用于驱动 HID 设备扫描动作。
十六进制转换工具常量
协议报文调试与解析依赖十六进制互转,两个工具类各自持有字符表常量:
private final static String sHexStr = "0123456789ABCDEF";
private final static char[] sHexChars = sHexStr.toCharArray();
Source: CHexConver.java#L16-L18
private final static char[] mChars = "0123456789ABCDEF".toCharArray();
Source: BluetoothUtil.java#L32-L33
设计意图:字符表 "0123456789ABCDEF" 是十六进制转换的基础映射。CHexConver.sHexStr 以字符串保存后 toCharArray() 生成字符数组,供逐字节转换时索引;BluetoothUtil.mChars 直接以字符数组形式声明。两者等价但服务于不同工具类,避免跨类耦合。
Core Flow
协议常量在真实控制流中的角色如下(以一次典型 BLE 连接与数据发送为例):
sequenceDiagram
participant App as 上层业务
participant BM as BleManager
participant H as Handler(超时)
participant G as GATT 通道
participant T as SendBleDataThread
App->>BM: 开始扫描
BM->>H: postDelayed(MSG_SCAN_BLE_TIMEOUT, SCAN_BLE_TIMEOUT)
H-->>BM: MSG_SCAN_BLE_TIMEOUT(12s) → 停止扫描
App->>BM: 连接设备(TRANSPORT_LE)
BM->>G: connectGatt(transport)
BM->>H: postDelayed(MSG_CONNECT_BLE_TIMEOUT, CONNECT_BLE_TIMEOUT)
G-->>BM: onConnectionStateChange(CONNECTED)
BM->>G: discoverServices()
G-->>BM: 服务发现完成(BLE_UUID_SERVICE 匹配)
App->>BM: 写数据
BM->>T: 入队发送(SEND_DATA_MAX_TIMEOUT=8s)
T->>G: writeCharacteristic(BLE_UUID_WRITE)
G-->>T: onCharacteristicWrite → 出队
T-->>App: 发送成功回调
流程要点:
- 扫描阶段:
BleManager以SCAN_BLE_TIMEOUT(12s)为期限发起扫描,超时消息MSG_SCAN_BLE_TIMEOUT保证扫描必然收敛。 - 连接阶段:
connectGatt使用TRANSPORT_LE指定 BLE 传输;CONNECT_BLE_TIMEOUT(40s)兜底连接异常。 - 服务发现:连接成功后按
BLE_UUID_SERVICE匹配服务,按BLE_UUID_WRITE/BLE_UUID_NOTIFICATION获取读写与通知特征。 - 数据发送:数据进入
SendBleDataThread的阻塞队列,单次发送受SEND_DATA_MAX_TIMEOUT(8s)约束,超时则触发失败清理。 - 通知订阅:向
BLE_UUID_NOTIFICATION_DESCRIPTOR(CCCD)写入使能值后,设备端数据经BLE_UUID_NOTIFICATION通知上来。
Usage Examples
从 Config 单例读取协议 UUID
BleManager 展示了标准的"配置单例 → 静态常量"消费模式。业务代码无需直接触碰 Config,通过 BleManager 的公开常量即可访问协议 UUID:
import com.jieli.bt.att.data.constant.Config;
...
//BLE服务UUID
public final static UUID BLE_UUID_SERVICE = Config.INSTANCE.getBLE_SERVICE_UUID();
//BLE的写特征UUID
public final static UUID BLE_UUID_WRITE = Config.INSTANCE.getBLE_WRITE_UUID();
//BLE的通知特征UUID
public final static UUID BLE_UUID_NOTIFICATION = Config.INSTANCE.getBLE_NOTIFY_UUID();
Source: BleManager.java#L33-L34、BleManager.java#L76-L81
说明:
Config类的内部实现(data/constant包)未在本页文档生成过程中读取,此处仅能依据BleManager的使用方式确认其接口形态:单例对象INSTANCE、访问器getBLE_SERVICE_UUID()/getBLE_WRITE_UUID()/getBLE_NOTIFY_UUID(),返回值类型为java.util.UUID。
使用传输模式常量建立 GATT 连接
TRANSPORT_LE 等常量在调用平台 connectGatt 时作为 transport 参数传入,选择物理传输通道:
public static final int TRANSPORT_AUTO = 0;
public static final int TRANSPORT_BREDR = 1;
public static final int TRANSPORT_LE = 2;
Source: BleManager.java#L65-L73
调用示例(示意,非原文):
// 双模设备上强制走 BLE 通道
device.connectGatt(context, false, callback, TRANSPORT_LE);
这些常量与 Android SDK 中 BluetoothDevice.TRANSPORT_* 的数值保持一致,因此可直接透传;若设备只支持 BLE,使用 TRANSPORT_LE 可跳过经典蓝牙协商、缩短连接时间。
十六进制字符表驱动协议转换
协议数据打印依赖字符表常量,CHexConver 以字符串声明后转字符数组:
private final static String sHexStr = "0123456789ABCDEF";
private final static char[] sHexChars = sHexStr.toCharArray();
Source: CHexConver.java#L16-L18
BluetoothUtil 采用等价但独立的声明:
private final static char[] mChars = "0123456789ABCDEF".toCharArray();
Source: BluetoothUtil.java#L32-L33
典型用法(示意):将字节 0xAB 转为字符串时,hexChars[(value >> 4) & 0x0F] 取高四位、hexChars[value & 0x0F] 取低四位,即可拼出 "AB"。两个工具类各自持有字符表,避免跨类静态依赖,保持工具类独立可复用。
Configuration Options
协议常量本身即"配置项",按可修改性分为三类:
| 常量/配置项 | 类型 | 默认值 | 可见性 | 说明 |
|---|---|---|---|---|
Config.INSTANCE.getBLE_SERVICE_UUID() | UUID | 由 Config 单例提供 | public | BLE 服务 UUID,协议变更时唯一需修改处 |
Config.INSTANCE.getBLE_WRITE_UUID() | UUID | 由 Config 单例提供 | public | 写特征 UUID(下发指令) |
Config.INSTANCE.getBLE_NOTIFY_UUID() | UUID | 由 Config 单例提供 | public | 通知特征 UUID(接收数据) |
BLE_UUID_NOTIFICATION_DESCRIPTOR | UUID | 00002902-0000-1000-8000-00805F9B34FB | public | CCCD 标准描述符,蓝牙规范固定值 |
TRANSPORT_AUTO | int | 0 | public | 自动选择物理传输 |
TRANSPORT_BREDR | int | 1 | public | 强制经典蓝牙传输 |
TRANSPORT_LE | int | 2 | public | 强制 BLE 传输 |
MIN_CONNECT_TIME | int | 8000 ms | private | 连接最小时间超时 |
SEND_DATA_MAX_TIMEOUT | int | 8000 ms | public | 单次发送最大超时 |
SCAN_BLE_TIMEOUT | int | 12000 ms | private | 扫描超时 |
CONNECT_BLE_TIMEOUT | int | 40000 ms | private | 连接超时 |
CALLBACK_TIMEOUT | int | 6000 ms | private | 回调等待超时 |
RECONNECT_BLE_DELAY | int | 2000 ms | private | 重连延迟 |
BOUND_TIMEOUT | int | 30000 ms | private | 配对/绑定超时 |
MSG_SCAN_BLE_TIMEOUT ~ MSG_BOUND_DEVICE_TIMEOUT | int | 0x1010 ~ 0x1017 | private | Handler 消息码,与超时一一对应 |
调参建议:
- 修改协议 UUID 只需改
Config单例,BleManager无需改动(但需注意BLE_UUID_SERVICE等是在类加载时固化的,修改后需重启进程生效)。 - 超时常量多声明为
private final static,如需调整建议直接改源码后重新编译——这符合"常量编译期内联、运行期不可变"的预期。 TRANSPORT_*数值必须与 Android 平台 API 保持一致,禁止自定义数值,否则connectGatt会收到非法参数。
API Reference
协议常量本身为静态字段,此处以"访问器/常量签名"形式给出参考(均来自 BleManager、CHexConver、BluetoothUtil 的实际声明):
BleManager.BLE_UUID_SERVICE : UUID
BLE 服务 UUID,来自 Config.INSTANCE.getBLE_SERVICE_UUID()。
声明位置: BleManager.java#L77
BleManager.BLE_UUID_WRITE : UUID
写特征 UUID,来自 Config.INSTANCE.getBLE_WRITE_UUID()。
声明位置: BleManager.java#L79
BleManager.BLE_UUID_NOTIFICATION : UUID
通知特征 UUID,来自 Config.INSTANCE.getBLE_NOTIFY_UUID()。
声明位置: BleManager.java#L81
BleManager.BLE_UUID_NOTIFICATION_DESCRIPTOR : UUID
通知使能描述符(CCCD)标准 UUID,硬编码为 00002902-0000-1000-8000-00805F9B34FB。
声明位置: BleManager.java#L83
BleManager.TRANSPORT_AUTO | TRANSPORT_BREDR | TRANSPORT_LE : int
GATT 连接物理传输模式:0(自动)、1(BR/EDR)、2(BLE)。需与 Android 平台 BluetoothDevice.TRANSPORT_* 保持一致。
声明位置: BleManager.java#L65-L73
BleManager.SEND_DATA_MAX_TIMEOUT : int
发送数据最大超时,8000 ms。公开常量,供发送线程与外部判断发送是否超时。
声明位置: BleManager.java#L105
CHexConver.sHexStr : String / CHexConver.sHexChars : char[]
十六进制字符表 "0123456789ABCDEF" 及其字符数组形态,供字节↔十六进制字符串互转。
声明位置: CHexConver.java#L17-L18
BluetoothUtil.mChars : char[]
十六进制字符表字符数组形态,等价于 CHexConver.sHexChars,但独立声明以避免工具类间耦合。
声明位置: BluetoothUtil.java#L33
Handler 消息码(private)
| 消息码 | 值 | 触发场景 |
|---|---|---|
MSG_SCAN_BLE_TIMEOUT | 0x1010 | 扫描超时 |
MSG_CONNECT_BLE_TIMEOUT | 0x1011 | 连接超时 |
MSG_SCAN_HID_DEVICE | 0x1012 | 触发 HID 设备扫描(非超时类) |
MSG_NOTIFY_BLE_TIMEOUT | 0x1013 | 通知使能/接收超时 |
MSG_CHANGE_BLE_MTU_TIMEOUT | 0x1014 | MTU 协商超时 |
MSG_BLE_DISCOVER_SERVICES_CALLBACK_TIMEOUT | 0x1015 | 服务发现回调超时 |
MSG_DISCONNECT_BLE_TIMEOUT | 0x1016 | 断开操作超时 |
MSG_BOUND_DEVICE_TIMEOUT | 0x1017 | 绑定设备超时 |
声明位置: BleManager.java#L113-L120
故障模式、边界情况与并发
超时兜底与失败收敛
BLE 的异步回调可能永远不回来(设备断电、系统蓝牙栈异常)。BleManager 为每个异步阶段注册了 postDelayed 的超时消息,handleMessage 收到 MSG_* 后执行清理(停止扫描、断开 GATT、回调失败)。若超时常量被误改为过小值(如连接超时 < 扫描时间),会出现"正常流程被超时打断"的假失败;若过大,则用户等待时间不可接受。这是调参时的首要权衡点。
静态常量的线程安全
所有常量均为 final static,类加载阶段完成初始化(Config.INSTANCE.getXXX() 在静态初始化时调用一次),之后不可变。多线程并发读写这些常量天然安全,无需同步。风险点:BLE_UUID_SERVICE 等在类加载时固化,若运行期修改 Config 中的配置值,已加载的 BleManager 常量不会更新——必须重启进程。
TRANSPORT_* 的平台一致性约束
TRANSPORT_BREDR=1、TRANSPORT_LE=2 与 Android SDK 定义一致。若有人"优化"常量(例如将 TRANSPORT_LE 改为 3),connectGatt 将抛出 IllegalArgumentException 或产生未定义行为。这组常量属于平台契约而非业务可调项。
十六进制转换的边界
CHexConver 与 BluetoothUtil 的字符表只覆盖大写十六进制(A-F)。若协议报文含小写十六进制字符串(a-f),转换前需自行归一化;"0123456789ABCDEF" 表长度为 16,索引越界(值 > 15)会抛 ArrayIndexOutOfBoundsException,调用方必须保证入参是合法字节。
性能与运维注意
- 零运行时开销:
final static常量在编译期内联,热路径(如发送超时判断)无方法调用开销;UUID 在类加载时仅构造一次。 - 内存:常量类为极少量静态字段,无内存压力;
Config单例应保持轻量,避免在 getter 中做 I/O 或解析。 - 调试:超时消息码段
0x10xx与业务消息分段隔离,日志中可通过消息码快速定位处于哪个阶段(扫描/连接/发送/MTU/绑定)超时。 - 修改后验证:调整任何超时常量后,建议覆盖"正常流程不受影响"的回归用例(连接、发送、重连各一次),防止把兜底超时改成流程瓶颈。
扩展点
- 更换协议 UUID:修改
Config单例(data/constant/Config.java)中的getBLE_SERVICE_UUID()/getBLE_WRITE_UUID()/getBLE_NOTIFY_UUID()返回值即可,BleManager及下游全部自动生效——这是本工程刻意设计的唯一"协议配置入口"。 - 新增超时阶段:在
BleManager中按现有模式扩展——新增XXX_TIMEOUT常量 → 新增MSG_XXX_TIMEOUT消息码(0x1018起)→postDelayed注册 →handleMessage清理。消息码须与现有0x10xx段保持不冲突。 - 复用工具常量:
CHexConver/BluetoothUtil的字符表为包内(或类内)可见,其他模块如需十六进制转换,应复用这两个工具类的方法,而不是复制字符表。
Related Links
- BleManager.java(协议常量主声明处)
- Config.java(UUID 配置单例,
data/constant包) - SendBleDataThread.java(消费
SEND_DATA_MAX_TIMEOUT的发送线程) - CHexConver.java(十六进制转换工具)
- BluetoothUtil.java(蓝牙工具类)
- 相关目录页:BleManager 连接管理、SendBleDataThread 数据发送、日志与调试配置