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

    • 杰理 OTA SDK 项目简介
    • 快速开始与接入指南
    • 工程结构与发布物
  • 核心库与依赖

    • OTA 核心库集成
    • 版本历史与更新说明
  • SDK 工具层

    • OTA 参数配置
    • 蓝牙扫描与连接管理
    • BLE 通道与事件回调
    • OTA 升级流程与状态模型
    • 固件文件管理与监听
  • 演示应用

    • 演示应用架构与主界面
    • 设备发现与连接界面
    • 文件选择与升级界面
    • 多设备 OTA 模型

蓝牙扫描与连接管理

蓝牙扫描与连接管理是 otasdk 中面向 OTA 业务层的蓝牙操作门面(Facade),通过 BluetoothHelper 单例统一封装 BLE 与经典蓝牙 SPP 两种链路的设备扫描、连接、断开、重连与数据读写,并通过 BTEventCbHelper 以观察者模式将底层 BleManager / SppManager 事件统一回调到主线程,供 UI 层订阅。

Purpose and Scope

本页覆盖 com.jieli.otasdk.tool.bluetooth 包下的两个核心类:

  • BluetoothHelper —— 对外提供的蓝牙操作统一入口(扫描、连接、读写、状态查询、回调注册);
  • BTEventCbHelper —— 蓝牙事件的注册/分发辅助类,负责线程切换与多订阅者广播。

同时会说明它们与底层传输层(BleManager、SppManager)、配置层(ConfigHelper)、公共常量(OtaConstant、BluetoothConstant)之间的协作关系。

以下主题属于兄弟页面、不在本页展开:底层 BLE GATT 传输实现(BleManager 的扫描细节、MTU 协商、分包收发)与 SPP 套接字传输实现(SppManager 的 UUID 通道管理)、配置项来源(ConfigHelper)、以及基于本门面之上的 OTA 升级流程(BluetoothViewModel、BaseBluetoothFragment 等 UI 层用法)。

概述

设计目标

OTA 升级依赖一条稳定的蓝牙数据链路。杰理 OTA SDK 需要同时支持两种传输方式:

  1. BLE(低功耗蓝牙):走 GATT 服务与特征值,适合低功耗、短数据包的升级场景;
  2. SPP(经典蓝牙串口协议):走 RFCOMM 通道,适合大数据量、连续流的升级场景。

BluetoothHelper 的核心价值在于:屏蔽底层差异,向上层暴露一套统一的蓝牙操作 API。上层(BluetoothViewModel、BaseBluetoothFragment、OTA 流程代码)只需调用 startScan、connectDevice、writeDataToDevice 等方法,由门面根据 ConfigHelper 中的连接方式配置自动路由到 BleManager 或 SppManager。

关键概念

概念说明
连接方式(ConnectWay)ConfigHelper.getConnectWay() 决定路由:SPP / GATT_OVER_BR_EDR / 默认 BLE
协议类型OtaConstant.PROTOCOL_BLE 与 OtaConstant.PROTOCOL_SPP,用于回调中区分事件来源
事件回调OnBTEventCallback 接口,覆盖适配器状态、扫描发现、连接状态、数据接收、MTU 变化
线程模型底层事件在任意线程触发,BTEventCbHelper 统一投递到主线程 Handler 执行

使用场景

  • 设备发现:调用 startScan(timeout) 扫描附近杰理设备,通过 onDiscovery 回调获取 BluetoothDevice 与 BleScanInfo(含 RSSI);
  • 建立连接:对扫描到的设备调用 connectDevice(device),监听 onDeviceConnection 确认连接成功;
  • 数据交互:连接成功后调用 writeDataToDevice() 下发 OTA 命令,通过 onReceiveData 接收设备响应;
  • 状态监控:通过 isConnected() / isScanning() / isConnecting() 轮询或通过回调驱动 UI 状态。

架构

