数据模型与常量定义
本文档介绍 JL_OTA Flutter SDK 中定义的数据模型与常量契约:BleMethodConstants(方法调用常量)、BleEventConstants(事件流常量)、AppConstants(应用级常量)以及 ScanDevice、DeviceConnection 两个核心数据模型,说明它们如何在 Flutter 与原生 BLE 插件之间充当稳定的通信契约。
Purpose and Scope
本页覆盖 SDK 核心 API 层中"契约层"的全部内容:
- 常量契约:
code/JL_OTA/lib/constant/目录下的三个常量类,它们定义了 Flutter 侧与原生侧(Android/iOS MethodChannel)之间所有方法名、参数键与事件键的字符串协议。 - 数据模型:
code/JL_OTA/lib/model/目录下的ScanDevice(扫描到的设备)与DeviceConnection(设备连接状态)模型,它们是事件回调与业务层之间传递数据的载体。
以下主题属于其他目录页,不在本页展开:
- 方法调用的封装与执行细节(
BleMethod类)→ 参见 SDK 核心 API 相关页面。 - 事件流的订阅与分发机制(
BleEventStream类)→ 参见 SDK 核心 API 相关页面。 - 示例 App 的 UI 与业务管理器(
example/lib/下的页面与对话框)→ 参见示例应用相关页面。 - 原生插件的实现(Android/Kotlin、iOS/Swift 源码)→ 参见原生层相关页面。
说明:本次文档基于源码探索时预算有限,
ble_event_constants.dart、constants.dart及两个模型文件的完整字段清单未逐行确认,文中凡涉及这些文件的内容均以示例工程中的实际引用证据为准,并明确标注。
Overview
JL_OTA Flutter SDK 采用 Flutter ↔ 原生(MethodChannel) 的桥接架构。Flutter 侧不能直接操作蓝牙硬件,所有能力(扫描、连接、OTA 升级、日志管理等)最终都要通过原生插件完成。在这种架构下,字符串常量就是跨语言边界的协议——方法名、事件名、参数键必须两端完全一致,否则调用会静默失败或事件无法匹配。
为此,SDK 在 lib/constant/ 下集中定义了三个常量类:
| 常量类 | 文件 | 职责 |
|---|---|---|
BleMethodConstants | ble_method_constants.dart | 方法名(METHOD_*)与参数键(ARG_*),即 Flutter 调用原生时的"请求协议" |
BleEventConstants | ble_event_constants.dart | 事件键(如 KEY_STATE、SCAN_STATE_SCANNING),即原生回调 Flutter 时的"通知协议" |
AppConstants | constants.dart | 应用级全局配置(如用户协议 URL) |
数据模型则承担"载荷"角色:原生侧返回的原始数据经 ScanDevice、DeviceConnection 等模型结构化后,通过 BleEventStream 分发给业务层。常量和模型共同构成了 SDK 的稳定契约层——业务代码只依赖这些契约,不依赖具体的原生实现,因此更换原生实现或扩展新能力时,只要保持契约不变,上层代码无需改动。
flowchart TD
subgraph sg_App["示例应用层 example/lib"]
AppUI["页面 / 管理器<br/>(devices_page.dart 等)"]
UIConstants["UI 常量类<br/>MethodChannelConstants / OtaStateConstants"]
end
subgraph sg_SDK["SDK 核心层 lib"]
BleMethod["BleMethod<br/>方法调用封装"]
BleEventStream["BleEventStream<br/>事件流封装"]
subgraph sg_Contract["契约层 constant/ + model/"]
MethodConst["BleMethodConstants<br/>METHOD_* / ARG_*"]
EventConst["BleEventConstants<br/>KEY_STATE 等"]
AppConst["AppConstants<br/>应用配置"]
ScanDevice["ScanDevice<br/>扫描设备模型"]
DeviceConn["DeviceConnection<br/>连接状态模型"]
end
end
subgraph sg_Native["原生插件层"]
Native["Android / iOS 插件<br/>MethodChannel"]
end
AppUI -->|"引用"| UIConstants
AppUI -->|"调用"| BleMethod
AppUI -->|"订阅"| BleEventStream
BleMethod -->|"方法名/参数键"| MethodConst
BleMethod -->|"invokeMethod"| Native
Native -->|"事件回调"| BleEventStream
BleEventStream -->|"解析载荷"| ScanDevice
BleEventStream -->|"解析载荷"| DeviceConn
BleEventStream -->|"事件键"| EventConst
UIConstants -->|"复用契约常量"| EventConst
UIConstants -->|"复用契约常量"| MethodConst
AppConst -.->|"全局配置"| AppUI
架构解读:BleMethodConstants 与 BleEventConstants 是双向通信契约——前者约束 Flutter→原生方向的方法调用(BleMethod 使用 METHOD_* 作为方法名、ARG_* 作为参数键),后者约束原生→Flutter 方向的事件通知(BleEventStream 按 KEY_STATE 等事件键分发)。ScanDevice 与 DeviceConnection 作为事件载荷的载体,在事件流与业务层之间传递结构化数据。示例工程中的 MethodChannelConstants、OtaStateConstants、ScanStateConstants 等 UI 常量类直接复用契约常量(如 BleEventConstants.KEY_STATE),验证了契约层的可复用性。
常量契约:BleMethodConstants
BleMethodConstants(ble_method_constants.dart)是 SDK 中规模最大的常量类,集中定义了 Flutter 调用原生 BLE 插件所需的全部方法名与参数键。它分两组:
METHOD_*:方法名,作为MethodChannel.invokeMethod的第一个参数。ARG_*:参数键,作为方法调用argumentsMap 中的键名。
方法名常量(METHOD_*)
按功能域划分,方法名常量覆盖了 SDK 的全部对外能力:
| 功能域 | 常量 | 值 |
|---|---|---|
| 扫描控制 | METHOD_IS_SCANNING | 'isScanning' |
METHOD_CHECK_BLUETOOTH_ENVIRONMENT | 'checkBluetoothEnvironment' | |
METHOD_START_SCAN | 'startScan' | |
METHOD_STOP_SCAN | 'stopScan' | |
METHOD_GET_SCAN_FILTER | 'getScanFilter' | |
METHOD_SET_SCAN_FILTER | 'setScanFilter' | |
| 连接控制 | METHOD_CONNECT_DEVICE | 'connectDevice' |
METHOD_DISCONNECT_BT_DEVICE | 'disconnectBtDevice' | |
METHOD_GET_CONNECT_WAY | 'getConnectWay' | |
METHOD_SET_CONNECT_WAY | 'setConnectWay' | |
METHOD_IS_USING_SDK_BLUETOOTH | 'isUseSDKBluetooth' | |
METHOD_SET_USING_SDK_BLUETOOTH | 'setUseSDKBluetooth' | |
METHOD_IS_USING_GATT_OVER_EDR | 'isUseGattOverEdr' | |
METHOD_SET_GATT_OVER_EDR | 'setGattOverEdr' | |
METHOD_GET_GATT_SERVICE_UUIDS | 'getGattServiceUuids' | |
METHOD_SET_GATT_SERVICE_UUIDS | 'setGattServiceUuids' | |
METHOD_IS_USE_DEVICE_AUTH | 'isUseDeviceAuth' | |
METHOD_SET_USE_DEVICE_AUTH | 'setUseDeviceAuth' | |
METHOD_IS_HID_DEVICE | 'isHidDevice' | |
METHOD_SET_HID_DEVICE | 'setHidDevice' | |
METHOD_IS_USE_CUSTOM_RECONNECT_WAY | 'isUseCustomReConnectWay' | |
METHOD_SET_USE_CUSTOM_RECONNECT_WAY | 'setUseCustomReConnectWay' | |
METHOD_GET_BLE_REQUEST_MTU | 'getBleRequestMtu' | |
METHOD_SET_BLE_REQUEST_MTU | 'setBleRequestMtu' | |
| 版本与日志 | METHOD_GET_SDK_VERSION | 'getSdkVersion' |
METHOD_GET_APP_VERSION | 'getAppVersion' | |
METHOD_GET_LOG_FILE_DIR_PATH | 'getLogFileDirPath' | |
METHOD_GET_LOG_FILES | 'getLogFiles' | |
METHOD_LOG_FILE_INDEX | 'logFileIndex' | |
METHOD_SHARE_LOG_FILE | 'shareLogFile' | |
METHOD_DELETE_ALL_LOG_FILE | 'deleteAllLogFile' | |
| 文件管理 | METHOD_DOWNLOAD_FILE | 'downloadFile' |
METHOD_READ_FILE_LIST | 'readFileList' | |
METHOD_SET_SELECTED_INDEX | 'setSelectedIndex' | |
METHOD_DELETE_OTA_FILE_INDEX | 'deleteOtaFileIndex' | |
METHOD_TRY_TO_CHECK_STORAGE_ENVIRONMENT | 'tryToCheckStorageEnvironment' | |
METHOD_PICK_FILE | 'pickFile' | |
| OTA 升级 | METHOD_TYPE_IS_OTA | 'isOta' |
METHOD_START_OTA | 'startOTA' | |
| 其他 | METHOD_GET_WIFI_IP_ADDRESS | 'getWifiIpAddress' |
METHOD_POP_ALL_ACTIVITY | 'popAllActivity' | |
METHOD_SEND_CUSTOM_COMMAND | 'sendCustomCommand' |
参数键常量(ARG_*)
方法调用需要携带参数时,参数以 Map 形式传递,键名由 ARG_* 常量统一约束:
| 常量 | 值 | 关联方法域 |
|---|---|---|
ARG_INDEX | 'index' | 文件索引选择 |
ARG_FILTER | 'filter' | 扫描过滤条件 |
ARG_CONNECT_WAY | 'connectWay' | 连接方式 |
ARG_IS_USING_SDK_BLUETOOTH | 'isUsingSDKBluetooth' | SDK 蓝牙开关 |
ARG_IS_USING_GATT_OVER_EDR | 'isUsingGattOVerEdr' | Gatt Over EDR 开关 |
ARG_GATT_SERVICE_UUIDS | 'gattServiceUuids' | GATT Service UUID 列表 |
ARG_IS_AUTH | 'isAuth' | 设备认证开关 |
ARG_IS_HID | 'isHid' | HID 设备标记 |
ARG_IS_CUSTOM | 'isCustom' | 自定义重连方式 |
ARG_MTU | 'mtu' | MTU 请求值 |
ARG_LOG_FILE_INDEX | 'logFileIndex' | 日志文件索引 |
ARG_HTTP_URL | 'httpUrl' | HTTP 下载地址 |
ARG_POS | 'pos' | 位置参数 |
ARG_PATH | 'path' | 升级文件路径 |
ARG_CUSTOM_DATA | 'customData' | 自定义命令载荷 |
设计意图
将所有方法名与参数键收敛到单一常量类,而非散落在调用处,是契约集中化的设计决策:
- 单一事实来源:原生侧插件与 Flutter 侧 SDK 都引用同一份字符串协议(原生侧以常量文件形式镜像),避免魔法字符串导致的两端漂移。
- 类型安全替代:Dart 是弱字符串类型语言,集中定义让 IDE 支持自动补全与重命名重构,降低拼写错误风险。
- 跨端对齐的文档价值:常量即 API 文档——原生开发者只需对照此文件即可实现完整的通道协议。
例如 BleMethod 封装层发起扫描时,方法名取 BleMethodConstants.METHOD_START_SCAN,原生侧对应处理 "startScan",两端通过该字符串握手:
/// 检查是否正在扫描设备的方法名。
static const String METHOD_IS_SCANNING = 'isScanning';
/// 开始扫描设备的方法名。
static const String METHOD_START_SCAN = 'startScan';
/// 停止扫描设备的方法名。
static const String METHOD_STOP_SCAN = 'stopScan';
Source: ble_method_constants.dart
/// 索引参数名。
static const String ARG_INDEX = 'index';
/// 过滤条件参数名。
static const String ARG_FILTER = 'filter';
/// 使用连接方式的参数名。
static const String ARG_CONNECT_WAY = 'connectWay';
Source: ble_method_constants.dart
常量契约:BleEventConstants
BleEventConstants(ble_event_constants.dart)定义了 BLE 事件流相关的常量,是原生侧主动上报状态时的事件键协议。与 BleMethodConstants 的"请求"方向相反,它是"通知"方向:原生插件通过 MethodChannel 的事件通道把扫描状态、连接状态、OTA 进度等事件推送给 Flutter 侧,BleEventStream 依据这些事件键进行匹配与分发。
从示例工程的引用可以确认其至少包含以下事件键(完整字段清单未在本次探索中逐行确认):
| 常量(依据引用确认) | 用途 |
|---|---|
BleEventConstants.KEY_STATE | 状态事件键,用于携带 BLE 开关/系统状态 |
BleEventConstants.SCAN_STATE_SCANNING | 扫描状态值,标识"正在扫描中" |
示例工程 devices_page.dart 中的 OtaStateConstants 与 ScanStateConstants 直接引用这些事件常量,证明事件常量是跨 SDK 与业务层复用的公共契约:
class OtaStateConstants {
/// OTA State Constants
static const String keyState = BleEventConstants.KEY_STATE;
// ...
}
class ScanStateConstants {
/// Scan State Constants
static const String stateScanning = BleEventConstants.SCAN_STATE_SCANNING;
// ...
}
Source: devices_page.dart
设计意图:将事件键与状态值也集中定义为常量,业务层订阅事件流时直接使用 BleEventConstants.KEY_STATE 等命名常量,而不是手写字符串。这样当原生侧调整事件协议时,只需修改常量定义与原生镜像,业务代码不受影响。
常量契约:AppConstants
AppConstants(constants.dart)承载应用级全局常量与配置值(例如用户协议 URL)。它与 SDK 桥接协议无关,属于产品层配置,主要服务于示例应用与 SDK 内的通用逻辑。
设计意图:将跨页面、跨模块复用的应用配置从散落的硬编码中抽离,统一管理,便于发布时集中修改(如更换协议地址、调整全局开关)。
数据模型:ScanDevice 与 DeviceConnection
lib/model/ 目录下定义了两个核心数据模型,它们是事件流载荷的结构化载体:
| 模型 | 文件 | 职责 |
|---|---|---|
ScanDevice | scan_device.dart | 描述一次扫描发现的蓝牙设备(地址、名称、信号强度等),是扫描结果事件的载荷 |
DeviceConnection | device_connection.dart | 描述设备连接状态/连接信息,是连接状态事件的载荷 |
这两个模型在 SDK 数据流中的位置如下:
flowchart LR
Native["原生插件"] -->|"扫描结果原始数据"| ScanDevice["ScanDevice"]
Native -->|"连接状态原始数据"| DeviceConn["DeviceConnection"]
ScanDevice --> Stream["BleEventStream 事件流"]
DeviceConn --> Stream
Stream -->|"分发携带模型的事件"| Business["业务层<br/>示例 App 管理器"]
设计意图:模型层将原生侧返回的异构数据(Map、JSON 等)转换为强类型 Dart 对象,业务层消费事件时无需关心原生数据结构,直接读取 ScanDevice 的字段即可。这一层抽象同时屏蔽了 Android 与 iOS 在数据格式上的差异——两端都向 Flutter 侧吐同一结构的模型数据。
注意:本次探索受工具预算限制,未逐行读取
scan_device.dart与device_connection.dart的字段定义;上述职责描述基于文件名、目录结构与 SDK 桥接架构推断。完整字段清单请直接查看 scan_device.dart 与 device_connection.dart。