04-📝物联网组网 | DTBluetoothProvider概要设计文档
前言
基于上一篇文章 对 经典蓝牙、BLE等理论知识的 分享,在这篇文章我们进一步分享技术方案上的具体实现的设计内容。
基于概要设计可以选择对应不同类型的平台自己去实践详细设计与编码的部分
📋 项目概述
DTBluetoothProvider 是一个跨平台的高级蓝牙服务封装库,提供了完整的蓝牙设备管理解决方案。该库同时支持经典蓝牙(Classic Bluetooth)和低功耗蓝牙(BLE),支持多设备连接、智能指令管理、自动重连和数据包封装等核心功能。
设计目标:
- 提供统一的蓝牙设备管理接口,屏蔽不同平台的底层实现差异
- 支持多设备并发连接和管理
- 提供智能化的指令管理和自动重连机制
- 支持数据包封装和格式转换工具
- 具备良好的可扩展性和可维护性
🏗️ 架构设计思想
一、分层架构设计
项目采用清晰的分层架构,从业务层到底层实现,职责分明:
┌─────────────────────────────────────────┐
│ 业务层 (Business Layer) │
│ - BluetoothViewModel │
│ - 封装常用操作,集成所有工具 │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 服务层 (Service Layer) │
│ - BleServiceImpl │
│ - 多设备管理,连接重试 │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 底层实现层 (Implementation Layer) │
│ - DTBleCentralProviderInternal │
│ - DefaultBleCentralProvider │
│ - ClassicBluetoothProvider (经典蓝牙) │
│ - BleProvider (低功耗蓝牙) │
│ - 基于平台原生蓝牙 API │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 工具层 (Utility Layer) │
│ - BleCommandBuffer (指令缓冲) │
│ - DTDeviceBindingCache (绑定缓存) │
│ - DTReconnectionStateMachine (重连) │
│ - DTDataPacket (数据帧封装) │
│ - DTDataFormatConverter (数据格式转换) │
└─────────────────────────────────────────┘
设计优势
- 职责分离:每一层专注于自己的职责,降低耦合度
- 易于扩展:新功能可以在对应层级添加,不影响其他层
- 便于测试:各层可以独立测试,支持依赖注入
- 代码复用:工具层可以被多个业务场景复用
- 平台无关:通过接口抽象,底层实现可适配不同平台
二、核心设计模式
1. 单例模式 (Singleton Pattern)
应用场景:
-
DTDeviceBindingCache.getInstance()- 设备绑定缓存单例 - 确保全局唯一的设备绑定记录管理
设计意图:
- 保证设备绑定数据的一致性
- 简化跨模块访问
- 统一管理持久化存储
伪代码实现:
class DTDeviceBindingCache {
private static instance: DTDeviceBindingCache = null
synchronized static getInstance(): DTDeviceBindingCache {
if (instance == null) {
instance = new DTDeviceBindingCache()
}
return instance
}
}
2. 策略模式 (Strategy Pattern)
应用场景:
-
ReconnectionStrategy- 重连策略-
immediate- 立即重连 -
fixedDelay- 固定延迟 -
exponentialBackoff- 指数退避 -
custom- 自定义策略
-
设计意图:
- 灵活配置重连行为
- 支持运行时切换策略
- 易于扩展新的重连策略
伪代码实现:
interface ReconnectionStrategy {
calculateDelay(attempt: Integer): Long
}
class ImmediateStrategy implements ReconnectionStrategy {
calculateDelay(attempt: Integer): Long {
return 0
}
}
class FixedDelayStrategy implements ReconnectionStrategy {
private delay: Long
calculateDelay(attempt: Integer): Long {
return delay
}
}
class ExponentialBackoffStrategy implements ReconnectionStrategy {
private initialDelay: Long
private maxDelay: Long
calculateDelay(attempt: Integer): Long {
delay = initialDelay * (2 ^ attempt)
return min(delay, maxDelay)
}
}
3. 状态机模式 (State Machine Pattern)
应用场景:
-
DTReconnectionStateMachine- 重连状态机 -
DTBleCentralModeStateMachine- 连接状态机
状态流转:
idle → reconnecting → succeeded/failed/paused
设计意图:
- 清晰的状态管理
- 防止非法状态转换
- 便于状态追踪和调试
伪代码实现:
enum ReconnectionState {
Idle,
Reconnecting(attempt: Integer),
Succeeded,
Failed,
Paused
}
class DTReconnectionStateMachine {
private currentState: ReconnectionState = ReconnectionState.Idle
transitionTo(newState: ReconnectionState) {
if (isValidTransition(currentState, newState)) {
currentState = newState
} else {
throw InvalidStateTransitionException()
}
}
}
4. 观察者模式 (Observer Pattern)
应用场景:
- 回调机制:
onDiscoveredDevicesChanged、onConnectedDevicesChanged等 - 事件通知:蓝牙状态变化、连接状态变化
- 使用响应式编程框架实现数据流
设计意图:
- 解耦业务逻辑和 UI 层
- 支持多个观察者
- 实时响应状态变化
伪代码实现:
class BleServiceImpl {
private discoveredDevices: Observable<List<BluetoothDevice>>
private connectedDevices: Observable<List<BluetoothDevice>>
// 或者使用回调方式
onDiscoveredDevicesChanged: Callback<List<BluetoothDevice>>
onConnectedDevicesChanged: Callback<List<BluetoothDevice>>
// 通知观察者
notifyDevicesChanged(devices: List<BluetoothDevice>) {
discoveredDevices.emit(devices)
onDiscoveredDevicesChanged?.invoke(devices)
}
}
5. 工厂模式 (Factory Pattern)
应用场景:
-
BluetoothProviderFactory- 创建不同类型的 Provider -
DeviceConnectionContext- 根据 Channel 创建不同的上下文
设计意图:
- 统一创建逻辑
- 隐藏复杂的初始化过程
- 支持多设备类型扩展
伪代码实现:
class BluetoothProviderFactory {
createProvider(
type: BluetoothType,
platformContext: PlatformContext
): BluetoothProvider {
switch (type) {
case CLASSIC:
return new ClassicBluetoothProvider(platformContext)
case BLE:
return new BleProvider(platformContext)
default:
throw UnsupportedBluetoothTypeException()
}
}
}
6. 适配器模式 (Adapter Pattern)
应用场景:
-
BluetoothProvider统一接口,屏蔽经典蓝牙和 BLE 的差异 - 适配不同平台的蓝牙 API
设计意图:
- 统一接口抽象
- 屏蔽底层实现差异
- 简化业务层使用
三、经典蓝牙与 BLE 双模式支持
核心设计
DTBluetoothProvider 同时支持经典蓝牙(Classic Bluetooth)和低功耗蓝牙(BLE),通过统一的接口抽象,屏蔽底层实现差异:
-
经典蓝牙(Classic Bluetooth)
- 适用于大数据传输、音频传输等场景
- 支持 RFCOMM、L2CAP 等协议
- 连接方式:通过 UUID 或固定端口
-
低功耗蓝牙(BLE)
- 适用于低功耗、小数据传输场景
- 支持 GATT 服务和特征值操作
- 连接方式:通过 Service UUID 和 Characteristic UUID
统一接口抽象
interface BluetoothProvider {
// 扫描设备
scanDevices(
type: BluetoothType,
callback: Callback<List<BluetoothDevice>>
)
// 连接设备
connect(
device: BluetoothDevice,
type: BluetoothType
): Boolean
// 断开设备
disconnect(deviceAddress: String)
// 读取数据
readData(
deviceAddress: String,
characteristic: BluetoothCharacteristic
): ByteArray?
// 写入数据
writeData(
deviceAddress: String,
characteristic: BluetoothCharacteristic,
data: ByteArray
): Boolean
// 订阅通知
subscribeNotify(
deviceAddress: String,
characteristic: BluetoothCharacteristic,
callback: Callback<ByteArray>
)
}
enum BluetoothType {
CLASSIC, // 经典蓝牙
BLE // 低功耗蓝牙
}
// 统一的数据结构
union BluetoothCharacteristic {
// 经典蓝牙使用 UUID 或端口号
ClassicCharacteristic {
uuid: UUID?,
port: Integer?
},
// BLE 使用 Service UUID 和 Characteristic UUID
BleCharacteristic {
serviceUuid: UUID,
characteristicUuid: UUID
}
}
实现示例
// 经典蓝牙实现
class ClassicBluetoothProvider implements BluetoothProvider {
private connectedSockets: Map<String, BluetoothSocket>
connect(device: BluetoothDevice, type: BluetoothType): Boolean {
if (type != BluetoothType.CLASSIC) {
return false
}
try {
// 使用 RFCOMM 连接
socket = device.createRfcommSocket(uuid)
socket.connect()
connectedSockets[device.address] = socket
return true
} catch (Exception e) {
return false
}
}
writeData(deviceAddress: String, characteristic: BluetoothCharacteristic, data: ByteArray): Boolean {
socket = connectedSockets[deviceAddress]
if (socket == null) {
return false
}
try {
socket.outputStream.write(data)
return true
} catch (Exception e) {
return false
}
}
}
// BLE 实现
class BleProvider implements BluetoothProvider {
private connectedGatts: Map<String, BluetoothGatt>
connect(device: BluetoothDevice, type: BluetoothType): Boolean {
if (type != BluetoothType.BLE) {
return false
}
gatt = device.connectGatt(callback)
if (gatt.connectionState == CONNECTED) {
connectedGatts[device.address] = gatt
return true
}
return false
}
writeData(deviceAddress: String, characteristic: BluetoothCharacteristic, data: ByteArray): Boolean {
gatt = connectedGatts[deviceAddress]
if (gatt == null) {
return false
}
if (characteristic.type != BLE) {
return false
}
service = gatt.getService(characteristic.serviceUuid)
char = service.getCharacteristic(characteristic.characteristicUuid)
if (char != null) {
char.value = data
gatt.writeCharacteristic(char)
return true
}
return false
}
}
// 工厂类根据类型创建对应的 Provider
class BluetoothProviderFactory {
createProvider(type: BluetoothType, platformContext: PlatformContext): BluetoothProvider {
switch (type) {
case CLASSIC:
return new ClassicBluetoothProvider(platformContext)
case BLE:
return new BleProvider(platformContext)
}
}
}
设计优势
- ✅ 统一接口:经典蓝牙和 BLE 使用相同的接口,降低使用复杂度
- ✅ 自动适配:根据设备类型自动选择合适的实现
- ✅ 灵活切换:支持运行时切换不同的蓝牙类型
- ✅ 向后兼容:保持与现有代码的兼容性
- ✅ 平台无关:接口设计不依赖特定平台实现
四、多设备管理设计
核心概念
-
Channel(设备类型)
- 定义:设备类型枚举
- 作用:区分不同类型的蓝牙设备
- 示例:
_zdeer_ai_earphones、_tj_ej121
-
ChannelNumb(设备编号)
- 定义:同一类型设备的序号
- 作用:支持同时连接多个同类型设备
- 规则:从 0 开始递增
-
RealChannelValue(真实通道值)
- 格式:
"_" + channel.rawValue + "_" + channelNumb - 示例:
"_zdeer_ai_0"、"_zdeer_ai_1" - 作用:唯一标识一个设备连接上下文
- 格式:
设计优势
// 支持同时连接多个设备
viewModel.initDevice1() // Channel: _zdeer_ai_0
viewModel.initDevice2() // Channel: _zdeer_ai_1
// 每个设备独立的连接上下文
context1 = bleService.queryConnectionContext(device1.address)
context2 = bleService.queryConnectionContext(device2.address)
优势:
- ✅ 支持同时连接多个同类型设备
- ✅ 支持同时连接多个不同类型设备
- ✅ 每个设备独立的指令队列
- ✅ 线程安全的连接管理
五、指令缓冲工具设计
核心功能
BleCommandBuffer 实现了智能指令队列管理:
-
串行执行
- 确保指令按顺序发送
- 一个指令完成后再发送下一条
- 避免硬件处理冲突
-
智能去重
- 无参数指令(readData, subscribe_notifyData):自动忽略重复
- 有参数指令(writeData):可自定义比较逻辑
-
参数更新决策
- 通过
shouldUpdateCommand回调自定义 - 支持根据数据内部结构决定是否更新
- 通过
设计实现
// 指令唯一标识
abstract class BleCommand {
abstract uniqueKey: String
abstract isParameterless: Boolean
}
class ReadDataCommand extends BleCommand {
characteristicUuid: UUID
uniqueKey = "read_" + characteristicUuid
isParameterless = true
}
class WriteDataCommand extends BleCommand {
characteristicUuid: UUID
data: ByteArray
uniqueKey = "write_" + characteristicUuid
isParameterless = false
equals(other: Object): Boolean {
if (other is not WriteDataCommand) {
return false
}
return characteristicUuid == other.characteristicUuid &&
data.equals(other.data)
}
}
class SubscribeNotifyCommand extends BleCommand {
characteristicUuid: UUID
uniqueKey = "subscribe_" + characteristicUuid
isParameterless = true
}
// 智能去重逻辑
class BleCommandBuffer {
private commandQueues: Map<String, Queue<BleCommand>>
private shouldUpdateCommand: Callback<BleCommand, BleCommand, Boolean>
addCommand(command: BleCommand, deviceAddress: String): Boolean {
queue = commandQueues.getOrCreate(deviceAddress)
existingCommand = queue.find(command.uniqueKey)
if (existingCommand != null) {
if (command.isParameterless) {
// 无参数指令,直接忽略
return false
} else {
// 有参数指令,由业务层决定
shouldUpdate = shouldUpdateCommand?.invoke(existingCommand, command) ?? true
if (!shouldUpdate) {
return false
}
queue.remove(existingCommand)
}
}
queue.offer(command)
return true
}
}
设计优势:
- ✅ 防止指令冲突
- ✅ 减少不必要的网络请求
- ✅ 灵活的自定义策略
- ✅ 线程安全的队列管理
六、设备绑定缓存设计
核心功能
DTDeviceBindingCache 实现了设备绑定记录的持久化存储:
-
持久化存储
- JSON 格式保存到本地存储
- 应用启动时自动加载
- 操作后自动保存
-
绑定记录管理
- 保存设备信息(设备地址、名称、连接时间等)
- 记录连接次数和最后连接/断开时间
- 支持启用/禁用单个设备的自动重连
-
重连决策
-
shouldStartReconnection()方法根据绑定记录决定是否启动重连 - 检查是否有绑定记录
- 检查是否启用自动重连
-
数据结构
class DeviceBindingRecord {
deviceAddress: String // 设备地址
deviceName: String
bindingTime: Long // 首次绑定时间(时间戳)
lastConnectionTime: Long // 最后连接时间
lastDisconnectionTime: Long? // 最后断开时间
connectionCount: Integer = 0 // 连接次数
autoReconnectEnabled: Boolean = true // 是否启用自动重连
channel: String? // 设备类型
metadata: Map<String, String>? // 自定义元数据
toJson(): String {
return JSON.serialize(this)
}
static fromJson(json: String): DeviceBindingRecord? {
return JSON.deserialize(json, DeviceBindingRecord)
}
}
class DTDeviceBindingCache {
private static instance: DTDeviceBindingCache = null
private bindingRecords: Map<String, DeviceBindingRecord>
private storage: LocalStorage
static getInstance(): DTDeviceBindingCache {
if (instance == null) {
instance = new DTDeviceBindingCache()
}
return instance
}
init() {
loadFromStorage()
}
saveBinding(
device: BluetoothDevice,
channel: String? = null,
autoReconnectEnabled: Boolean = true
) {
record = bindingRecords[device.address]?.copy(
lastConnectionTime = currentTime(),
connectionCount = connectionCount + 1,
autoReconnectEnabled = autoReconnectEnabled
) ?? new DeviceBindingRecord(
deviceAddress = device.address,
deviceName = device.name ?? "Unknown",
bindingTime = currentTime(),
lastConnectionTime = currentTime(),
connectionCount = 1,
autoReconnectEnabled = autoReconnectEnabled,
channel = channel
)
bindingRecords[device.address] = record
saveToStorage()
}
shouldStartReconnection(deviceAddress: String): Boolean {
record = bindingRecords[deviceAddress]
if (record == null) {
return false
}
return record.autoReconnectEnabled
}
private loadFromStorage() {
json = storage.getString("binding_records")
if (json != null) {
bindingRecords = JSON.deserialize(json, Map<String, DeviceBindingRecord>)
}
}
private saveToStorage() {
json = JSON.serialize(bindingRecords)
storage.putString("binding_records", json)
}
}
设计优势:
- ✅ 持久化存储,应用重启后仍可恢复
- ✅ 智能决策,避免不必要的重连
- ✅ 线程安全,支持并发访问
- ✅ 灵活配置,支持自定义元数据
- ✅ 平台无关,使用通用的本地存储接口
七、重连状态机设计
核心功能
DTReconnectionStateMachine 管理设备断开后的重连逻辑:
-
状态管理
-
idle- 空闲状态 -
reconnecting- 正在重连中 -
paused- 暂停重连 -
failed- 重连失败 -
succeeded- 重连成功
-
-
重连策略
-
immediate- 立即重连 -
fixedDelay- 固定延迟 -
exponentialBackoff- 指数退避 -
custom- 自定义策略
-
-
配置选项
- 最大重试次数
- 连接超时时间
- 蓝牙关闭时暂停
- 应用进入后台时暂停
- 冷却期机制
状态流转图
[idle]
│
│ startReconnection()
▼
[reconnecting]
│
├─→ notifyConnectionSucceeded() → [succeeded] → [idle]
│
├─→ pauseReconnection() → [paused]
│ │
│ │ resumeReconnection()
│ └─→ [reconnecting]
│
└─→ maxRetries reached → [failed] → [idle]
伪代码实现:
class DTReconnectionStateMachine {
private strategy: ReconnectionStrategy
private maxRetries: Integer = 5
private connectionTimeout: Long = 30000
private currentState: ReconnectionState = ReconnectionState.Idle
private retryCount: Integer = 0
private reconnectionTask: Task = null
private stateObservable: Observable<ReconnectionState>
startReconnection(
deviceAddress: String,
connectFunction: Function<String, Boolean>
) {
if (currentState != ReconnectionState.Idle) {
return
}
currentState = ReconnectionState.Reconnecting(0)
stateObservable.emit(currentState)
retryCount = 0
reconnectionTask = async {
while (retryCount < maxRetries &&
currentState is ReconnectionState.Reconnecting) {
delay = strategy.calculateDelay(retryCount)
if (delay > 0) {
sleep(delay)
}
try {
success = timeout(connectionTimeout) {
connectFunction(deviceAddress)
}
if (success) {
currentState = ReconnectionState.Succeeded
stateObservable.emit(currentState)
currentState = ReconnectionState.Idle
stateObservable.emit(currentState)
return
} else {
retryCount++
currentState = ReconnectionState.Reconnecting(retryCount)
stateObservable.emit(currentState)
}
} catch (TimeoutException e) {
retryCount++
currentState = ReconnectionState.Reconnecting(retryCount)
stateObservable.emit(currentState)
} catch (Exception e) {
retryCount++
currentState = ReconnectionState.Reconnecting(retryCount)
stateObservable.emit(currentState)
}
}
if (retryCount >= maxRetries) {
currentState = ReconnectionState.Failed
stateObservable.emit(currentState)
currentState = ReconnectionState.Idle
stateObservable.emit(currentState)
}
}
}
pauseReconnection() {
if (currentState is ReconnectionState.Reconnecting) {
reconnectionTask?.cancel()
currentState = ReconnectionState.Paused
stateObservable.emit(currentState)
}
}
resumeReconnection(deviceAddress: String, connectFunction: Function<String, Boolean>) {
if (currentState is ReconnectionState.Paused) {
startReconnection(deviceAddress, connectFunction)
}
}
stopReconnection() {
reconnectionTask?.cancel()
currentState = ReconnectionState.Idle
stateObservable.emit(currentState)
retryCount = 0
}
}
设计优势:
- ✅ 清晰的状态管理
- ✅ 灵活的重连策略
- ✅ 支持暂停和恢复
- ✅ 完善的错误处理
- ✅ 平台无关的异步实现
八、数据包封装设计
核心功能
DTDataPacket 用于包装和解析硬件数据:
-
数据包构建
- 从命令类型和载荷构建数据包
- 支持多种格式:默认、带帧头、带长度、完整格式
- 自动计算长度和校验和
-
数据包解析
- 从原始字节数组解析数据包
- 支持多种格式的自动识别和解析
- 提取帧头、命令类型、载荷、校验和、帧尾等
-
支持的格式
- 默认格式:命令类型 + 载荷
- 带帧头格式:帧头 + 命令类型 + 载荷
- 带长度格式:帧头 + 长度 + 命令类型 + 载荷
- 完整格式:帧头 + 长度 + 命令类型 + 载荷 + 校验和 + 帧尾
设计实现
class DTDataPacket {
frameHeader: Byte? = null
length: Integer? = null
commandType: Byte
payload: ByteArray
checksum: Byte? = null
frameTail: Byte? = null
private static DEFAULT_FRAME_HEADER: Byte = 0xAA
private static DEFAULT_FRAME_TAIL: Byte = 0x55
static forBluetoothSend(
commandType: Byte,
payload: ByteArray,
format: PacketFormat = PacketFormat.DEFAULT
): DTDataPacket {
switch (format) {
case DEFAULT:
return new DTDataPacket(
commandType = commandType,
payload = payload
)
case WITH_HEADER:
return new DTDataPacket(
frameHeader = DEFAULT_FRAME_HEADER,
commandType = commandType,
payload = payload
)
case WITH_LENGTH:
return new DTDataPacket(
frameHeader = DEFAULT_FRAME_HEADER,
length = payload.length + 1, // +1 for commandType
commandType = commandType,
payload = payload
)
case FULL:
data = [commandType] + payload
checksum = calculateChecksum(data)
return new DTDataPacket(
frameHeader = DEFAULT_FRAME_HEADER,
length = data.length,
commandType = commandType,
payload = payload,
checksum = checksum,
frameTail = DEFAULT_FRAME_TAIL
)
}
}
static fromBluetoothData(data: ByteArray): DTDataPacket? {
try {
// 根据数据格式自动识别并解析
if (data.length >= 2 &&
data[0] == DEFAULT_FRAME_HEADER &&
data[data.length - 1] == DEFAULT_FRAME_TAIL) {
// 完整格式
length = data[1] & 0xFF
commandType = data[2]
payload = data[3..(3 + length - 1)]
checksum = data[data.length - 2]
return new DTDataPacket(
frameHeader = data[0],
length = length,
commandType = commandType,
payload = payload,
checksum = checksum,
frameTail = data[data.length - 1]
)
}
// 其他格式的解析...
return null
} catch (Exception e) {
return null
}
}
private static calculateChecksum(data: ByteArray): Byte {
sum = 0
for (byte in data) {
sum += byte & 0xFF
}
return (sum & 0xFF) as Byte
}
toByteArray(): ByteArray {
result = []
if (frameHeader != null) {
result.add(frameHeader)
}
if (length != null) {
result.add(length as Byte)
}
result.add(commandType)
result.addAll(payload)
if (checksum != null) {
result.add(checksum)
}
if (frameTail != null) {
result.add(frameTail)
}
return result
}
verifyChecksum(): Boolean {
if (checksum == null) {
return true
}
data = [commandType] + payload
calculatedChecksum = calculateChecksum(data)
return checksum == calculatedChecksum
}
}
enum PacketFormat {
DEFAULT,
WITH_HEADER,
WITH_LENGTH,
FULL
}
设计优势:
- ✅ 统一的数据包格式
- ✅ 自动校验和验证
- ✅ 便捷的数据访问方法
- ✅ 支持多种硬件协议格式
- ✅ 平台无关的实现
九、系统要求与平台适配
平台适配要求
DTBluetoothProvider 设计为跨平台库,需要各平台实现以下接口:
-
蓝牙适配器接口
- 检查蓝牙是否支持
- 检查蓝牙是否启用
- 启用蓝牙(需要用户授权)
-
权限管理接口
- 检查权限是否授予
- 请求权限
- 处理权限回调
-
本地存储接口
- 保存字符串数据
- 读取字符串数据
- 删除数据
-
异步执行接口
- 异步任务执行
- 延迟执行
- 超时控制
-
响应式编程接口
- 可观察对象(Observable)
- 数据流(Stream/Flow)
- 订阅和取消订阅
平台实现要求
| 平台 | 蓝牙 API | 异步框架 | 存储方案 | 响应式框架 |
|---|---|---|---|---|
| Android | BluetoothAdapter / BluetoothGatt | Coroutines | SharedPreferences / Room | Flow / LiveData |
| iOS | CoreBluetooth | DispatchQueue / Combine | UserDefaults / CoreData | Combine |
| HarmonyOS | @ohos.bluetoothManager | Promise / async/await | dataPreferences | Emitter |
| Flutter | flutter_blue | Future / async/await | SharedPreferences | Stream |
系统要求
各平台需要满足以下最低要求:
- 蓝牙硬件支持:设备必须支持蓝牙功能
- 权限支持:平台必须支持蓝牙权限管理
- 异步支持:平台必须支持异步编程模型
- 存储支持:平台必须提供本地持久化存储方案
📐 项目结构
DTBluetoothProvider/
├── Business/ # 业务层
│ └── BluetoothViewModel # 业务逻辑封装
│
├── Service/ # 服务层
│ └── BleServiceImpl # 服务层实现
│
├── Implementation/ # 实现层
│ ├── BluetoothProvider # 统一接口
│ ├── ClassicBluetoothProvider # 经典蓝牙实现
│ ├── BleProvider # BLE 实现
│ └── PlatformAdapter/ # 平台适配器
│ ├── Android/ # Android 平台实现
│ ├── iOS/ # iOS 平台实现
│ ├── HarmonyOS/ # HarmonyOS 平台实现
│ └── Flutter/ # Flutter 平台实现
│
└── Utility/ # 工具层
├── BleCommandBuffer # 指令缓冲工具
├── DTDeviceBindingCache # 设备绑定缓存
├── DTReconnectionStateMachine # 重连状态机
├── DTDataPacket # 数据包封装
└── DTDataFormatConverter # 数据格式转换工具
二、核心类说明
1. BluetoothViewModel - 业务逻辑层
职责:
- 封装常用的蓝牙操作(扫描、连接、读写等)
- 集成指令缓冲工具、设备绑定缓存、重连状态机
- 管理设备列表和选中状态
- 提供响应式数据流供 UI 层观察
主要方法:
-
initDevice1()/initDevice2()- 初始化设备连接上下文 -
startScan()/stopScan()- 扫描管理 -
connect(device:)/disconnect(device:)- 连接管理 -
readData(characteristic:)/writeData(characteristic:data:)- 数据操作(自动使用指令缓冲)
伪代码实现:
class BluetoothViewModel {
private bleService: BleServiceImpl
private bindingCache: DTDeviceBindingCache
private discoveredDevices: Observable<List<BluetoothDevice>>
private connectionState: Observable<ConnectionState>
startScan() {
async {
bleService.startScan { devices ->
discoveredDevices.emit(devices)
}
}
}
connect(device: BluetoothDevice) {
async {
connectionState.emit(ConnectionState.Connecting)
success = bleService.connect(device)
connectionState.emit(
success ? ConnectionState.Connected : ConnectionState.Disconnected
)
}
}
}
2. BleServiceImpl - 服务层
职责:
- 管理多个设备的连接上下文
- 提供线程安全的连接管理
- 支持连接重试机制
- 处理底层回调并转发给业务层
核心特性:
- 多设备连接管理(通过 Channel 和 channelNumb 区分)
- 连接重试机制(支持指数退避)
- 线程安全的连接上下文管理
伪代码实现:
class BleServiceImpl {
private provider: BluetoothProvider
private connectionContexts: ConcurrentMap<String, DeviceConnectionContext>
private reconnectionStateMachines: ConcurrentMap<String, DTReconnectionStateMachine>
connect(device: BluetoothDevice, channel: String? = null): Boolean {
context = new DeviceConnectionContext(device, channel)
connectionContexts[device.address] = context
try {
return provider.connect(device.address)
} catch (Exception e) {
startReconnection(device.address)
return false
}
}
queryConnectionContext(deviceAddress: String): DeviceConnectionContext? {
return connectionContexts[deviceAddress]
}
}
3. BleCommandBuffer - 指令缓冲工具
职责:
- 管理指令队列,实现串行发送
- 智能去重和参数更新决策
- 每个设备独立的指令队列
核心方法:
-
addCommand(command:for:)- 添加指令到队列 -
shouldUpdateCommand- 自定义指令更新策略 -
clearCommands(for:)- 清空指定设备的指令队列
4. DTDeviceBindingCache - 设备绑定缓存
职责:
- 持久化存储设备绑定记录
- 根据绑定记录决策是否启动重连
- 单例模式,全局共享
核心方法:
-
saveBinding(device:channel:autoReconnectEnabled:)- 保存绑定记录 -
shouldStartReconnection(for:)- 决策是否启动重连 -
setAutoReconnectEnabled(enabled:for:)- 启用/禁用自动重连
5. DTReconnectionStateMachine - 重连状态机
职责:
- 管理设备断开后的重连逻辑
- 支持多种重连策略
- 状态机管理重连流程
核心方法:
-
startReconnection(deviceAddress:connectFunction:)- 开始重连 -
pauseReconnection()/resumeReconnection()- 暂停/恢复重连 -
stopReconnection()- 停止重连
6. DTDataPacket - 数据帧封装
职责:
- 包装和解析硬件数据
- 支持多种数据包格式
- 校验和验证
核心方法:
-
forBluetoothSend(commandType:payload:format:)- 创建数据包 -
fromBluetoothData(data:)- 解析数据包 -
verifyChecksum()- 验证校验和
三、设计模式应用
| 设计模式 | 应用场景 | 优势 |
|---|---|---|
| 单例模式 | DTDeviceBindingCache.getInstance() | 全局唯一,数据一致性 |
| 策略模式 | ReconnectionStrategy | 灵活配置,易于扩展 |
| 状态机模式 | DTReconnectionStateMachine | 清晰的状态管理 |
| 观察者模式 | Observable / Stream / Flow | 解耦业务和 UI |
| 工厂模式 | BluetoothProviderFactory | 统一创建逻辑 |
| 适配器模式 | BluetoothProvider / PlatformAdapter | 屏蔽平台差异 |
四、线程安全设计
并发控制策略
-
异步执行框架
class BleServiceImpl { private asyncExecutor: AsyncExecutor connect(device: BluetoothDevice): Boolean { return asyncExecutor.execute { // 连接操作 } } } -
并发集合
connectionContexts: ConcurrentMap<String, DeviceConnectionContext> commandQueues: ConcurrentMap<String, Queue<BleCommand>> -
互斥锁
private mutex: Mutex updateState() { mutex.lock() try { // 写操作,确保线程安全 } finally { mutex.unlock() } }
应用场景:
-
BleServiceImpl- 连接上下文管理 -
BleCommandBuffer- 指令队列管理 -
DTDeviceBindingCache- 绑定记录管理
五、错误处理机制
错误类型定义
enum DTBluetoothError {
DeviceNotConnected,
DeviceNotFound,
CharacteristicNotFound,
ConnectionTimeout,
ConnectionFailed,
DataTransmissionFailed,
MtuExceeded,
BluetoothUnauthorized,
BluetoothPoweredOff,
UnknownError(cause: Exception)
}
错误处理策略
-
Result 类型返回
trigger( event: TriggerEvent, device: BluetoothDevice ): Result<Unit, DTBluetoothError> -
异常传播
connect(device: BluetoothDevice): Boolean { try { return provider.connect(device.address) } catch (Exception e) { handleError(e) return false } } -
响应式错误处理
connectionState: Observable<ConnectionState> { onError { error -> emit(ConnectionState.Error(convertToBluetoothError(error))) } }
🎯 设计亮点总结
1. 多设备管理能力
- ✅ 支持同时连接多个同类型设备(通过 channelNumb 区分)
- ✅ 支持同时连接多个不同类型设备(通过 Channel 区分)
- ✅ 每个设备独立的连接上下文和指令队列
2. 智能指令管理
- ✅ 串行执行,避免硬件冲突
- ✅ 智能去重,减少不必要的请求
- ✅ 灵活的参数更新策略
3. 持久化存储
- ✅ 设备绑定记录持久化(平台无关的存储接口)
- ✅ 应用重启后自动恢复
- ✅ 智能重连决策
4. 灵活的重连策略
- ✅ 多种重连策略可选
- ✅ 状态机管理重连流程
- ✅ 支持暂停和恢复
5. 完善的错误处理
- ✅ 详细的错误类型定义
- ✅ Result 类型返回
- ✅ 统一的错误转换机制
6. 线程安全设计
- ✅ 异步执行框架实现异步操作
- ✅ 并发集合保护共享资源
- ✅ 互斥锁确保写安全
7. 清晰的架构分层
- ✅ 业务层、服务层、实现层分离
- ✅ 工具层可复用
- ✅ 易于扩展和维护
8. 响应式编程
- ✅ 使用响应式编程框架实现数据流
- ✅ 支持多种观察者模式实现
- ✅ 自动处理生命周期
9. 经典蓝牙与 BLE 双模式支持
- ✅ 统一接口抽象,屏蔽底层差异
- ✅ 支持经典蓝牙(RFCOMM、L2CAP)
- ✅ 支持低功耗蓝牙(GATT)
- ✅ 根据设备类型自动选择合适的实现
- ✅ 平台无关的设计
10. 跨平台支持
- ✅ 统一的接口设计,适配不同平台
- ✅ 平台适配层隔离平台差异
- ✅ 核心逻辑与平台实现分离
📚 技术栈
核心设计
- 架构模式:分层架构、MVVM
- 设计模式:单例、策略、状态机、观察者、工厂、适配器
- 并发模型:异步编程、响应式编程
- 数据存储:本地持久化存储(平台无关接口)
平台适配
各平台需要实现以下接口:
- 蓝牙适配器接口:扫描、连接、读写等蓝牙操作
- 权限管理接口:权限检查、请求、回调
- 本地存储接口:数据持久化
- 异步执行接口:异步任务、延迟、超时
- 响应式编程接口:可观察对象、数据流
🔍 代码质量特点
- 注释完善:关键类和方法都有详细注释
- 命名规范:遵循平台命名规范
- 类型安全:充分利用类型系统
- 错误处理:完善的错误处理机制
- 线程安全:关键操作都有线程保护
- 可测试性:支持依赖注入,便于单元测试
- 平台无关:核心逻辑不依赖特定平台
💡 设计思想总结
DTBluetoothProvider 的设计体现了以下核心思想:
- 分层架构:清晰的职责分离,便于维护和扩展
- 多设备支持:通过 Channel 和 channelNumb 实现灵活的多设备管理
- 智能管理:指令缓冲、设备绑定、自动重连等智能化功能
- 线程安全:完善的并发控制,确保数据一致性
- 可扩展性:策略模式、工厂模式等设计模式支持灵活扩展
- 用户体验:自动重连、持久化存储等功能提升用户体验
- 响应式编程:使用响应式编程框架实现现代化的数据流
- 平台无关:核心设计不依赖特定平台,通过适配层实现跨平台
- 双模式支持:同时支持经典蓝牙和 BLE,使用统一接口抽象
这是一个企业级的蓝牙管理解决方案,设计思路清晰,代码质量高,具有很强的实用性和可维护性。通过统一的接口设计和平台适配层,可以在多个平台上实现一致的架构和功能。
🔄 跨平台实现对比
| 特性 | Android | iOS | HarmonyOS | Flutter |
|---|---|---|---|---|
| 异步处理 | Coroutines | DispatchQueue / Combine | Promise / async/await | Future / async/await |
| 观察者模式 | Flow / LiveData | Combine | Emitter | Stream |
| 持久化 | SharedPreferences / Room | UserDefaults / CoreData | dataPreferences | SharedPreferences |
| 设备标识 | MAC Address | UUID | MAC Address | UUID |
| 蓝牙框架 | BluetoothAdapter / BluetoothGatt | CoreBluetooth | @ohos.bluetoothManager | flutter_blue |
| 蓝牙类型 | 经典蓝牙 + BLE | BLE only | BLE | BLE |
| 单例实现 | object / getInstance() | static let shared | 单例模式 | 单例模式 |
| 状态管理 | Sealed Class | 枚举 + 结构体 | 枚举 | 枚举 |
📖 使用示例
基本使用
// 1. 初始化 ViewModel
viewModel = new BluetoothViewModel(
bleService = new BleServiceImpl(platformContext, provider),
bindingCache = DTDeviceBindingCache.getInstance()
)
// 2. 观察设备列表
viewModel.discoveredDevices.subscribe { devices ->
// 更新 UI
}
// 3. 开始扫描
viewModel.startScan()
// 4. 连接设备
viewModel.connect(device)
// 5. 发送数据
packet = DTDataPacket.forBluetoothSend(
commandType = 0x10,
payload = [50],
format = PacketFormat.FULL
)
viewModel.writeData(characteristicUuid, packet.toByteArray())
多设备管理
// 连接多个同类型设备
viewModel.initDevice1() // Channel: _zdeer_ai_0
viewModel.initDevice2() // Channel: _zdeer_ai_1
// 每个设备独立的操作
viewModel.writeData(device1Address, data1)
viewModel.writeData(device2Address, data2)
自定义重连策略
strategy = new ExponentialBackoffStrategy(
initialDelay = 1000,
maxDelay = 30000
)
stateMachine = new DTReconnectionStateMachine(
strategy = strategy,
maxRetries = 5
)
经典蓝牙与 BLE 使用
// 1. 创建 Provider(根据设备类型选择)
classicProvider = BluetoothProviderFactory.createProvider(
BluetoothType.CLASSIC,
platformContext
)
bleProvider = BluetoothProviderFactory.createProvider(
BluetoothType.BLE,
platformContext
)
// 2. 扫描设备
classicProvider.scanDevices(BluetoothType.CLASSIC) { devices ->
// 处理经典蓝牙设备
}
bleProvider.scanDevices(BluetoothType.BLE) { devices ->
// 处理 BLE 设备
}
// 3. 连接并操作
// 经典蓝牙
classicChar = new ClassicCharacteristic(
uuid = "00001101-0000-1000-8000-00805F9B34FB"
)
classicProvider.connect(device, BluetoothType.CLASSIC)
classicProvider.writeData(device.address, classicChar, data)
// BLE
bleChar = new BleCharacteristic(
serviceUuid = "0000180f-0000-1000-8000-00805f9b34fb",
characteristicUuid = "00002a19-0000-1000-8000-00805f9b34fb"
)
bleProvider.connect(device, BluetoothType.BLE)
bleProvider.writeData(device.address, bleChar, data)
🚀 未来扩展方向
- 支持更多蓝牙协议:BLE Mesh、蓝牙音频(A2DP、HFP)等
- 性能优化:连接池管理、数据压缩、MTU 协商优化等
- 监控和日志:详细的性能监控和日志系统
- 单元测试:完善的单元测试覆盖
- 文档完善:API 文档和使用指南
- 更多平台支持:Web Bluetooth、Windows、macOS 等
📝 总结
本文档详细介绍了 DTBluetoothProvider 的概要设计,主要特点包括:
- 平台无关设计:通过接口抽象和适配层,实现跨平台支持
- 双模式支持:同时支持经典蓝牙和低功耗蓝牙(BLE)
- 统一接口抽象:通过接口设计屏蔽底层实现差异
- 企业级架构:清晰的分层设计,易于维护和扩展
- 完善的工具支持:指令缓冲、设备绑定、自动重连、数据包封装等
通过统一的架构设计和平台适配层,可以在多个平台上实现一致的蓝牙管理功能,是一个企业级的跨平台蓝牙管理解决方案。
本文档描述了 DTBluetoothProvider 的概要设计,核心逻辑与平台实现分离,通过适配层支持不同平台的蓝牙 API。各平台实现需要遵循本文档定义的接口和架构设计。