flowchart TD
    subgraph sg_UI["UI / 业务层"]
        ViewModel["BluetoothViewModel / BaseBluetoothFragment"]
        Callback["OnBTEventCallback 实现"]
    end

    subgraph sg_Facade["蓝牙门面层 (tool.bluetooth)"]
        Helper["BluetoothHelper (单例)"]
        CbHelper["BTEventCbHelper (事件分发)"]
    end

    subgraph sg_Transport["传输层 (tool.ota)"]
        Ble["BleManager (BLE GATT)"]
        Spp["SppManager (SPP RFCOMM)"]
    end

    subgraph sg_Config["配置层"]
        Config["ConfigHelper"]
    end

    ViewModel -->|"startScan / connectDevice / writeDataToDevice"| Helper
    ViewModel -->|"registerCallback"| CbHelper
    Callback -->|"回调订阅"| CbHelper

    Helper -->|"路由: isBleWay / isSppWay"| Config
    Helper -->|"委托扫描/连接/读写"| Ble
    Helper -->|"委托扫描/连接/读写"| Spp
    Helper -->|"注册底层事件"| CbHelper

    Ble -->|"onDiscoveryBle / onBleConnection / onBleDataNotification"| Helper
    Spp -->|"onDiscoveryDevice / onSppConnection / onReceiveSppData"| Helper
    CbHelper -->|"onDiscovery / onDeviceConnection / onReceiveData (主线程)"| Callback

架构说明:

  • BluetoothHelper 是唯一对外的门面,持有 BleManager、SppManager、BTEventCbHelper、ConfigHelper 四个依赖(见 BluetoothHelper.kt)。它不直接操作 GATT 或 Socket,所有底层动作都委托给传输层管理器。
  • BTEventCbHelper 是事件总线:底层 BleEventCallback / SppEventCallback 的事件先到达 BluetoothHelper 的匿名回调对象,再转发给 BTEventCbHelper,由其统一广播给所有注册的 OnBTEventCallback(见 BTEventCbHelper.kt)。
  • 传输层(BleManager / SppManager)各自实现扫描与连接细节,本页只描述门面对它们的调用契约。

单例与生命周期

BluetoothHelper 采用经典的线程安全懒加载单例:@Volatile 字段 + synchronized 双重检查(见 BluetoothHelper.kt)。构造时(init 块)同时向 BleManager 与 SppManager 注册事件回调,因此无论当前配置走哪种协议,两个传输层的事件都会被监听;destroy() 时对称地注销回调并释放资源、将 instance 置空以允许重新创建(见 BluetoothHelper.kt)。

双协议路由设计

门面层的核心决策逻辑全部委托给 ConfigHelper,自身只做分发。三个关键路由方法:

1. 链路选择:isBleWay() / isSppWay()

fun isScanning(): Boolean = if (configHelper.isBleWay()) {
    bleManager.isBleScanning
} else {
    sppManager.isScanning
}

fun getConnectedDevice(): BluetoothDevice? {
    return if (configHelper.isSppWay()) {
        sppManager.connectedSppDevice
    } else {
        bleManager.connectedBtDevice
    }
}

Source: BluetoothHelper.kt

设计意图:isScanning() 优先判断 isBleWay(),而 getConnectedDevice() 优先判断 isSppWay()。这并非笔误,而是反映了默认策略:未显式配置时按 BLE 链路处理,但若配置为 SPP 则以 SPP 为准。所有状态查询方法(isScanning、isConnecting、getConnectedDevice、getConnectingDevice、getConnectedGatt、getBleMtu)都遵循这一"先查 SPP、否则走 BLE"的对称模式,保证上层代码不感知底层协议。

2. 连接路由:connectDevice() 三分支

fun connectDevice(device: BluetoothDevice?): Boolean =
    when (configHelper.getConnectWay()) {
        BluetoothConstant.PROTOCOL_TYPE_SPP -> sppManager.connectSpp(device)
        BluetoothConstant.PROTOCOL_TYPE_GATT_OVER_BR_EDR -> bleManager.connectBleDevice(
            device, BleConnectParam()
                .setRequestMtu(BluetoothConstant.BLE_MTU_MAX)
                .setTransport(BleConnectParam.TRANSPORT_BREDR)
        )
        else -> bleManager.connectBleDevice(device)
    }

