设置与调试
本页介绍 JL_OTA Flutter 示例应用(code/JL_OTA/example)中「设置」页面的完整实现:包括 SettingPage 的用户界面结构、SettingManager 的数据加载/保存逻辑、Android/iOS 平台差异、MTU 调整、日志文件访问、版本信息展示,以及与 SDK 桥接层 BleMethod 的交互方式。
Purpose and Scope
本页聚焦于示例应用的「设置与调试」能力,涵盖:
- UI 层:
SettingPage(StatefulWidget)如何组织各设置区块(设备认证、HID、自定义重连、通信方式、MTU、SDK 蓝牙、GATT over EDR、日志文件、版本、自定义命令、关于)。 - 数据层:
SettingManager如何通过静态方法封装对原生 SDK 的读写调用,以及异常兜底策略。 - 平台差异:Android 与 iOS 各自特有的设置项与保存行为(Android 保存后
popAllActivity()重启应用)。 - 调试入口:日志文件目录展示、日志文件列表页(
FileListPage)入口、自定义命令页(CustomCmdPage)入口。
以下主题由同目录下其他页面文档负责,不在本页展开:设备扫描与连接的完整流程(devices_page)、文件列表与升级流程(file_list_page / update_page)、关于页面(about_page)、自定义命令的指令细节(custom_cmd_page)。如需了解,请参阅对应页面。
Overview
「设置」页面是示例应用中对 SDK 运行参数进行配置与调试的核心入口。应用启动后,SettingPage.initState() 触发 _initialize(),通过 SettingManager 的系列静态方法从原生 SDK 读取当前配置(设备认证开关、HID 开关、自定义重连方式、通信方式、MTU、SDK 蓝牙、GATT over EDR 等),并展示在分组列表中。用户在页面上修改任意设置后,AppBar 上的「保存」按钮由 _hasSettingsChanged() 检测结果驱动变为可用;点击保存会调用 SettingManager.saveSettings(),按平台分支写入原生 SDK。
该设计有两点关键意图:
- 单一数据入口:所有与原生 SDK 的交互都收敛到
SettingManager,UI 层不直接接触BleMethod,便于统一处理异常与默认值。 - 保存后重启(Android):部分原生参数(如 HID、自定义重连)在 SDK 初始化后无法热切换,因此 Android 保存成功后调用
BleMethod.popAllActivity()重启应用使配置生效——这是示例应用明确的权衡,iOS 则不需要重启。
调试方面,页面顶部展示日志文件目录路径(Android 居中、iOS 左对齐),「日志文件」导航行在蓝牙连接状态下可进入 FileListPage 查看/下载日志;「自定义命令」行在 Android 或 iOS 使用 SDK 蓝牙时可用,进入 CustomCmdPage 发送调试指令;「版本信息」行展示 SDK 版本与应用版本;「关于应用」行进入 AboutPage。
Architecture
flowchart TD
subgraph sg_UI["UI 层 (Flutter Widgets)"]
SettingPage["SettingPage<br/>(StatefulWidget)"]
SettingSection["SettingSection<br/>(分组容器)"]
SettingSwitchRow["SettingSwitchRow<br/>(开关行)"]
SettingNavigationRow["SettingNavigationRow<br/>(导航行)"]
CommunicationOption["CommunicationOption<br/>(单选通信方式)"]
end
subgraph sg_Data["数据层 (示例应用)"]
SettingManager["SettingManager<br/>(静态方法封装)"]
end
subgraph sg_Plugin["SDK 桥接层 (jl_ota 插件)"]
BleMethod["BleMethod<br/>(MethodChannel)"]
end
subgraph sg_Native["原生层 (JL BLEKit / Android SDK)"]
Android["Android 原生 SDK"]
iOS["iOS 原生 SDK"]
end
SettingPage --> SettingSection
SettingPage --> SettingSwitchRow
SettingPage --> SettingNavigationRow
SettingPage --> CommunicationOption
SettingPage -->|"加载 / 保存"| SettingManager
SettingManager -->|"静态调用"| BleMethod
BleMethod -->|"通道分发"| Android
BleMethod -->|"通道分发"| iOS
各层职责说明:
SettingPage:页面唯一入口(setting_page.dart)。持有所有设置项的状态变量与初始值快照,负责按平台条件渲染区块,并驱动保存流程。它通过context.watch<ConnectionStateManager>()订阅蓝牙连接状态,决定 MTU/日志/自定义命令等入口是否可用。SettingManager:纯静态方法的数据访问层(setting_manager.dart)。每个方法都包裹try-catch,原生调用失败时记录日志并返回安全默认值;只有saveSettings选择rethrow,因为保存失败必须让 UI 感知。BleMethod:jl_ota插件暴露的 Dart 静态桥接类,内部通过 MethodChannel 与原生 SDK(Android JL SDK / iOS JL_BLEKit)通信。SettingManager是它在本能力域内的唯一消费者。- 原生层:真正持有配置状态(如 MTU、通信方式、设备认证开关)的载体,示例应用仅做透传与展示。
主要实现
SettingPage 状态设计
SettingPage 是一个 StatefulWidget,其状态类 _SettingPageState 维护了两组状态变量(setting_page.dart):
- 当前值:
_isDeviceAuthenticated、_isHidDevice、_customReconnectMethod、_connectUsingSdkBluetooth、_isGattOverEdr、_currentCommunicationMethod、_mtu、_gattServiceUuids等,直接驱动 UI 渲染。 - 初始值快照:
_initialDeviceAuthenticated、_initialHidDevice、_initialCustomReconnectMethod、_initialConnectUsingSdkBluetooth、_initialGattOverEdr、_initialCommunicationMethod、_initialMtu,用于_hasSettingsChanged()变更检测。
// State variables
String _logFileDirPath = "";
int _currentCommunicationMethod = AppConstants.communicationWayBle;
String _sdkVersion = "unknown";
String _appVersion = "unknown";
bool _isDeviceAuthenticated = false;
bool _isHidDevice = false;
bool _customReconnectMethod = false;
bool _connectUsingSdkBluetooth = false;
bool _isGattOverEdr = false;
List<String> _gattServiceUuids = [];
int _mtu = 0;
// Initial value tracking
bool _initialDeviceAuthenticated = false;
...
Source: setting_page.dart
关键的设计意图是**「初始值快照 + 变更检测」**:保存按钮的可用性由 hasChanges 决定,避免用户未做任何修改时触发无意义的原生写入。同时,_connectState 通过 context.watch<ConnectionStateManager>() 订阅,使页面在蓝牙断开时自动禁用依赖连接的入口。
页面渲染与平台分支
build() 方法(setting_page.dart)按以下顺序渲染:
- 日志路径提示(页面顶部):Android 下居中显示,iOS 下左对齐;颜色为浅灰(
0xFF6F6F6F),字号 13。 - 设备认证开关:所有平台通用。
- Android 专属区块(
if (isAndroid)):HID 设备开关、自定义重连方式开关、通信方式单选(BLE/SPP/GATT over BR/EDR)、MTU 调整行。 - iOS 专属区块(
if (!isAndroid)):使用 SDK 蓝牙开关、GATT over EDR 开关(打开时弹出 UUID 设置页)。 - 通用区块:日志文件导航行、SDK 版本信息行、自定义命令导航行、关于应用导航行。
// Check if any settings have been modified
final bool hasChanges = _hasSettingsChanged();
return Scaffold(
appBar: AppBar(
...
actions: [
TextButton(
onPressed: hasChanges ? () => _onSavePressed(isAndroid) : null,
child: Text(
loc.save,
style: TextStyle(
color: hasChanges ? primaryColor : disabledColor,
...
Source: setting_page.dart
flowchart TD
Start(["打开设置页"]) --> Init["initState() → _initialize()"]
Init --> Load["SettingManager.loadXxx() 系列<br/>(从原生 SDK 读取)"]
Load --> Build["build() 渲染页面"]
Build --> P{"isAndroid?"}
P -->|"是"| AndroidSec["Android 区块<br/>HID / 自定义重连 / 通信方式 / MTU"]
P -->|"否"| iOSSec["iOS 区块<br/>SDK蓝牙 / GATT over EDR"]
AndroidSec --> Common["通用区块<br/>日志 / 版本 / 自定义命令 / 关于"]
iOSSec --> Common
Common --> HasChange{"_hasSettingsChanged()?"}
HasChange -->|"有变更"| SaveBtn["保存按钮可用 (primaryColor)"]
HasChange -->|"无变更"| SaveBtn2["保存按钮禁用 (disabledColor)"]
平台分支的设计意图:Android 与 iOS 的底层 SDK 能力不同——Android 支持 HID、SPP 通信与自定义重连,iOS 则引入「使用 SDK 蓝牙」与「GATT over EDR」两个概念,因此 UI 必须按 AppUtil.isAndroid 做条件渲染,保证每个平台只暴露其原生支持的能力,避免误导用户。
通信方式选择
通信方式区块包含三个 CommunicationOption(单选),分别对应常量 AppConstants.communicationWayBle、communicationWaySpp、communicationWayGattOverBrEdr:
/// Builds BLE communication option
Widget _buildCommunicationOptionBle(AppLocalizations loc) {
return CommunicationOption(
title: loc.communicationWayBle,
isSelected:
_currentCommunicationMethod == AppConstants.communicationWayBle,
onTap: () => _updateState(
() => _currentCommunicationMethod = AppConstants.communicationWayBle,
),
);
}
Source: setting_page.dart
选择结果存于 _currentCommunicationMethod,保存时经 SettingManager 写入原生层。_updateState(() => ...) 统一包装 setState,保证所有修改都走同一路径。
MTU 调整与连接状态守卫
MTU 调整行仅在通信方式为 BLE 时完全可用(Opacity(opacity: isBleEnabled ? 1.0 : 0.5)),点击前会检查连接状态:
SettingNavigationRow(
title: loc.adjustMtu,
subtitle: mtuDisplay,
onTap: isBleEnabled
? () {
if (_connectState == AppConstants.connectionDisconnect &&
mounted) {
ToastUtils.show(context, loc.bluetoothDisconnected);
} else {
showMtuAdjustmentDialog(context);
}
}
: null,
),
Source: setting_page.dart
页面定义了 MTU 的合法区间常量:minMtu = 23、maxMtu = 509(setting_page.dart)。mtuDisplay getter 在 _mtu > 0 时显示数值,否则显示空字符串。这种「断开即 Toast 提示」的守卫模式同样应用于日志文件与自定义命令入口,确保所有依赖蓝牙连接的调试操作都先校验连接状态。
自定义命令与日志入口的可达性
- 自定义命令(
_onCustomCmdTap):仅 Android 或 iOS 使用 SDK 蓝牙时返回可点击回调;点击后再次校验连接状态,断开则 Toast 提示,否则Navigator.push进入CustomCmdPage(setting_page.dart)。 - 日志文件:连接状态下点击进入
FileListPage(setting_page.dart)。 - 关于应用:无条件可用,进入
AboutPage;副标题展示_appVersion。
SettingManager 数据层
SettingManager 是示例应用与 jl_ota 插件之间的静态门面(static facade),全部方法为 static,不持有实例状态(setting_manager.dart)。这样设计是因为配置项本质上是原生 SDK 的全局状态,无需在 Dart 侧保存副本;UI 层随时可调用静态方法读取最新值。
加载方法:统一异常兜底
每个 load* 方法都遵循同一模式——调用 BleMethod 对应方法,失败时用 dart:developer 的 log() 记录错误并返回安全默认值:
// 加载设备认证状态
static Future<bool> loadDeviceAuth() async {
try {
return await BleMethod.isUseDeviceAuth();
} catch (e) {
log("Failed to load device auth: $e");
return false;
}
}
// 加载MTU值(仅Android)
static Future<int> loadMtu() async {
try {
return await BleMethod.getBleRequestMtu();
} catch (e) {
log("Failed to load MTU: $e");
return 23; // 默认值
}
}
Source: setting_manager.dart
设计意图:加载失败返回默认值(false / 23 / communicationWayBle / 空字符串 / "unknown"),保证 UI 永远能渲染出一个可用状态,而不是因原生异常导致页面崩溃;错误通过 log() 写入调试日志,方便开发者在「日志文件」入口中回溯问题。
版本信息聚合
getVersions() 并发获取 SDK 与应用版本并组装为 Map,键使用 AppConstants.sdkName / AppConstants.appName:
static Future<Map<String, String>> getVersions() async {
try {
final sdkVersion = await BleMethod.getSdkVersion();
final appVersion = await BleMethod.getAppVersion();
return {
AppConstants.sdkName: sdkVersion,
AppConstants.appName: appVersion,
};
} catch (e) {
log("Failed to get versions: $e");
return {AppConstants.sdkName: "unknown", AppConstants.appName: "unknown"};
}
}
Source: setting_manager.dart
保存流程(核心控制流)
saveSettings() 是唯一 rethrow 异常的方法——保存失败必须向上传播,由 UI 层感知并提示用户,这与加载方法的静默兜底形成鲜明对比:
static Future<void> saveSettings({
required bool isAndroid,
required bool deviceAuth,
required bool hidDevice,
required bool customReconnect,
required int communicationMethod,
required int mtu,
required bool useSdkBluetooth,
required bool gattOverEdr,
required List<String> gattServiceUuids,
}) async {
try {
// 通用设置:设备认证
await BleMethod.setUseDeviceAuth(deviceAuth);
if (isAndroid) {
// Android特有设置
await BleMethod.setHidDevice(hidDevice);
await BleMethod.setUseCustomReConnectWay(customReconnect);
await BleMethod.setConnectWay(communicationMethod);
await BleMethod.setBleRequestMtu(mtu);
await BleMethod.popAllActivity(); // 重启应用
} else {
// iOS特有设置
await BleMethod.setConnectUsingSdkBluetooth(useSdkBluetooth);
await BleMethod.setGattOverEdrState(gattOverEdr);
await BleMethod.setGattServiceUuids(gattServiceUuids);
}
} catch (e) {
log("Failed to save settings: $e");
rethrow;
}
}
Source: setting_manager.dart
sequenceDiagram
participant U as 用户
participant SP as SettingPage
participant SM as SettingManager
participant BM as BleMethod
participant N as 原生 SDK
U->>SP: 修改任意设置项
SP->>SP: _updateState() 更新状态变量
SP->>SP: _hasSettingsChanged() → hasChanges=true
U->>SP: 点击 AppBar「保存」
SP->>SM: saveSettings(isAndroid, deviceAuth, ...)
SM->>BM: setUseDeviceAuth(deviceAuth) (通用)
alt Android
SM->>BM: setHidDevice / setUseCustomReConnectWay
SM->>BM: setConnectWay / setBleRequestMtu
BM->>N: 写入原生配置
SM->>BM: popAllActivity() 重启应用
else iOS
SM->>BM: setConnectUsingSdkBluetooth / setGattOverEdrState
SM->>BM: setGattServiceUuids(gattServiceUuids)
BM->>N: 写入原生配置
end
N-->>SM: 结果
SM-->>SP: 成功返回 / rethrow 异常
保存流程要点:
- 通用设置先行:
setUseDeviceAuth不分平台总是最先写入,因为设备认证是所有通信方式的前提。 - Android 分支以
popAllActivity()收尾:HID、自定义重连、通信方式、MTU 均为 SDK 启动期参数,原生侧要求重启应用才能生效,因此保存成功后直接退出所有 Activity 触发冷启动。 - iOS 分支顺序写入:SDK 蓝牙 → GATT over EDR → 服务 UUID 列表;其中
_gattServiceUuids默认含AE00(setting_page.dart),由service_uuid_input_page提供编辑入口。 - 异常传播:任一步骤失败即
rethrow,UI 层可据此提示「保存失败」,避免用户误以为配置已生效。
使用示例
以下示例均摘自仓库真实源码,展示如何在实际代码中使用本能力。
示例 1:在页面初始化时加载全部设置
_SettingPageState.initState() 调用 _initialize(),通过 SettingManager 的加载方法批量读取原生配置并填充状态变量(含初始值快照):
void initState() {
super.initState();
_initialize();
}
Source: setting_page.dart
示例 2:读取 SDK 版本与应用版本并展示
final versions = await SettingManager.getVersions();
setState(() {
_sdkVersion = versions[AppConstants.sdkName] ?? "unknown";
_appVersion = versions[AppConstants.appName] ?? "unknown";
});
说明:
getVersions()内部通过BleMethod.getSdkVersion()/BleMethod.getAppVersion()获取,异常时回退为"unknown"。Source: setting_manager.dart
示例 3:构造可复用的设置区块与开关行
页面使用自定义组件 SettingSection(分组容器)与 SettingSwitchRow(开关行)组织 UI:
// Device authentication settings
SettingSection(
children: [
SettingSwitchRow(
title: loc.deviceAuthentication,
value: _isDeviceAuthenticated,
onChanged: (value) =>
_updateState(() => _isDeviceAuthenticated = value),
),
],
),
Source: setting_page.dart
示例 4:保存设置的完整调用(按平台分支)
await SettingManager.saveSettings(
isAndroid: isAndroid,
deviceAuth: _isDeviceAuthenticated,
hidDevice: _isHidDevice,
customReconnect: _customReconnectMethod,
communicationMethod: _currentCommunicationMethod,
mtu: _mtu,
useSdkBluetooth: _connectUsingSdkBluetooth,
gattOverEdr: _isGattOverEdr,
gattServiceUuids: _gattServiceUuids,
);
Source(参数契约): setting_manager.dart
Configuration Options
本能力没有独立配置文件,所有配置项均由原生 SDK 持有,示例应用通过 SettingManager 读写。可配置项如下:
| 设置项 | 类型 | 平台 | 默认值 | 说明 |
|---|---|---|---|---|
deviceAuth | bool | 通用 | false | 设备认证开关,保存时最先写入 |
hidDevice | bool | Android | false | HID 设备模式开关 |
customReconnect | bool | Android | false | 自定义重连方式开关 |
communicationMethod | int | Android | AppConstants.communicationWayBle | 通信方式:BLE / SPP / GATT over BR/EDR 单选 |
mtu | int | Android | 23 | BLE 请求 MTU,合法区间 23–509 |
useSdkBluetooth | bool | iOS | false | 使用 SDK 蓝牙开关,控制自定义命令可用性 |
gattOverEdr | bool | iOS | false | GATT over EDR 开关,打开时弹出 UUID 设置 |
gattServiceUuids | List<String> | iOS | ['AE00'] | GATT 服务 UUID 列表(defaultServiceUuid = 'AE00') |
logFileDirPath | String | 通用(展示) | "" | 日志目录路径,页面顶部展示 |
sdkVersion / appVersion | String | 通用(展示) | "unknown" | 版本信息,只读展示 |
说明:
minMtu = 23、maxMtu = 509常量定义见 setting_page.dart;通信方式常量与默认值见 setting_manager.dart。
API Reference
SettingManager(setting_manager.dart)为静态类,全部方法可直接以 SettingManager.xxx() 调用。
static Future<bool> loadDeviceAuth()
加载设备认证状态。
- 返回:
true表示已开启设备认证;原生调用异常时返回false。
static Future<bool> loadHidDevice()
加载 HID 设备状态(仅 Android 有意义)。
- 返回:HID 开关状态;异常时返回
false。
static Future<bool> loadCustomReconnect()
加载自定义重连方式状态(仅 Android)。
- 返回:是否使用自定义重连;异常时返回
false。
static Future<int> loadCommunicationMethod()
加载当前通信方式(仅 Android)。
- 返回:
AppConstants中的通信方式常量(communicationWayBle/communicationWaySpp/communicationWayGattOverBrEdr);异常时返回communicationWayBle。
static Future<int> loadMtu()
加载 BLE 请求 MTU(仅 Android)。
- 返回:MTU 数值;异常时返回
23。
static Future<bool> loadSdkBluetooth()
加载 SDK 蓝牙使用状态(仅 iOS)。
- 返回:是否使用 SDK 蓝牙;异常时返回
false。
static Future<bool> isUseGattOverEdr()
读取 GATT over EDR 状态(仅 iOS)。
- 返回:是否启用 GATT over EDR;异常时返回
false。
static Future<String> getLogDirPath()
获取日志文件目录路径。
- 返回:日志目录绝对路径;异常时返回空字符串
""。
static Future<Map<String, String>> getVersions()
获取 SDK 版本与应用版本。
- 返回:
{AppConstants.sdkName: sdkVersion, AppConstants.appName: appVersion};异常时两个值均为"unknown"。
static Future<void> saveSettings({required bool isAndroid, required bool deviceAuth, required bool hidDevice, required bool customReconnect, required int communicationMethod, required int mtu, required bool useSdkBluetooth, required bool gattOverEdr, required List<String> gattServiceUuids})
保存全部设置到原生 SDK。
参数:
isAndroid(bool,必填):平台标识,决定走 Android 还是 iOS 分支。deviceAuth(bool,必填):设备认证开关。hidDevice(bool,必填):HID 设备开关(Android)。customReconnect(bool,必填):自定义重连开关(Android)。communicationMethod(int,必填):通信方式常量(Android)。mtu(int,必填):BLE 请求 MTU(Android)。useSdkBluetooth(bool,必填):SDK 蓝牙开关(iOS)。gattOverEdr(bool,必填):GATT over EDR 开关(iOS)。gattServiceUuids(List<String>,必填):GATT 服务 UUID 列表(iOS)。
行为:
- 通用设置
setUseDeviceAuth总是先执行; - Android 分支写入 HID、自定义重连、通信方式、MTU 后调用
popAllActivity()重启应用; - iOS 分支依次写入 SDK 蓝牙、GATT over EDR、服务 UUID。
Throws:
Exception(原生侧错误):任一写入失败时rethrow,由调用方处理;错误同时写入log()。
失败模式、边界情况与并发
原生调用异常
- 加载路径:
SettingManager每个load*方法都以try-catch包裹,异常时log()记录并返回默认值(false/23/communicationWayBle/""/"unknown")。这意味着原生 SDK 不可用时页面仍可渲染,但会展示默认配置——用户在调试时可能误以为配置已生效,因此日志中保留错误记录用于排查。 - 保存路径:
saveSettings失败时rethrow,UI 层应提示保存失败。这是有意的不对称设计:加载可降级,保存必须明确失败,否则配置会静默丢失。
连接状态守卫
MTU 调整、日志文件、自定义命令三个入口在 _connectState == AppConstants.connectionDisconnect 时不会进入对应流程,而是 ToastUtils.show(context, loc.bluetoothDisconnected) 提示(setting_page.dart)。守卫使用 mounted 检查避免在 Widget 销毁后弹 Toast。
MTU 边界
页面定义 minMtu = 23、maxMtu = 509,实际输入校验由 mtu_adjustment_dialog.dart 负责;mtuDisplay 仅在 _mtu > 0 时展示数值,避免加载失败(默认 23 之外的异常值)显示误导信息。
平台特有边界
- iOS 自定义命令:仅当
_connectUsingSdkBluetooth == true时可用,否则整行以Opacity(0.5)半透明禁用(setting_page.dart)。 - Android 保存重启:
popAllActivity()会退出所有 Activity,属于「破坏性」操作——用户必须接受重启才能使 HID/重连/MTU 等生效,这是原生 SDK 能力的硬约束。 - GATT over EDR:iOS 打开该开关时立即弹出
service_uuid_input_page设置 UUID,先于状态提交,确保用户理解该开关需要附加配置。
并发与状态一致性
- 页面状态与原生配置不同步写入:用户修改 UI 后、点击保存前,原生侧仍是旧值;期间若蓝牙连接状态变化,
context.watch<ConnectionStateManager>()会触发重建,但已修改的设置项会保留(状态变量不因重建丢失)。 _initialize()内部多个await串行加载,setState前应检查mounted,避免异步返回时页面已销毁(_autoScrollToBottom中已使用_scrollController.hasClients防御)。- 所有加载/保存均为异步方法,示例应用未引入显式锁;由于入口集中在设置页且保存为一次性全量提交,当前并发模型足以满足需求。
扩展点与运维建议
新增设置项
若要新增一个配置项,按三步接入(与现有模式保持一致):
- 在
SettingManager增加loadXxx()/ 复用saveSettings的参数,并包裹try-catch兜底; - 在
_SettingPageState增加状态变量与_initialXxx快照,并加入_hasSettingsChanged()与_updateState()的变更路径; - 在
build()对应平台分支中新增SettingSection/SettingSwitchRow/SettingNavigationRow。
国际化
所有文案均通过 AppLocalizations.of(context)!(loc)获取,新增设置项时应同步在 l10n/app_localizations.dart 中补充多语言资源,保持页面可本地化。
调试入口(日志)
- 日志路径在页面顶部实时展示,指向原生 SDK 写入的日志目录;
- 「日志文件」入口在连接状态下进入
FileListPage,可查看/分享/下载日志文件,是排查 OTA 失败的首选手段; SettingManager的log()输出会进入 Flutter 调试控制台,便于开发期定位加载/保存异常。
测试与质量
仓库中本页相关测试未见独立测试文件;当前正确性保障主要依赖:加载方法的默认值兜底、保存方法的 rethrow 契约、以及连接状态守卫的 Toast 提示。若补充测试,建议优先覆盖:saveSettings 平台分支参数映射、loadXxx 异常兜底返回值、_hasSettingsChanged 的变更检测逻辑。
Related Links
- 设置页源码 setting_page.dart — 页面 UI 与交互实现
- 设置管理器源码 setting_manager.dart — 数据加载/保存封装
- 设置组件 widgets/setting_components.dart —
SettingSection/SettingSwitchRow/CommunicationOption等复用组件 - 导航行组件 widgets/setting_navigation_row_widget.dart — 导航行样式
- 相关页面:设备连接与扫描(Devices)、文件与升级流程(FileList / Update)、关于页面(About)、自定义命令(Custom Command)、UUID 输入页(Service UUID Input)
- SDK 桥接层:
package:jl_ota/ble_method.dart与package:jl_ota/constant/constants.dart(AppConstants通信方式常量)