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

    • 项目简介与核心能力
    • 运行环境与SDK版本
  • 快速开始

    • 工程导入与依赖配置
    • 权限配置与示例运行
  • 平台架构

    • SDK分层架构与RCSP协议
    • 蓝牙连接库
    • 健康SDK核心库 JL_Watch
    • 健康服务器与云端服务
  • 健康与运动数据

    • 健康数据同步
    • 运动数据同步
    • 本地数据持久化
  • 设备管理功能

    • 表盘管理
    • 闹钟与健康提醒
    • 消息与联系人同步
    • 天气同步
    • 设备查找
    • 支付宝集成
  • 传输与媒体处理

    • 文件传输与文件管理
    • 音乐传输与播放控制
    • 图像转换库
    • 音频编解码与解密
  • OTA 升级

    • 固件空中升级流程
    • 4G模块与差分升级
  • AI 能力

    • AI表盘与云服务
    • AI语音助手
  • 示例应用

    • HealthAide 健康助手应用
    • WatchTestTool 测试工具
  • 开发者指南

    • 自定义命令扩展
    • 调试技巧与问题排查
    • 版本历史与兼容性

蓝牙连接库

HealthAide 应用中的蓝牙连接能力由两层构成:底层是杰理科技封装的 com.jieli.bluetooth_connect SDK(外部依赖,负责 BLE/SPP 扫描、连接、GATT 数据收发与历史记录),上层是本仓库内 com.jieli.healthaide.tool.bluetooth 包下的应用层封装(BluetoothHelper 门面类、BluetoothEventListener 事件抽象与 BtEventCbManager 事件分发),两者配合 RCSP 协议层实现手表设备的完整连接生命周期。

Purpose and Scope

本页聚焦"蓝牙连接库"这一能力边界,覆盖:

  • 应用层对 bluetooth_connect SDK 的初始化与配置(BluetoothOption、BluetoothCore.init);
  • BluetoothHelper 单例门面提供的连接、断开、MTU 修改、历史记录、设备认证等对外 API;
  • 连接方式的决策逻辑(BLE / SPP / BLE→SPP 切换、OTA 升级设备特殊路径);
  • 事件回调体系(BluetoothEventListener → BtEventCbManager 的注册与分发);
  • 与 RCSP 协议层(RcspAuth、RcspOpImpl)的协作方式。

以下内容不属于本页范围,请参见对应页面:

  • 手表业务指令的封装与 RCSP 协议交互,参见 WatchManager(手表管理);
  • 应用整体启动流程与配置加载,参见 HealthApplication / ConfigHelper;
  • 升级(OTA)流程细节,参见设备升级相关页面。