Source: BluetoothHelper.kt

设计意图:连接动作被拆成三种方式:

  • PROTOCOL_TYPE_SPP → 走经典蓝牙 RFCOMM;
  • PROTOCOL_TYPE_GATT_OVER_BR_EDR → 走 BR/EDR 传输上的 GATT(TRANSPORT_BREDR),此时显式请求最大 MTU(BLE_MTU_MAX),适合大包升级;
  • 其他(默认 BLE)→ 走低功耗 GATT,参数使用默认值。

BleConnectParam 以链式 API 构造连接参数,将 MTU 请求与传输类型编码进一次调用,避免为每种组合定义独立方法。

扫描流程

fun startScan(timeout: Long): Boolean {
    return if (configHelper.isBleWay()) {
        bleManager.startLeScan(timeout)
    } else {
        sppManager.startDeviceScan(timeout)
    }
}

fun stopScan() {
    if (configHelper.isBleWay()) {
        bleManager.stopLeScan()
    } else {
        sppManager.stopDeviceScan()
    }
}

Source: BluetoothHelper.kt

扫描结果通过两条路径回传:

  • BLE:onDiscoveryBle(device, bleScanMessage),携带 BleScanInfo(扫描信息,如广播数据、RSSI);
  • SPP:onDiscoveryDevice(device, rssi),仅携带 RSSI,由门面包装成 BleScanInfo().setRssi(rssi) 以统一回调签名(见 BluetoothHelper.kt)。

扫描开始/结束状态统一通过 onDiscoveryChange(bStart, scanType) 通知,scanType 区分 PROTOCOL_BLE / PROTOCOL_SPP,UI 层可据此显示"搜索中"提示。

数据读写

writeDataToDevice() 是门面中最复杂的自适应方法:它先探测设备当前实际处于哪条链路,再选择对应的异步写接口:

fun writeDataToDevice(bluetoothDevice: BluetoothDevice?, byteArray: ByteArray?): Boolean {
    if (null == bluetoothDevice || null == byteArray || byteArray.isEmpty()) return false
    if (bleManager.isConnectedDevice(bluetoothDevice)) {//目前连接的设备是ble
        bleManager.writeDataByBleAsync(
            bluetoothDevice,
            BleManager.BLE_UUID_SERVICE,
            BleManager.BLE_UUID_WRITE,
            byteArray
        ) { device, _, _, result, data ->
            JL_Log.d(TAG, "writeDataByBleAsync",
                "device : ${printDeviceInfo(device)}, result : $result,\n" +
                        "data : [${CHexConver.byte2HexStr(data)}]")
        }
        return true
    }
    if (sppManager.isSppConnected(bluetoothDevice)) {//目前连接的设备是Spp
        sppManager.writeDataToSppAsync(
            bluetoothDevice,
            SppManager.UUID_SPP,
            byteArray
        ) { device, sppUUID, result, data ->
            JL_Log.d(TAG, "writeDataToSppAsync",
                "device : ${printDeviceInfo(device)}, uuid : $sppUUID, result : $result,\n" +
                        "data : ${CHexConver.byte2HexStr(data)}")
        }
        return true
    }
    return false
}

Source: BluetoothHelper.kt

设计意图与边界行为:

  • 前置校验:设备或数据为空、数据为空数组时直接返回 false,不产生无效调用;
  • 不依赖配置、依赖实际连接状态:即使配置为 BLE,只要该设备实际是通过 SPP 连接的(例如双模设备),也会正确路由到 SPP 通道;反之亦然。这避免了"配置与实况不一致"导致写入失败;
  • 异步写(...Async)携带回调,回调中打印设备信息、结果与十六进制数据,便于 OTA 调试;
  • 两条链路都未连接时返回 false,调用方(OTA 流程)应据此判定链路异常并提示用户。

事件回调机制

双层转发结构

底层事件 → BluetoothHelper 匿名回调 → BTEventCbHelper → 所有订阅者,共两层转发。第一层在 BluetoothHelper 的 bleEventCallback / sppEventCallback 中完成协议归一化:

