基类管理器与常量体系
本文档介绍 JieLi_Home 项目中支撑整个 App 架构的两大基础体系:lib/constant/ 下的常量体系(AppConstants、BleMethodConstants、BleEventConstants)与 lib/manager/ 下的管理器体系(一组 Ble*Manager 静态方法类)。它们是页面层与底层 JL BLE SDK 之间的桥梁,定义了全局配置值、连接状态机语义、BLE 指令方法名与事件名,以及所有 BLE 业务操作的统一调用入口。
Purpose and Scope
本页覆盖以下内容:
- 常量体系的设计意图与分类:应用级常量(
AppConstants)、BLE 方法常量(BleMethodConstants)、BLE 事件常量(BleEventConstants); - 管理器体系的统一模式:为何采用"纯静态方法类"而非继承式基类(源码中未发现
BaseManager显式基类,统一模式即事实上的"基类约定"); - 代表性管理器(
BleConnectionManager、BleConfigManager、BleCustomCmdManager、BleEqManager等)的职责划分; - 页面 → 管理器 → BLE SDK → 设备的端到端控制流;
- 常量表的完整清单、管理器的 API 形态、失败模式与扩展点。
以下主题属于相邻页面,不在本页展开:BLE 协议栈底层实现、具体设备功能的协议细节(如 EQ、闹钟、AuraCast 各自的指令编码)、UI 页面布局与状态管理(Provider/Bloc)、OTA 升级流程。若目录中存在对应页面,请优先参阅那些页面。
Overview
为什么需要"常量 + 管理器"双体系
JL 智能硬件 App 需要与多种蓝牙耳机/音箱设备通信。底层 SDK 暴露的是字节级 BLE 指令通道,而业务层需要的是语义化的操作("获取 EQ 数据"、"设置闹钟"、"进入充电盒消息页")。为了在这两层之间建立稳定契约,项目引入了两个基础设施:
- 常量体系把魔法字符串/魔法数字集中管理,避免散落各处导致不一致。例如连接状态用
0/1/2/3表示,通信方式用'BLE'/'SPP'表示——这些语义都收敛在AppConstants中。 - 管理器体系把每一类设备能力封装为独立的管理器类,页面只依赖管理器的方法签名,不接触 SDK 细节。所有管理器统一采用静态方法类模式(见下文分析),这构成了项目事实上的"基类约定"。
关键概念
| 概念 | 说明 |
|---|---|
AppConstants | 应用级全局常量(URL、连接状态、UI 尺寸、推送开关键名、语言键名等) |
BleMethodConstants | BLE 指令方法名常量(管理器构造指令时引用) |
BleEventConstants | BLE 事件名常量(SDK 回调 → 页面分发时引用) |
Ble*Manager | 静态方法类,按设备功能域划分(连接、信息、EQ、闹钟、音乐、设置等) |
| 静态方法类模式 | 所有管理器不持有实例状态,通过 static Future<...> 方法提供能力 |
Architecture
flowchart TD
subgraph sg_UI["页面与业务层 (lib/pages, lib/widgets)"]
Page["页面 / Dialog / Widget"]
end
subgraph sg_Manager["管理器体系 (lib/manager)"]
Conn["BleConnectionManager"]
Info["BleDeviceInfoManager"]
Config["BleConfigManager"]
Music["BleDeviceMusicManager"]
EQ["BleEqManager"]
Others["BleAlarmManager / BleCustomCmdManager / BleDeviceSettingManager / ..."]
end
subgraph sg_Constant["常量体系 (lib/constant)"]
App["AppConstants"]
Method["BleMethodConstants"]
Event["BleEventConstants"]
end
subgraph sg_SDK["JL BLE SDK 层"]
Sdk["BLE 协议栈 / 设备连接通道"]
Device["硬件设备"]
end
Page --> Conn
Page --> Info
Page --> Config
Page --> Music
Page --> EQ
Page --> Others
Conn --> App
Info --> App
Config --> App
Music --> Method
EQ --> Method
Others --> Method
Method --> Sdk
Sdk --> Event
Event --> Page
Sdk --> Device
架构说明:
- 页面层只面向管理器,不直接拼装 BLE 指令。这保证了业务代码的可读性与可替换性——即使底层 SDK 更换,页面的调用代码不变。
- 管理器层是唯一允许触碰
BleMethodConstants的层:每个管理器的静态方法内部把业务参数编码为指令数据,再交给 BLE SDK 发送。 - 常量体系是"读多写少"的共享契约:
AppConstants供全 App 使用(含页面 UI 与存储键名),BleMethodConstants供管理器使用,BleEventConstants则承载 SDK 上行事件名,页面据此分发回调。 - 分层方向是单向的:页面 → 管理器 → SDK → 设备;事件反向:设备 → SDK → 页面。常量层被各层读取,但不反向依赖任何业务代码。
该设计把"易变的设备协议细节"隔离在管理器内部,把"稳定的全局语义"收敛到常量类,是典型的分层 + 单一职责组合,适合多设备型号共存的场景。
常量体系详解(lib/constant)
lib/constant/ 目录下有三个文件,分别承载不同粒度的常量:constants.dart(应用级)、ble_method_constants.dart(BLE 指令方法名)、ble_event_constants.dart(BLE 事件名)。它们的共同特征是:全部为 static const,编译期确定、零运行时开销,且集中在单一文件中便于全局审计。
AppConstants:应用级常量
AppConstants 定义在 constants.dart,把散落在各处的魔法值收敛为带文档注释的命名常量。按其语义可划分为以下几组:
1) 法务与协议 URL
/// User agreement URL for the application
static const String userAgreementUrl = 'https://cam.jieliapp.com/app/app.user.service.protocol.html';
/// Privacy policy URL for the application
static const String privacyPolicyUrl = 'https://cam.jieliapp.com/app/JL_OTA_app_privacy_policy.html';
/// Icp number
static const String icpNumber = '粤ICP备18069041号-15A';
/// Icp url
static const String icpUrl = 'https://beian.miit.gov.cn/';
Source: constants.dart
2) 通信方式标识:'BLE' 与 'SPP' 两个字符串常量,用于标识设备当前采用的通信通道,避免在多处硬编码字符串导致拼写不一致:
/// Constant representing BLE communication method
static const String communicationWayBle = 'BLE';
/// Constant representing SPP communication method
static const String communicationWaySpp = 'SPP';
Source: constants.dart
3) 连接状态机语义:用整数表达 BLE 连接的五个状态。状态值从 -1 到 3,语义清晰且与 SDK 层约定一致:
/// Connection state: Default value
static const int connectDefaultState = -1;
/// Connection state: Disconnected
static const int connectionDisconnect = 0;
/// Connection state: Successfully connected
static const int connectionOK = 1;
/// Connection state: Connection failed
static const int connectionFailed = 2;
/// Connection state: Currently connecting
static const int connectionConnecting = 3;
Source: constants.dart
把状态集中定义的意义在于:连接状态会在"设备列表页、连接管理器、SDK 回调、全局状态管理"多处流转,若不统一,0 究竟表示"断开"还是"默认值"极易产生歧义。这里用 connectDefaultState = -1 明确区分"尚未初始化"与"已断开"两种语义,是避免状态机误判的关键设计。
4) UI 尺寸与平台阈值:dialogButtonHeight = 45.0、returnIconSizeValue = 28.0 统一对话框按钮高度与返回图标尺寸;tiramisu = 33 标记 Android 13 的 API level,供权限/行为分支判断使用。
5) 存储键名与推送开关:agreePolicy、filterContent、otaPath、storageStatus、updateFileName(默认 'upgrade.ufw')等键名用于本地存储与 OTA 文件操作;messagePushEnabled、messagePushSmsState、messagePushWechatState 等一组常量对应消息推送各渠道的开关状态键,配套的 keyAppSms/keyAppWechat/keyAppQQ/keyAppDingTalk/keyAppLark 标识各 App 的存储键。这类键名若在读写处各自硬编码,一旦改名会静默丢失用户设置,集中定义即为此服务。
6) 语言键名:keyLanguageChinese = 'zh'、keyLanguageEnglish = 'en'、keyLanguageJapanese = 'ja' 等,与 App 多语言支持联动。
BleMethodConstants:BLE 指令方法名
ble_method_constants.dart 与 ble_event_constants.dart 是 BLE 协议侧的专属常量文件,与管理器体系一一对应:管理器在构造指令时引用方法名常量,SDK 上行事件通过事件名常量回传。详细枚举项未在本页读取预算内逐条展开,直接查阅源文件即可获得完整清单;其存在本身印证了"管理器引用方法名、页面引用事件名"的分层契约。
常量体系关系图
classDiagram
class AppConstants {
+static const String userAgreementUrl
+static const String communicationWayBle
+static const String communicationWaySpp
+static const int connectDefaultState
+static const int connectionDisconnect
+static const int connectionOK
+static const int connectionFailed
+static const int connectionConnecting
+static const int tiramisu
+static const double dialogButtonHeight
+static const double returnIconSizeValue
+static const String messagePushEnabled
+static const String keyLanguageChinese
}
class BleMethodConstants {
+static const ... BLE 指令方法名
}
class BleEventConstants {
+static const ... BLE 上行事件名
}
BleMethodConstants --> AppConstants : 同目录、供管理器引用
BleEventConstants --> AppConstants : 同目录、供页面分发引用
设计意图:一个常量类不足以承载所有语义。AppConstants 面向全 App(含 UI 与存储),BleMethodConstants 面向管理器(指令编码),BleEventConstants 面向事件分发(SDK 回调)。三者按"使用者"切分,避免单个巨型常量类被无关页面误引,也让 BLE 协议相关常量可以整体替换(例如适配新 SDK 时只需改常量映射层)。
管理器体系详解(lib/manager)
lib/manager/ 目录按设备功能域拆分为十余个管理器:BleConnectionManager(连接)、BleConfigManager(配置/总线占用)、BleDeviceInfoManager(设备信息)、BleDeviceMusicManager(设备音乐)、BleDeviceSettingManager(按键设置)、BleEqManager(EQ)、BleAlarmManager(闹钟)、BleAuraCastManager(AuraCast 投播)、BleChargingCaseManager(充电盒)、BleCustomCmdManager(自定义指令)、BleDoubleDeviceManager(双设备)等。
关键发现:事实上的"基类"是统一模式,而非继承
在 lib/ 与 example/lib/ 中检索 class BaseManager、abstract class Base 等显式基类声明,未发现任何管理器继承自基类(implementation details not found in source)。取而代之的是完全一致的代码约定,这正是本项目"基类管理器"的真实形态:
- 每个管理器是一个纯静态方法类:无实例字段、无构造函数、不持有状态;
- 方法签名统一为
static Future<...> xxx()形态,异步返回操作结果; - 类名统一为
Ble<功能域>Manager,文件名统一为ble_<功能域>_manager.dart; - 类注释一行概括职责,方法注释描述具体能力。
这种"约定优于继承"的选择在 Dart/Flutter 场景下是合理的:管理器不需要共享实例状态,也没有模板方法需要子类覆写;静态方法类避免了单例的初始化顺序问题,调用即所得,天然线程(isolate)安全,也便于单元测试时直接打桩。
代表性管理器分析
BleCustomCmdManager — 自定义指令通道,暴露最底层的能力:把原始字节数据直接发送给设备:
class BleCustomCmdManager {
static Future<void> sendCustomCommand(Uint8List data) async {
Source: ble_custom_cmd_manager.dart
它是其他管理器的"兜底"入口:当某个新功能尚未封装成专用管理器时,业务方可以先用 sendCustomCommand 透传指令验证协议,再沉淀为正式管理器方法。
BleChargingCaseManager — 页面级能力封装,返回 Future<bool> 表达操作成败,体现"管理器不直接操作 UI、但可为页面流程提供引导"的边界:
class BleChargingCaseManager {
static Future<bool> enterMessagePage() async {
Source: ble_charging_case_manager.dart
BleAuraCastManager — 纯异步任务,用于获取投播记录列表:
class BleAuraCastManager {
static Future<void> auraCastGetRecordList() async {
Source: ble_aura_cast_manager.dart
BleConnectionManager(ble_connection_manager.dart,职责注释 "Device Connection Manager")负责开始扫描、建立/断开连接,是设备列表页的核心依赖;BleConfigManager(ble_config_manager.dart)提供 "Check if BLE communication is currently being used" 的总线占用检查,供页面在发起新指令前判断通道是否繁忙;BleDeviceInfoManager(ble_device_info_manager.dart)暴露 "Get current device type" 等查询能力;BleDeviceSettingManager(ble_device_setting_manager.dart)对应 "Update key function settings" 的按键功能设置。
管理器分工总览
| 管理器 | 职责(依据类注释) | 入口文件 |
|---|---|---|
| BleConnectionManager | Device Connection Manager(扫描/连接) | ble_connection_manager.dart |
| BleConfigManager | Bluetooth Configuration Manager(总线占用检查) | ble_config_manager.dart |
| BleDeviceInfoManager | Device Information Manager(设备类型等) | ble_device_info_manager.dart |
| BleDeviceMusicManager | Device Music Manager(音乐信息) | ble_device_music_manager.dart |
| BleDeviceSettingManager | Device Settings Manager(按键功能设置) | ble_device_setting_manager.dart |
| BleEqManager | EQ Manager(EQ 数据读写) | ble_eq_manager.dart |
| BleAlarmManager | Alarm Manager(闹钟列表/设置) | ble_alarm_manager.dart |
| BleAuraCastManager | AuraCast Manager(投播记录) | ble_aura_cast_manager.dart |
| BleChargingCaseManager | Ble charging case manager(充电盒消息页) | ble_charging_case_manager.dart |
| BleCustomCmdManager | 自定义指令透传 | ble_custom_cmd_manager.dart |
| BleDoubleDeviceManager | Ble double device manager(双设备) | ble_double_device_manager.dart |
Core Flow:端到端控制流
一次典型操作的完整链路如下:页面调用管理器静态方法 → 管理器编码指令(引用 BleMethodConstants)→ SDK 写入 BLE 特征值 → 设备应答/主动上报 → SDK 触发事件 → 页面依据 BleEventConstants 分发并刷新 UI。
sequenceDiagram
participant UI as 页面
participant M as Ble*Manager
participant SDK as JL BLE SDK
participant DEV as 设备
UI->>M: 调用静态方法<br/>(如 sendCustomCommand(data))
activate M
M->>SDK: 编码并发送指令<br/>(引用 BleMethodConstants)
activate SDK
SDK->>DEV: 写入 BLE 特征值
DEV-->>SDK: 设备应答 / 主动上报
SDK-->>M: 回调结果
deactivate SDK
M-->>UI: Future 结果 (bool/void/数据)
deactivate M
UI->>UI: 依据 BleEventConstants 分发事件并刷新
流程要点:
- 异步契约:管理器一律返回
Future,页面用await串行等待结果;设备不在线时由 SDK 层超时并向下传递错误,管理器不吞异常(失败模式见下文)。 - 指令编码点:指令组装只发生在管理器内部,页面永远传"业务参数"而非"字节流",唯一的例外是
BleCustomCmdManager.sendCustomCommand显式暴露字节通道。 - 上行事件点:设备主动上报(如闹钟提醒、连接断开)不经过管理器的返回值,而是走 SDK 事件 →
BleEventConstants事件名 → 页面监听的旁路,保证"请求-应答"与"主动推送"两条路径互不阻塞。
用法示例
示例一:从页面调用管理器(连接/信息查询)
页面不感知 SDK,只面向管理器静态方法:
// 连接管理器:开始扫描
class BleConnectionManager {
/// Start scanning
static Future<void> startScan() async { ... }
}
Source: ble_connection_manager.dart
// 设备信息管理器:获取当前设备类型
class BleDeviceInfoManager {
/// Get current device type
static Future<void> getCurrentDeviceType() async { ... }
}
Source: ble_device_info_manager.dart
示例二:自定义指令透传
当新协议尚未封装时,业务层可直接发送原始字节:
class BleCustomCmdManager {
static Future<void> sendCustomCommand(Uint8List data) async {
Source: ble_custom_cmd_manager.dart
示例三:依赖连接状态常量做分支
页面在显示连接状态时引用 AppConstants 而非魔法数字:
switch (state) {
case AppConstants.connectionOK: // 1
// 已连接:展示设备信息
break;
case AppConstants.connectionConnecting: // 3
// 连接中:展示 loading
break;
case AppConstants.connectionFailed: // 2
// 连接失败:引导重试
break;
}
Source: constants.dart
配置选项(常量清单节选)
以下为 AppConstants 中已核实的关键常量;完整清单见 constants.dart。
| 常量 | 类型 | 默认值 | 说明 |
|---|---|---|---|
userAgreementUrl | String | https://cam.jieliapp.com/app/app.user.service.protocol.html | 用户协议 URL |
privacyPolicyUrl | String | https://cam.jieliapp.com/app/JL_OTA_app_privacy_policy.html | 隐私政策 URL |
communicationWayBle | String | 'BLE' | BLE 通信方式标识 |
communicationWaySpp | String | 'SPP' | SPP 通信方式标识 |
icpNumber | String | '粤ICP备18069041号-15A' | ICP 备案号 |
icpUrl | String | 'https://beian.miit.gov.cn/' | 备案查询 URL |
connectDefaultState | int | -1 | 连接状态默认值(未初始化) |
connectionDisconnect | int | 0 | 已断开 |
connectionOK | int | 1 | 已连接 |
connectionFailed | int | 2 | 连接失败 |
connectionConnecting | int | 3 | 连接中 |
tiramisu | int | 33 | Android 13 API level |
dialogButtonHeight | double | 45.0 | 对话框底部按钮高度 |
returnIconSizeValue | double | 28.0 | 返回图标尺寸 |
updateFileName | String | 'upgrade.ufw' | OTA 升级文件名 |
keyLanguageChinese | String | 'zh' | 中文语言键 |
messagePushEnabled | String | 'message_push_enabled' | 消息推送总开关存储键 |
API Reference
本体系的公开 API 形态统一为管理器静态方法,签名约定如下:
static Future<T> <operation>([参数])
参数: 各方法按需接收业务参数(如 BleCustomCmdManager.sendCustomCommand(Uint8List data) 接收原始指令字节)。
返回:
Future<void>:纯触发型操作(发送指令、获取列表),结果经事件旁路回传;Future<bool>:成败型操作(进入消息页等),true表示成功;- 其他数据型操作返回对应数据对象。
Throws: 未发现管理器层统一捕获异常的代码;设备离线、指令超时等错误由底层 SDK 以异常/Future 错误形式向上传播,由页面按需处理。
BleEventConstants / BleMethodConstants
常量类全部为 static const 字段,无方法;通过 BleMethodConstants.xxx / BleEventConstants.xxx 直接读取。
失败模式、边界与并发
- 设备离线/超时:管理器方法依赖设备在线的 BLE 链路,指令超时表现为
Future异常。由于管理器不做重试,页面需要捕获错误并提供重试入口;连接状态常量中的connectionFailed = 2即用于此分支。 - BLE 总线占用:
BleConfigManager提供 "Check if BLE communication is currently being used" 检查,说明项目采用"单通道串行指令"模型——并发下发多条指令可能互相覆盖,业务方应在发送前检查总线占用、发送后等待应答。 - 静态方法的并发安全:管理器无实例状态,天然免疫共享可变状态问题;但这也意味着"正在进行的操作"无法从管理器内部查询,需要页面自行维护(或依赖 SDK 回调事件)。
- 常量误用边界:
connectDefaultState = -1与connectionDisconnect = 0是两种语义,若误用默认值判断"是否已连接"会导致首帧状态误判;统一走常量可最大限度降低此类风险。
性能与运维
- 常量为
static const,编译期内联,零运行时开销,可放心在热路径(列表渲染、状态刷新)中引用。 - 管理器为静态方法,无对象分配与 DI 开销;每次调用仅产生一次 Future 与指令数据分配。
- 运维关注点集中在 BLE 通道:指令串行化、超时阈值、事件去重均由 SDK 层与管理器协作完成;如需诊断,可从
BleCustomCmdManager透传通道抓取原始指令对比协议文档。
扩展点
- 新增设备能力:在
lib/manager/下新建ble_xxx_manager.dart,遵循Ble<功能域>Manager+ 静态Future方法约定即可,无需改动现有管理器;如指令协议复用,可将方法名常量补充进BleMethodConstants,事件名补充进BleEventConstants。 - 协议适配:更换/升级 SDK 时,只需调整管理器内部编码与
BleMethodConstants/BleEventConstants映射,页面层零改动。 - 临时调试:利用
BleCustomCmdManager.sendCustomCommand透传新协议字节,验证通过后再沉淀为正式方法——这是项目预留的"快速验证"扩展口。
测试
未在本页读取预算内发现针对管理器/常量的独立测试文件。从设计形态看,静态方法类与 static const 常量天然便于测试:常量可被直接断言,管理器方法可在无 UI 环境下调用(配合 SDK mock)。若仓库中存在测试目录,建议按"常量语义不回归、管理器指令编码正确"两个维度补充用例。
Related Links
- BLE 事件常量 ble_event_constants.dart
- BLE 方法常量 ble_method_constants.dart
- 连接管理器 ble_connection_manager.dart
- 配置管理器 ble_config_manager.dart
- 自定义指令管理器 ble_custom_cmd_manager.dart
- 设备信息管理器 ble_device_info_manager.dart
- EQ 管理器 ble_eq_manager.dart
- 相邻主题:连接状态机与扫描流程(BleConnectionManager 详页)、EQ/闹钟/音乐等具体功能协议页、OTA 升级流程页