注意:com.jieli.bluetooth_connect 库本身以 AAR 形式引入,其源码不在本仓库内(仓库中 ListFiles 未发现 bluetooth_connect/** 源码目录)。本页以仓库内可验证的应用层封装代码与测试代码为依据进行说明;SDK 内部实现细节标注为"外部依赖,未在仓库源码中"。

Overview

HealthAide 通过蓝牙与杰理系智能手表通信。连接库解决的核心问题是:如何稳定、可重用地管理一条或多条蓝牙链路,并把底层 Android BLE/GATT 细节与上层业务解耦。

设计上采用经典的分层 + 门面(Facade)+ 单例模式:

  • 门面:BluetoothHelper 是应用全局唯一的蓝牙操作入口,采用双重检查锁(DCL)单例,内部持有 BluetoothManager(SDK 连接管理器)与 RcspAuth(RCSP 设备认证器);
  • 事件总线:BluetoothHelper 内部注册一个 SDK 回调 mBtEventCallback,再通过 BtEventCbManager 把事件扇出给任意数量的 BluetoothEventListener 业务监听者(页面/管理器),实现"一个生产者、多个消费者"的订阅模型;
  • 策略化连接:同一设备可能走 BLE、SPP 或"先 BLE 后切换 SPP"三种路径,连接库根据广播信息(BleScanMessage)、历史记录(HistoryRecord)与设备类型(JL_DeviceType)做运行时决策;
  • 状态管理:连接状态、认证状态(mAuthDeviceMap)、待更新设备(needUpdateDeviceMap)、BLE→SPP 切换参数(connectSppParam)均以内存 Map/对象维护,并通过 Handler 主线程消息做超时兜底。
flowchart TD
    subgraph sg_App["应用层 (com.jieli.healthaide)"]
        UI["业务页面 / WatchManager"]
        Helper["BluetoothHelper<br/>(单例门面)"]
        CbMgr["BtEventCbManager<br/>(事件分发)"]
        Listener["BluetoothEventListener<br/>(抽象监听器)"]
        UI --> Helper
        Helper --> CbMgr
        CbMgr --> Listener
        UI -.implements.-> Listener
    end

    subgraph sg_Sdk["连接库层 (com.jieli.bluetooth_connect 外部 AAR)"]
        Core["BluetoothCore<br/>(全局初始化)"]
        Manager["BluetoothManager<br/>(连接管理器)"]
        Option["BluetoothOption<br/>(连接配置)"]
        Auth["RcspAuth<br/>(设备认证)"]
    end

    subgraph sg_Proto["协议层 (com.jieli.jl_rcsp)"]
        RcspOp["RcspOpImpl<br/>(RCSP 指令操作)"]
    end

    subgraph sg_Android["Android 系统层"]
        Adapter["BluetoothAdapter / GATT"]
    end

    Helper --> Core
    Helper --> Manager
    Helper --> Auth
    Helper --> RcspOp
    Manager --> Option
    Manager --> Adapter
    Auth --> Manager
    RcspOp --> Helper

架构说明:

  • BluetoothHelper 构造时若 BluetoothCore.isInit() 为 false 则用 BluetoothOption.createDefaultOption() 定制参数完成 SDK 全局初始化,随后获取 BluetoothManager 单例并注册回调,创建 RcspAuth,最后调用 fastConnect() 尝试回连历史设备(见 BluetoothHelper.java);
  • 所有 SDK 回调在 mBtEventCallback(BluetoothEventCallback 实现)中统一收敛,经 BtEventCbManager 分发给注册的 BluetoothEventListener;
  • RcspAuth 通过 this::sendDataToDevice 方法引用把认证指令经 BluetoothManager 下发,认证结果回写 mAuthDeviceMap,用于 isConnectedDevice() 的"已连接且已认证"判定。

核心实现剖析

1. SDK 初始化与连接配置

BluetoothHelper 的私有构造函数是连接库的装配点。它把 SDK 的启动参数收敛到 BluetoothOption 中,避免业务方各自初始化:

private BluetoothHelper() {
    BluetoothOption bluetoothOption = BluetoothOption.createDefaultOption()
            .setPriority(HealthConstant.DEFAULT_CONNECT_WAY)
            .setScanFilterData("")
            .setNeedChangeBleMtu(false)
            .setMtu(BluetoothConstant.BLE_MTU_MAX)
            .setUseMultiDevice(false);
    mContext = HealthApplication.getAppViewModel().getApplication();
    if (!BluetoothCore.isInit()) {
        BluetoothCore.init(mContext, bluetoothOption);
    }
    mBluetoothOp = BluetoothManager.getInstance();
    mBluetoothOp.registerBluetoothCallback(mBtEventCallback);
    mRcspAuth = new RcspAuth(this::sendDataToDevice, mRcspAuthListener);
    mBtEventCbManager = new BtEventCbManager();
    mBluetoothOp.fastConnect();
}

Source: BluetoothHelper.java

设计意图:

  • setPriority(HealthConstant.DEFAULT_CONNECT_WAY) 指定扫描/连接优先采用的协议类型(BLE 或 SPP),由全局配置常量控制;
  • setNeedChangeBleMtu(false) + setMtu(BLE_MTU_MAX) 表明 SDK 层面不自动改 MTU,改由应用层在连接成功后按需调用 requestBleMtu(见下文"MTU 修改"),这是把异步时序风险留给应用层可控管理的取舍;
  • setUseMultiDevice(false) 声明单设备连接模式,简化了连接状态机;
  • 构造末尾立即 fastConnect(),让 App 启动即自动回连上次使用过的设备,提升用户"拿起即用"的体验。

单例采用双重检查锁,保证多线程首次访问只构造一次;destroy() 会反注册回调、销毁 BluetoothManager 与 RcspAuth、清理内存 Map 与 Handler 消息,并把 instance 置空以便重建。

2. 连接入口与协议决策

connectDevice(BluetoothDevice) 是基础连接入口。它根据设备类型与历史记录决定走 BLE 还是 SPP:

public boolean connectDevice(BluetoothDevice device) {
    if (null == device || !ConnectUtil.isHasConnectPermission(mContext)) return false;
    int devType = device.getType();
    int connectWay = BluetoothConstant.PROTOCOL_TYPE_BLE;
    if (!HealthConstant.ONLY_CONNECT_BLE) {
        if (devType == BluetoothDevice.DEVICE_TYPE_UNKNOWN || devType == BluetoothDevice.DEVICE_TYPE_DUAL) {
            connectWay = getCacheConnectWay(device);
            if (connectWay == BluetoothConstant.PROTOCOL_TYPE_SPP) {
                String mappedAddress = mBluetoothOp.getMappedDeviceAddress(device.getAddress());
                if (BluetoothAdapter.checkBluetoothAddress(mappedAddress)) {
                    BluetoothDevice mappedDev = getRemoteDevice(mappedAddress);
                    if (mappedDev != null && mappedDev.getType() != BluetoothDevice.DEVICE_TYPE_LE) {
                        device = mappedDev;
                    }
                }
            }
        }
    }
    return mBluetoothOp.connectBtDevice(device, connectWay);
}

Source: BluetoothHelper.java

逻辑要点:

  • 入口先做权限校验(ConnectUtil.isHasConnectPermission),这是 Android 6.0+ 动态权限的必要防线;
  • HealthConstant.ONLY_CONNECT_BLE 为 true 时强制 BLE,屏蔽 SPP 路径;
  • 对 DEVICE_TYPE_UNKNOWN(广播包未携带类型)与 DEVICE_TYPE_DUAL(双模)设备,调用 getCacheConnectWay 依据历史记录取回上次连接方式;
  • SPP 路径上会把 BLE 地址映射为经典蓝牙(EDR)地址(getMappedDeviceAddress),并校验映射地址合法且非纯 LE 设备后才替换目标设备。

带广播信息的重载 connectDevice(BluetoothDevice, BleScanMessage) 则利用扫描包做出更精确的决策:

  • 广播包 connectWay == SPP 时,若为手表设备(JL_DEVICE_TYPE_WATCH)且固件版本 v1 或 version Bit(1) 置位,则先走 BLE 再切 SPP(兼容 BR28 手表),否则直接用广播中的 edrAddr 连接经典蓝牙;
  • 若 scanMessage.isOTA()(升级固件的设备),把 OTA 广播地址记录进历史记录(historyRecord.setUpdateAddress),或对新设备放入 needUpdateDeviceMap 待连接后处理升级(见 BluetoothHelper.java)。

3. BLE→SPP 切换(bleChangeSpp)

手表类设备为提高数据吞吐会选择从 BLE 切换到 SPP。切换动作由 RCSP 指令驱动:

public void bleChangeSpp(@NonNull RcspOpImpl rcspOp, @NonNull BluetoothDevice device) {
    DeviceInfo deviceInfo = rcspOp.getDeviceInfo(device);
    connectSppParam = new ConnectSppParam(device.getAddress(), deviceInfo.getEdrAddr());
    rcspOp.sendRcspCommand(device, CommandBuilder.buildNotifyCommunicationWayCmd(BluetoothConstant.PROTOCOL_TYPE_SPP, 0),
            new BooleanRcspActionCallback("bleChangeSpp", new OnOperationCallback<Boolean>() {
                @Override
                public void onSuccess(Boolean result) {
                    JL_Log.i(TAG, "bleChangeSpp", "Waiting for ble disconnect...");
                    mHandler.removeMessages(MSG_CHECK_BLE_DISCONNECT);
                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_BLE_DISCONNECT, CHECK_DELAY);
                }
                @Override
                public void onFailed(BaseError error) {
                    JL_Log.w(TAG, "bleChangeSpp", "onErrCode ---> " + error);
                    if (mHandler.hasMessages(MSG_CHECK_BLE_DISCONNECT)) {
                        mHandler.removeMessages(MSG_CHECK_BLE_DISCONNECT);
                        mHandler.sendEmptyMessage(MSG_CHECK_BLE_DISCONNECT);
                    }
                }
            }));
}

Source: BluetoothHelper.java

切换成功后固件会主动断开 BLE,应用侧用 MSG_CHECK_BLE_DISCONNECT 延迟消息兜底:若 3 秒后 BLE 仍连接着,主线程 Handler 会强制 disconnectDevice(bleDev)(见 BluetoothHelper.java)。指令失败时则立即触发同一兜底逻辑。connectSppParam 记录 BLE 地址与 EDR 地址,供 isBleChangeSpp(device) 判断当前是否处于切换期。

4. MTU 修改与超时保护

BLE 数据吞吐依赖 MTU 协商。startChangeMtu 用任务对象防重入,并设置 5 秒超时:

private boolean startChangeMtu(BluetoothDevice device, int changeMtu) {
    if (mChangeBleMtuTimeoutTask != null) {
        JL_Log.w(TAG, "startChangeMtu", "Adjusting the MTU for BLE");
        return true;
    }
    boolean ret = mBluetoothOp.requestBleMtu(device, changeMtu);
    JL_Log.i(TAG, "startChangeMtu", "requestBleMtu = " + ret + ", change mtu = " + changeMtu);
    if (ret) {
        mChangeBleMtuTimeoutTask = new ChangeBleMtuTimeoutTask(device);
        mHandler.postDelayed(mChangeBleMtuTimeoutTask, DELAY_WAITING_TIME);
    }
    return ret;
}

Source: BluetoothHelper.java

要点:请求已发出(requestBleMtu 返回 true)后启动 5 秒超时任务,MTU 回调到达时调用 stopChangeBleMtu() 移除任务;超时未回调则按失败处理。这样既避免重复请求,又防止 GATT 回调丢失导致永久等待。

5. 设备认证与连接语义

连接库把"蓝牙已连接"与"业务可用"区分开:isConnectedDevice() 要求设备已连接且通过 RCSP 认证:

public boolean isConnectedDevice() {
    return getConnectedBtDevice() != null && isDevAuth(getConnectedBtDevice().getAddress());
}

private boolean isDevAuth(String address) {
    if (!isEnableDeviceAuth()) return true;
    Boolean b = mAuthDeviceMap.get(address);
    return b != null && b;
}

Source: BluetoothHelper.java 与 BluetoothHelper.java

  • 认证开关来自 ConfigHelper.getInstance().isEnableDeviceAuth()(可远程/本地配置),关闭时 isDevAuth 恒为 true;
  • 开启时,认证结果由 RcspAuth 的回调写入 mAuthDeviceMap(setDevAuth),断开时 removeDevAuth 清除;
  • RcspAuth 的认证指令下发复用 sendDataToDevice(device, data) → mBluetoothOp.sendDataToDevice,即认证报文与业务报文走同一条链路,保证了时序一致性。

6. 事件回调体系

BluetoothEventListener 是应用侧统一的事件抽象(抽象类,全部方法空实现),SDK 事件经 BtEventCbManager 扇出。回调覆盖:

回调方法触发时机
onAdapterStatus(boolean bEnabled)蓝牙适配器开关状态变化
onBtDiscoveryStatus(boolean bBle, boolean bStart)扫描开始/结束
onBtDiscovery(BluetoothDevice device, BleScanMessage bleScanMessage)扫描到设备(携带广播信息)
onShowDialog(BluetoothDevice device, BleScanMessage bleScanMessage)产品弹窗(发现可连接产品)
onBleMtuChange(BluetoothGatt gatt, int mtu, int status)BLE MTU 协商结果
onConnection(BluetoothDevice device, int status)连接状态变化(见 BluetoothConstant.CONNECT_STATE_*)
onReceiveData(BluetoothDevice device, byte[] data)收到裸数据(RCSP 帧解析前)
onSwitchConnectedDevice(BluetoothDevice device)使用中的设备切换
onHistoryRecord(int op, HistoryRecord record)历史记录增删(0 添加 / 1 删除)
onError(ErrorInfo error)连接/数据错误

Source: BluetoothEventListener.java

BluetoothHelper.addBluetoothEventListener/removeBluetoothEventListener 委托给 BtEventCbManager,页面在 onResume/onDestroy 中注册/注销即可,多个页面可同时监听互不干扰。destroy() 中会清空所有监听器,防止 Activity 泄漏。

核心流程

下图描述从扫描到设备可用的完整连接生命周期(以手表 BLE 连接为例):

sequenceDiagram
    participant UI as 业务页面
    participant H as BluetoothHelper
    participant M as BluetoothManager(SDK)
    participant A as Android BLE 栈
    participant CB as mBtEventCallback
    participant B as BtEventCbManager
    participant L as BluetoothEventListener

    UI->>H: connectDevice(device, scanMessage)
    H->>H: 解析连接方式(BLE/SPP/OTA)
    H->>M: connectBtDevice(device, connectWay)
    M->>A: BluetoothGatt connect
    A-->>CB: onConnection(device, CONNECTING)
    CB->>B: 分发
    B->>L: onConnection(device, CONNECTING)
    A-->>CB: onConnection(device, CONNECTED)
    CB->>B: 分发
    B->>L: onConnection(device, CONNECTED)
    H->>M: requestBleMtu(device, BLE_MTU_MAX)
    A-->>CB: onBleMtuChange(gatt, mtu, status)
    CB->>B: 分发
    B->>L: onBleMtuChange(...)
    H->>RcspAuth: 认证指令(sendDataToDevice)
    M-->>CB: onReceiveData(device, data)
    CB->>H: mRcspAuthListener 认证成功
    H->>H: setDevAuth(device, true)
    H-->>UI: isConnectedDevice() == true

流程解读:

  1. 业务方调用 connectDevice,BluetoothHelper 完成协议决策(BLE / SPP / OTA 特殊路径)后转交 BluetoothManager;
  2. SDK 内部驱动 Android BluetoothGatt 建立链路,连接状态通过 onConnection 回调上行,经 BtEventCbManager 广播给所有监听者;
  3. 连接成功后应用层主动 requestBleMtu 提升吞吐,MTU 结果同样走事件链路上报;
  4. RCSP 认证报文通过 sendDataToDevice 下发,认证结果写入 mAuthDeviceMap,此后 isConnectedDevice() 才返回 true——业务层用这一语义决定是否展示"已连接" UI 或允许数据操作;
  5. 数据接收(onReceiveData)始终先经 mBtEventCallback 汇聚,属于 RCSP 指令的数据再由上层协议栈(WatchManager / RcspOpImpl)解析。

使用示例

示例 1:应用启动时配置 SDK 日志

在 HealthApplication.onCreate 中把日志开关同步给连接库与 RCSP 层:

JL_Log.configureLog(this, isEnableLogFunc, isEnableLogFunc);
com.jieli.bluetooth_connect.util.JL_Log.setLog(isEnableLogFunc);
com.jieli.bluetooth_connect.util.JL_Log.setLogOutput(JL_Log::addLogOutput);

Source: HealthApplication.java

说明:JL_Log::addLogOutput 是应用自定义的日志输出方法引用,用于把 SDK 日志重定向到统一日志系统,便于线上问题排查。

示例 2:获取单例并监听连接事件

测试代码展示了最典型的使用姿势——注册监听器、获取连接状态、发起连接:

import com.jieli.bluetooth_connect.constant.BluetoothConstant;
import com.jieli.bluetooth_connect.util.ConnectUtil;
import com.jieli.healthaide.tool.bluetooth.BluetoothEventListener;
import com.jieli.healthaide.tool.bluetooth.BluetoothHelper;
BluetoothEventListener listener = new BluetoothEventListener() {
    @Override
    public void onRcspInit(BluetoothDevice device, boolean isInit) {
        super.onRcspInit(device, isInit); // RCSP 协议初始化状态
    }
    @Override
    public void onMandatoryUpgrade(BluetoothDevice device) {
        super.onMandatoryUpgrade(device); // 强升设备回调
    }
    @Override
    public void onWatchSystemException(BluetoothDevice device, int sysStatus) {
        super.onWatchSystemException(device, sysStatus); // 0 为正常,其他为错误码
    }
};
BluetoothHelper.getInstance().addBluetoothEventListener(listener);

Source: WatchManagerTest.java

说明:WatchManagerTest 通过继承 BluetoothEventListener 并覆写 RCSP 相关回调来观测连接/协议状态,这反映了连接库与 RCSP 协议层的协作契约——连接库只负责链路,协议事件由上层监听器继续处理。

示例 3:连接、状态查询与断开

public boolean connectDevice(BluetoothDevice device) {
    if (null == device || !ConnectUtil.isHasConnectPermission(mContext)) return false;
    // ... 协议决策 ...
    return mBluetoothOp.connectBtDevice(device, connectWay);
}

public int getConnectionStatus(BluetoothDevice device) {
    if (null == device) return BluetoothConstant.CONNECT_STATE_DISCONNECT;
    int status = BluetoothConstant.CONNECT_STATE_DISCONNECT;
    if (isConnectedBtDevice(device)) {
        status = BluetoothConstant.CONNECT_STATE_CONNECTED;
    } else if (BluetoothUtil.deviceEquals(device, getBluetoothOp().getConnectingDevice())) {
        status = BluetoothConstant.CONNECT_STATE_CONNECTING;
    }
    return status;
}

public void disconnectDevice(BluetoothDevice device) {
    if (null == device || !ConnectUtil.isHasConnectPermission(mContext)) return;
    if (isConnectedBtDevice(device)) {
        mBluetoothOp.disconnectBtDevice(device);
    } else {
        publishDeviceConnectionStatus(device, BluetoothConstant.CONNECT_STATE_DISCONNECT);
    }
}

Source: BluetoothHelper.java、BluetoothHelper.java、BluetoothHelper.java

说明:getConnectionStatus 归一化三种状态(断开/连接中/已连接),UI 层可直接绑定;disconnectDevice 对未连接设备会主动补发一条 CONNECT_STATE_DISCONNECT 事件,保证监听者状态一致。

配置选项

连接库的配置集中在 BluetoothOption(SDK 初始化参数)与 HealthConstant(应用全局常量)两处。

BluetoothOption(SDK 初始化)

配置项类型默认值(本仓库实际设置)说明
setPriority(connectWay)intHealthConstant.DEFAULT_CONNECT_WAY扫描/连接优先协议(BLE 或 SPP)
setScanFilterData(filter)String""扫描过滤数据(空为不过滤)
setNeedChangeBleMtu(need)booleanfalseSDK 是否自动协商 MTU(应用层自行控制)
setMtu(mtu)intBluetoothConstant.BLE_MTU_MAX目标 MTU 值
setUseMultiDevice(use)booleanfalse是否支持多设备同时连接
setSkipNoneNameDevice(skip)boolean注释掉(未启用)Android 13 上跳过无名称设备(注释保留备选)

Source: BluetoothHelper.java

应用级开关(HealthConstant / ConfigHelper)

开关类型说明
HealthConstant.ONLY_CONNECT_BLEbooleantrue 时强制所有连接走 BLE,屏蔽 SPP 与 EDR 映射
HealthConstant.DEFAULT_CONNECT_WAYint默认连接协议(注入 BluetoothOption.setPriority)
ConfigHelper.isEnableDeviceAuth()boolean是否启用 RCSP 设备认证流程(关闭则 isDevAuth 恒 true)
DELAY_WAITING_TIME = 5000LlongMTU 修改超时(毫秒)
CHECK_DELAY = 3000intBLE→SPP 切换后 BLE 断开兜底检查延迟(毫秒)

Source: BluetoothHelper.java

API 参考

BluetoothHelper(单例门面)

方法签名返回值说明
static BluetoothHelper getInstance()BluetoothHelperDCL 单例获取;首次调用触发 SDK 初始化与 fastConnect()
void addBluetoothEventListener(BluetoothEventListener listener)void注册事件监听(委托 BtEventCbManager)
void removeBluetoothEventListener(BluetoothEventListener listener)void注销事件监听
void destroy()void反注册回调、销毁 SDK 与认证器、清理状态
BluetoothManager getBluetoothOp()BluetoothManager暴露 SDK 连接管理器(高级用法)
boolean isConnectedBtDevice(BluetoothDevice)boolean设备是否已连接(链路层)
boolean isUsedBtDevice(BluetoothDevice)boolean设备是否连接且为当前使用设备
boolean isHistoryRecord(String devAddress)boolean是否存在历史记录
boolean isConnectedDevice()boolean是否已连接且已认证(业务可用语义)
BluetoothDevice getConnectedBtDevice()BluetoothDevice当前连接设备
BluetoothGatt getConnectedBluetoothGatt(BluetoothDevice)BluetoothGatt获取 GATT 控制对象
int getConnectionStatus(BluetoothDevice)intCONNECT_STATE_DISCONNECT/CONNECTING/CONNECTED
boolean connectDeviceWithoutRecord(BluetoothDevice)boolean连接且不写入历史记录
boolean connectDevice(BluetoothDevice)boolean基础连接(自动决策 BLE/SPP)
boolean connectDevice(BluetoothDevice, BleScanMessage)boolean基于广播信息连接(支持 OTA 设备)
void connectHistoryRecord(HistoryRecord, OnHistoryRecordCallback)void按历史记录回连
void removeHistoryRecord(String, OnHistoryRecordCallback)void删除历史记录
int getCacheConnectWay(BluetoothDevice)int从历史记录推断上次连接方式
boolean sendDataToDevice(BluetoothDevice, byte[])boolean发送裸数据到设备
void disconnectDevice(BluetoothDevice)void断开连接(未连接时补发断开事件)
boolean isAuthDevice(BluetoothDevice)boolean设备是否已通过认证
void syncEdrConnectionStatus(BluetoothDevice, DeviceInfo)void同步经典蓝牙连接状态(抢连处理)
void bleChangeSpp(RcspOpImpl, BluetoothDevice)void发起 BLE→SPP 切换(RCSP 指令)
boolean isBleChangeSpp(BluetoothDevice)boolean是否处于 BLE→SPP 切换期

BluetoothEventListener(抽象监听器)

全部方法为空实现的钩子,业务方可按需覆写;回调方法签名与语义见上文"事件回调体系"表格。典型覆写:onConnection(UI 状态刷新)、onBtDiscovery(扫描列表)、onReceiveData(裸数据/协议透传)、onError(错误提示)。

失败模式、边界情况与并发

  • 权限缺失:所有连接/断开/查询入口首先校验 ConnectUtil.isHasConnectPermission(mContext),不满足直接返回 false,避免运行时崩溃;BluetoothHelper 类级标注 @SuppressLint("MissingPermission"),权限由调用方在 UI 流程保证。
  • MTU 回调丢失:startChangeMtu 设 5 秒超时任务(ChangeBleMtuTimeoutTask),回调未到则超时处理;重入时直接返回 true 并告警,防止并发重复请求。
  • BLE→SPP 切换失败:onFailed 立即触发 MSG_CHECK_BLE_DISCONNECT 兜底;成功但固件未断 BLE 时由 3 秒延迟消息强制断开,避免双链路并存导致收发错乱。
  • 设备被其他手机连接:syncEdrConnectionStatus 检测到 edrStatus 为已连接但本机 profile 未连接时,判定"被其他手机占用",尝试 startConnectByBreProfiles 抢占,失败仅打日志不阻塞主流程。
  • 并发与线程:instance 为 volatile 且初始化走 synchronized 块(DCL);mAuthDeviceMap、needUpdateDeviceMap、bleToSppList 均为普通 HashMap/ArrayList,SDK 回调与主线程 Handler 操作存在潜在竞争,但工程上回调串行化于主线程(mHandler 基于 Looper.getMainLooper()),实际风险可控。
  • 资源泄漏防护:单例持有 Context 用 @SuppressLint("StaticFieldLeak") 标注并取 Application 级 context;destroy() 清空监听器、Map 与 Handler 消息,供应用退出时调用。
  • 未授权设备:开启设备认证时,链路已通但 isConnectedDevice() 返回 false,业务层应等待认证回调后再展示可用状态,避免对未认证设备下发指令。

性能与运维

  • 回连策略:构造时即 fastConnect(),减少用户手动重连等待;连接成功后再协商 MTU(BLE_MTU_MAX)提升单包吞吐,为健康数据同步提速。
  • 日志可观测:HealthApplication 统一配置 bluetooth_connect 与 RCSP 层日志开关,并重定向到 JL_Log::addLogOutput;连接库关键路径(JL_Log.d/i/w 打点:连接方式、MTU 结果、切换等待、抢连结果)均可按 TAG 检索。
  • 超时保护:所有异步协商(MTU、BLE 断开兜底)均有主线程 Handler 超时兜底,防止挂起。

扩展点

  • 新增连接协议/设备类型:在 connectDevice(device, scanMessage) 的协议决策分支中扩展(参照 SPP 特殊路径与 OTA 分支),决策结果仍是 mBluetoothOp.connectBtDevice 单一出口。
  • 自定义事件消费者:实现/继承 BluetoothEventListener 并注册到 BluetoothHelper,不修改连接库即可订阅任意事件子集。
  • 认证策略替换:RcspAuth 通过构造器注入数据发送函数(this::sendDataToDevice)与认证监听器,可替换为自定义认证实现;认证开关由 ConfigHelper.isEnableDeviceAuth() 控制。
  • SDK 层定制:getBluetoothOp() 暴露 BluetoothManager,高级场景可绕过门面直接操作 SDK(如自定义扫描过滤、多设备支持需同时调整 setUseMultiDevice)。

测试

  • WatchManagerTest(WatchManagerTest.java)通过继承 BluetoothEventListener 覆写 onRcspInit、onMandatoryUpgrade、onWatchSystemException 等回调,验证连接库与 RCSP 协议层的协作契约及系统异常码上报路径。
  • ConnectDebug(ConnectDebug.java)导入 JL_Log 用于连接调试,反映 SDK 日志 API 的测试用法。
  • 测试代码同时揭示了库的关键使用契约:连接回调必须先于协议指令下发、认证通过后才允许业务操作、强升设备需走 onMandatoryUpgrade 特殊流程。

相关链接

  • BluetoothHelper.java — 连接库门面实现
  • BluetoothEventListener.java — 事件监听抽象
  • BtEventCbManager.java — 事件分发管理器
  • NeedUpdateDevice.java — OTA 待更新设备信息模型
  • HealthApplication.java — 应用初始化(SDK 日志配置)
  • WatchManagerTest.java — 连接/协议协作测试
  • 相关能力页:WatchManager(手表管理)、ConfigHelper(配置中心)、设备升级(OTA)
Prev
SDK分层架构与RCSP协议
Next
健康SDK核心库 JL_Watch