private val bleEventCallback = object : BleEventCallback() {
    override fun onDiscoveryBle(device: BluetoothDevice?, bleScanMessage: BleScanInfo?) {
        btEventCbHelper.onDiscovery(device, bleScanMessage)
    }
    override fun onBleConnection(device: BluetoothDevice?, status: Int) {
        btEventCbHelper.onDeviceConnection(device, OtaConstant.PROTOCOL_BLE, status)
    }
    override fun onBleDataNotification(
        device: BluetoothDevice?, serviceUuid: UUID?,
        characteristicsUuid: UUID?, data: ByteArray?
    ) {
        btEventCbHelper.onReceiveData(device, OtaConstant.PROTOCOL_BLE, characteristicsUuid, data)
    }
}

Source: BluetoothHelper.kt

归一化规则:BLE/SPP 各自的连接回调统一为 onDeviceConnection(device, way, status);数据回调统一为 onReceiveData(device, way, uuid, data);MTU 变化统一为 onBleMtuChange。way 参数让订阅者可以在一个回调里区分事件来源协议。

SPP 多通道过滤

SPP 链路支持自定义多通道,当开启多通道且当前回调 UUID 不是自定义通道时,该连接事件被主动丢弃,避免干扰业务层:

override fun onSppConnection(device: BluetoothDevice?, uuid: UUID?, status: Int) {
    if (status == BluetoothProfile.STATE_CONNECTED && configHelper.isUseMultiSppChannel()
        && UUID.fromString(configHelper.getCustomSppChannel()) != uuid
    ) {
        JL_Log.i(TAG, "onSppConnection", "skip custom uuid = $uuid")
        return
    }
    btEventCbHelper.onDeviceConnection(device, OtaConstant.PROTOCOL_SPP, status)
}

Source: BluetoothHelper.kt

设计意图:某些杰理设备可能同时在多个 SPP UUID 上建连,业务层只关心自定义通道的连接事件;若不过滤,UI 可能被非业务通道的连接状态刷新干扰。

主线程投递与并发安全

BTEventCbHelper 内部维护 MutableList<OnBTEventCallback> 与主线程 Handler。所有事件的最终分发都经过 callbackEvent():

private fun callbackEvent(impl: CallbackImpl<OnBTEventCallback>?) {
    if (null == impl) return
    val runnable = CallbackRunnable(callbacks, impl)
    if (Thread.currentThread().id == Looper.getMainLooper().thread.id) {
        runnable.run()
    } else {
        uiHandler.post(runnable)
    }
}

Source: BTEventCbHelper.kt

CallbackRunnable 在真正遍历前对回调列表做快照拷贝(temp.addAll(callbacks) 后遍历 temp),因此回调中即使有订阅者注册/注销,也不会触发 ConcurrentModificationException;同时把遍历放在主线程,保证 UI 更新无需再手动切换线程(见 BTEventCbHelper.kt)。

核心流程

sequenceDiagram
    participant UI as 业务层 (BluetoothViewModel)
    participant H as BluetoothHelper (门面)
    participant B as BleManager / SppManager
    participant CB as BTEventCbHelper
    participant DEV as 杰理设备

    UI->>H: startScan(timeout)
    H->>B: startLeScan / startDeviceScan
    B-->>CB: onDiscoveryBle / onDiscoveryDevice
    CB-->>UI: onDiscovery(device, BleScanInfo) [主线程]
    UI->>H: connectDevice(device)
    H->>H: getConnectWay() 三分支路由
    H->>B: connectSpp / connectBleDevice(BleConnectParam)
    B-->>CB: onBleConnection / onSppConnection (status)
    CB-->>UI: onDeviceConnection(device, way, status) [主线程]
    UI->>H: writeDataToDevice(device, data)
    H->>H: isConnectedDevice 探测实际链路
    H->>B: writeDataByBleAsync / writeDataToSppAsync
    B-->>CB: onBleDataNotification / onReceiveSppData
    CB-->>UI: onReceiveData(device, way, uuid, data) [主线程]

