杰理 SDK 文档中心
首页
首页
  • 项目概览

    • 仓库简介与示例构成
    • 支持的平台与协议
  • 快速开始

    • 导入工程与编译运行
    • 蓝牙权限配置
  • 应用架构

    • 工程结构与模块分层
    • 核心类与回调接口
  • 核心功能

    • 蓝牙设备扫描
    • ATT 设备连接与断开管理
    • 数据收发与通知回调
  • 配置与调试

    • 协议配置常量
    • 日志系统与调试指南
  • 界面与交互

    • 设备扫描与连接界面
    • 设备详情与设置界面

协议配置常量

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() 这类访问器对外提供。

选择"常量类 + 单例配置"两层结构的设计意图:

  1. 单一事实来源(Single Source of Truth):Config 集中持有协议 UUID,BleManager 在类加载时即从 Config.INSTANCE 取值为 public final static 常量,全工程引用同一份定义,避免各模块各自硬编码 UUID 导致不匹配。
  2. 编译期稳定:BleManager 中的超时值与消息码以 final static 声明,编译后内联,热路径上零开销。
  3. 可维护性:时间类常量统一采用"数值 × 单位"的写法(如 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 通过 import com.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_TIME8000 ms连接最小时间超时,用于判定连接建立是否过慢
SEND_DATA_MAX_TIMEOUT8000 ms单次发送数据的最大超时(公开常量,供发送线程使用)
SCAN_BLE_TIMEOUT12000 ms扫描 BLE 设备的超时(注释建议的最小扫描时长)
CONNECT_BLE_TIMEOUT40000 ms建立 GATT 连接的超时
CALLBACK_TIMEOUT6000 ms等待回调返回的超时
RECONNECT_BLE_DELAY2000 ms断线后自动重连的延迟
BOUND_TIMEOUT30000 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: 发送成功回调

流程要点:

  1. 扫描阶段:BleManager 以 SCAN_BLE_TIMEOUT(12s)为期限发起扫描,超时消息 MSG_SCAN_BLE_TIMEOUT 保证扫描必然收敛。
  2. 连接阶段:connectGatt 使用 TRANSPORT_LE 指定 BLE 传输;CONNECT_BLE_TIMEOUT(40s)兜底连接异常。
  3. 服务发现:连接成功后按 BLE_UUID_SERVICE 匹配服务,按 BLE_UUID_WRITE / BLE_UUID_NOTIFICATION 获取读写与通知特征。
  4. 数据发送:数据进入 SendBleDataThread 的阻塞队列,单次发送受 SEND_DATA_MAX_TIMEOUT(8s)约束,超时则触发失败清理。
  5. 通知订阅:向 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 单例提供publicBLE 服务 UUID,协议变更时唯一需修改处
Config.INSTANCE.getBLE_WRITE_UUID()UUID由 Config 单例提供public写特征 UUID(下发指令)
Config.INSTANCE.getBLE_NOTIFY_UUID()UUID由 Config 单例提供public通知特征 UUID(接收数据)
BLE_UUID_NOTIFICATION_DESCRIPTORUUID00002902-0000-1000-8000-00805F9B34FBpublicCCCD 标准描述符,蓝牙规范固定值
TRANSPORT_AUTOint0public自动选择物理传输
TRANSPORT_BREDRint1public强制经典蓝牙传输
TRANSPORT_LEint2public强制 BLE 传输
MIN_CONNECT_TIMEint8000 msprivate连接最小时间超时
SEND_DATA_MAX_TIMEOUTint8000 mspublic单次发送最大超时
SCAN_BLE_TIMEOUTint12000 msprivate扫描超时
CONNECT_BLE_TIMEOUTint40000 msprivate连接超时
CALLBACK_TIMEOUTint6000 msprivate回调等待超时
RECONNECT_BLE_DELAYint2000 msprivate重连延迟
BOUND_TIMEOUTint30000 msprivate配对/绑定超时
MSG_SCAN_BLE_TIMEOUT ~ MSG_BOUND_DEVICE_TIMEOUTint0x1010 ~ 0x1017privateHandler 消息码,与超时一一对应

调参建议:

  • 修改协议 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_TIMEOUT0x1010扫描超时
MSG_CONNECT_BLE_TIMEOUT0x1011连接超时
MSG_SCAN_HID_DEVICE0x1012触发 HID 设备扫描(非超时类)
MSG_NOTIFY_BLE_TIMEOUT0x1013通知使能/接收超时
MSG_CHANGE_BLE_MTU_TIMEOUT0x1014MTU 协商超时
MSG_BLE_DISCOVER_SERVICES_CALLBACK_TIMEOUT0x1015服务发现回调超时
MSG_DISCONNECT_BLE_TIMEOUT0x1016断开操作超时
MSG_BOUND_DEVICE_TIMEOUT0x1017绑定设备超时

声明位置: 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 数据发送、日志与调试配置
Next
日志系统与调试指南