流程要点:

  1. 扫描:UI 调用 startScan(timeout),门面按 isBleWay() 路由;每个发现的设备经"底层回调 → 门面归一化 → BTEventCbHelper → 主线程"四跳到达 UI;
  2. 连接:connectDevice() 按 getConnectWay() 三分支路由;SPP 场景下非自定义通道的连接事件在门面层被过滤;
  3. 读写:writeDataToDevice() 不信任配置,而是用 isConnectedDevice / isSppConnected 探测设备实际连接链路,保证写入落到正确通道;
  4. 线程:所有回调最终都在主线程执行,UI 层可直接更新界面。

使用示例

基本用法:注册回调并扫描连接

以下代码演示 SDK 上层(如 BluetoothViewModel 类)如何使用 BluetoothHelper 的完整链路——注册回调、启动扫描、连接设备:

class BluetoothViewModel {
    // 通过门面单例获取统一操作入口
    private val bluetoothHelper = BluetoothHelper.getInstance()

    private val callback = object : OnBTEventCallback() {
        override fun onDiscoveryChange(bStart: Boolean, scanType: Int) {
            // 扫描状态变化,可刷新 UI 的"搜索中"提示
        }

        override fun onDiscovery(device: BluetoothDevice?, bleScanMessage: BleScanInfo?) {
            // 发现设备:bleScanMessage 包含 RSSI 等广播信息
        }

        override fun onDeviceConnection(device: BluetoothDevice?, way: Int, status: Int) {
            // way = OtaConstant.PROTOCOL_BLE 或 PROTOCOL_SPP
            // status 为连接状态,可用于判断连接成功/断开
        }

        override fun onReceiveData(device: BluetoothDevice?, way: Int, uuid: UUID?, data: ByteArray?) {
            // 设备主动上报的数据,OTA 流程在此解析应答
        }
    }

    init {
        bluetoothHelper.registerCallback(callback)
        bluetoothHelper.startScan(5000L)      // 扫描 5 秒
    }

    fun onDeviceSelected(device: BluetoothDevice?) {
        bluetoothHelper.stopScan()
        bluetoothHelper.connectDevice(device) // 按配置自动路由 BLE/SPP
    }

    fun release() {
        bluetoothHelper.unregisterCallback(callback)
        bluetoothHelper.destroy()
    }
}

Source: BluetoothHelper.kt 与 BTEventCbHelper.kt

高级用法:按配置路由的连接与自适应写入

connectDevice 的 when 分发与 writeDataToDevice 的实际链路探测,是上层无需感知协议差异的关键:

fun connectDevice(device: BluetoothDevice?): Boolean =
    when (configHelper.getConnectWay()) {
        BluetoothConstant.PROTOCOL_TYPE_SPP -> sppManager.connectSpp(device)
        BluetoothConstant.PROTOCOL_TYPE_GATT_OVER_BR_EDR -> bleManager.connectBleDevice(
            device, BleConnectParam()
                .setRequestMtu(BluetoothConstant.BLE_MTU_MAX)
                .setTransport(BleConnectParam.TRANSPORT_BREDR)
        )
        else -> bleManager.connectBleDevice(device)
    }

fun disconnectDevice(device: BluetoothDevice?) {
    if (configHelper.isSppWay()) {
        sppManager.disconnectSpp(device, null)
    } else {
        bleManager.disconnectBleDevice(device)
    }
}

Source: BluetoothHelper.kt

要点:disconnectDevice 直接按 isSppWay() 分流(无回退),因为断开动作不需要探测实况;而连接与写入则更谨慎地做了配置路由 + 实况探测的双保险。

配置选项

蓝牙连接行为由 ConfigHelper 驱动,BluetoothHelper 消费以下配置(配置项实际定义在 ConfigHelper 中,本页仅列出门面依赖的关键项):

配置项(方法)类型默认行为影响
getConnectWay()Int默认 BLE决定 connectDevice 三分支路由(SPP / GATT_OVER_BR_EDR / BLE)
isBleWay()Boolean未配置时按 BLE决定扫描、状态查询走 BleManager 还是 SppManager
isSppWay()Booleanfalse决定断开、设备查询走 SPP 链路
isUseMultiSppChannel()Booleanfalse是否启用 SPP 多通道过滤
getCustomSppChannel()String自定义 UUID 字符串多通道模式下唯一被放行的 SPP 连接 UUID

配置与行为的对应关系:

  • 扫描(startScan/stopScan)只认 isBleWay();
  • 连接(connectDevice)只认 getConnectWay() 的三分支;
  • 断开与已连接设备查询认 isSppWay();
  • SPP 连接事件过滤同时依赖 isUseMultiSppChannel() 与 getCustomSppChannel()。

API 参考

BluetoothHelper(com.jieli.otasdk.tool.bluetooth)

方法签名要点说明
getInstance()BluetoothHelper(伴生对象静态方法)线程安全懒加载单例
destroy()Unit注销回调、销毁传输层、置空单例
registerCallback(cb)Unit注册 OnBTEventCallback 订阅者(自动去重)
unregisterCallback(cb)Unit注销订阅者
isConnected()Boolean是否有已连接设备
isDeviceConnected(device)Boolean指定设备是否已连接
isScanning()Boolean是否正在扫描(按 isBleWay() 路由)
isConnecting()Boolean是否正在连接
getConnectedDevice()BluetoothDevice?当前已连接设备(按 isSppWay() 路由)
getConnectingDevice()BluetoothDevice?正在连接的设备
getConnectedGatt(device)BluetoothGatt?BLE 链路的 GATT 对象(SPP 返回 null)
getBleMtu(device)Int当前 MTU(SPP 返回 BLE_MTU_MAX)
startScan(timeout: Long)Boolean启动扫描,超时自动停止
stopScan()Unit停止扫描
connectDevice(device)Boolean按 getConnectWay() 三分支建立连接
connectBleDevice(device)Boolean强制走 BLE 连接
disconnectDevice(device)Unit断开连接(按 isSppWay() 分流)
reconnectDevice(address, isUseNewAdv)Unit按 MAC 地址重连 BLE(SPP 暂未实现,代码中留有 TODO)
writeDataToDevice(device, data)Boolean按实际链路异步写数据;未连接/参数非法返回 false

BTEventCbHelper(事件分发)

方法说明
registerCallback(cb)添加订阅者(已存在则忽略)
unregisterCallback(cb)移除订阅者(空列表时直接返回)
release()清空订阅者并移除主线程 Handler 中所有待执行消息
callbackEvent(impl)内部方法:在主线程执行 CallbackRunnable

OnBTEventCallback 事件接口

回调参数触发时机
onAdapterChangebEnabled: Boolean蓝牙适配器开关状态变化
onDiscoveryChangebStart: Boolean, scanType: Int扫描开始/结束
onDiscoverydevice, bleScanMessage: BleScanInfo?发现设备(SPP 由门面包装 RSSI)
onDeviceConnectiondevice, way: Int, status: Int连接状态变化(way 区分 BLE/SPP)
onReceiveDatadevice, way: Int, uuid: UUID?, data: ByteArray?收到设备数据
onBleMtuChangedevice, mtu: Int, status: IntBLE MTU 协商结果

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

写入失败的三类场景

writeDataToDevice() 返回 false 的三种情况及其业务含义:

  1. 参数非法:device 为 null、byteArray 为 null 或空数组——调用方应先做非空校验;
  2. 双链路均未连接:设备既不在 BleManager.isConnectedDevice 也不在 SppManager.isSppConnected 中——表明连接已丢失,OTA 流程应进入重连或失败分支;
  3. 写回调 result=false:链路在但写入失败(如 MTU 不足、特征值不可写、远端断开)——异步回调中会打印设备信息与十六进制数据,便于定位。

配置与实况不一致

门面刻意区分"配置路由"与"实况探测":

  • 信任配置:扫描、连接、断开、状态查询按 ConfigHelper 分流;
  • 信任实况:写入按设备实际连接链路分流。

这种双轨策略避免了"配置为 BLE 但设备实际通过 SPP 连接"时写入丢失,是 OTA 双模设备场景下的关键容错设计。

并发与线程安全

  • 单例创建:@Volatile + synchronized 双重检查,保证多线程首次获取时只构造一次(见 BluetoothHelper.kt);
  • 回调列表遍历:CallbackRunnable 先 temp.addAll(callbacks) 快照再遍历,注册/注销并发修改不会抛 ConcurrentModificationException(见 BTEventCbHelper.kt)。注意快照意味着本次分发不包含分发过程中新注册的回调,这是可接受的最终一致性语义;
  • 主线程约束:事件必然在主线程回调,UI 更新安全;但业务层若在回调中执行耗时操作会阻塞主线程,OTA 大包解析应自行切线程。

边界情况

  • SPP 自定义通道过滤:开启多通道后,非 getCustomSppChannel() 的 UUID 连接事件被 return 丢弃;此时订阅者不会收到任何 SPP 连接通知——业务层需知道"无通知即非目标通道";
  • SPP 重连缺口:reconnectDevice() 在 SPP 分支中仅有 //TODO:需要增加SPP自定义回连方式 注释,即SPP 按地址重连当前未实现,仅 BLE 支持;
  • BR/EDR GATT 连接:GATT_OVER_BR_EDR 分支强制 TRANSPORT_BREDR 并要求最大 MTU,若设备不支持 BR/EDR GATT,连接会失败——这是配置与设备能力的契约,调用方应提供配置入口让用户切换。

性能与运维建议

  • 扫描超时:startScan(timeout) 由传输层管理超时自动停止,上层应配合 onDiscoveryChange(bStart=false) 刷新 UI,避免无限扫描耗电;
  • 日志辅助:门面在连接事件、读写回调中均打印设备信息与十六进制数据(printDeviceInfo / CHexConver.byte2HexStr),线上问题可通过 BluetoothHelper TAG 过滤日志;
  • MTU 协商:BLE 链路 MTU 通过 getBleMtu() 查询、onBleMtuChange 感知;大包写入前应确认 MTU,减少分包数可显著提升 OTA 吞吐;
  • 生命周期:页面销毁时应成对调用 unregisterCallback 与 destroy();destroy() 会置空单例,若后续仍使用需重新 getInstance(),注意避免在旧引用上操作。

扩展点

  1. 自定义连接参数:通过 BleConnectParam 链式 API(setRequestMtu、setTransport、TRANSPORT_BREDR)扩展 BLE 连接行为;如需新增传输类型,可在 connectDevice 的 when 分支中扩展;
  2. 新增事件类型:在 OnBTEventCallback 增加方法,并在 BTEventCbHelper 中按现有 callbackEvent(impl) 模式实现对应分发即可,分发基础设施(主线程 + 快照)无需改动;
  3. SPP 多通道:通过 ConfigHelper 的 isUseMultiSppChannel() / getCustomSppChannel() 控制通道过滤策略,未来可扩展为多通道白名单;
  4. SPP 自定义回连:reconnectDevice 的 TODO 位置是预留的扩展点,可在 SppManager 增加按地址重连 API 后在此接入。

相关链接

  • BluetoothHelper.kt(门面实现)
  • BTEventCbHelper.kt(事件分发实现)
  • 底层传输层:BleManager(com.jieli.otasdk.tool.ota.ble)与 SppManager(com.jieli.otasdk.tool.ota.spp)——BLE GATT 与 SPP 通道的扫描/连接/收发细节,见对应 OTA 传输文档
  • 配置来源:ConfigHelper(com.jieli.otasdk.tool.config)——连接方式、SPP 通道等配置项的读写
  • UI 层使用示例:BluetoothViewModel、BaseBluetoothFragment(com.jieli.otasdk.ui)——本门面的典型消费方
  • 公共常量:OtaConstant.PROTOCOL_BLE / PROTOCOL_SPP、BluetoothConstant.PROTOCOL_TYPE_SPP / GATT_OVER_BR_EDR / BLE_MTU_MAX
Prev
OTA 参数配置
Next
BLE 通道与事件回调