杰理 SDK 文档中心
首页
首页
  • 概览与快速开始

    • 项目概述与能力总览
    • 快速开始与 SDK 集成
  • SDK 核心接口

    • 发送接口 BleMethod
    • 接收接口 BleEventStream
    • 数据模型与常量定义
  • 平台原生实现

    • Android 原生层
    • iOS 原生层架构
    • iOS 蓝牙管理与 SDK 运行
    • 辅助连接与广播音箱
  • OTA 升级功能

    • 升级流程与传输通道
    • 自动回连机制
    • 复用空间升级
    • 自定义命令
  • 示例应用

    • 页面结构与用户旅程
    • 设备扫描与连接管理
    • 固件文件管理
    • 升级执行与状态展示
    • 设置与调试
  • 文档与支持

    • 接口文档与收发说明
    • 调试与问题排查

设备扫描与连接管理

JL_OTA_Flutter 示例应用中负责 BLE 设备发现(扫描)与连接生命周期管理的能力模块。它通过 BleMethod(MethodChannel)向原生端下发扫描/连接指令,并通过 BleEventStream(EventChannel)接收扫描结果与连接状态事件,最终由 OtaConnectionManager 消费连接事件并联动清理 OTA 会话数据。

Purpose and Scope

本页面向开发者完整说明「设备扫描与连接管理」这一子系统的实现机制,覆盖:

  • 扫描指令的发起与停止(BleMethod.startScan / BleMethod.stopScan)
  • 扫描结果与扫描状态的推送通道(BleEventStream.scanDeviceListStream / scanStateStream)
  • 设备连接与断开的指令(BleMethod.connectDevice / BleMethod.disconnectBtDevice)
  • 连接状态事件的消费(BleEventStream.deviceConnectionStream)
  • OTA 连接管理器如何订阅上述事件并触发数据清理(OtaConnectionManager)

以下内容属于兄弟页面,不在本页展开:OTA 升级流程本身、固件文件管理(ota_file_manager.dart)、各类对话框(dialog/ 目录)、设置管理(setting_manager.dart)。本页只关注「从扫描到连接成功、再到连接断开」这条链路。

Overview

在 JL_OTA 的示例应用架构中,蓝牙能力由原生插件(com.jieli.ble_plugin)提供,Flutter 侧通过两条标准化通道与原生端通信:

  1. MethodChannel(指令通道):com.jieli.ble_plugin/methods,由 BleMethod 封装。所有"动作"类调用——检查蓝牙环境、开始/停止扫描、连接/断开设备、设置扫描过滤与通讯方式——都以静态方法形式下发到原生端。
  2. EventChannel(事件通道):com.jieli.ble_plugin/events,由 BleEventStream 封装。原生端主动推送的"状态"类数据——蓝牙开关状态、扫描状态、扫描设备列表、设备连接状态、OTA 连接状态——都以广播流形式暴露给 UI 层。

这一"指令/事件分离"的设计意图在于:扫描与连接是异步的、由原生 BLE 栈驱动的过程,Flutter 侧无法也不应轮询设备状态,而是通过事件流被动接收。BleEventStream.baseStream 采用单例模式(??= 只初始化一次),保证整个应用共享同一条原生广播流,避免重复订阅造成的事件丢失或资源浪费。

连接成功后,OtaConnectionManager 订阅设备连接流与 OTA 连接流,一旦设备断开(状态为 AppConstants.connectionDisconnect)或 OTA 连接事件触发,立即调用 onOtaDataCleaned 回调,将上一轮 OTA 会话的临时数据清空——这是保证"设备换了、旧数据不能残留"的关键联动逻辑。

Architecture

flowchart TD
    subgraph sg_Flutter["Flutter 应用层"]
        UI["UI 界面 / 业务逻辑"]
        ConnMgr["OtaConnectionManager"]
    end

    subgraph sg_Plugin["BLE 插件封装层 (libs/)"]
        BleMethod["BleMethod<br/>MethodChannel 指令封装"]
        BleEventStream["BleEventStream<br/>EventChannel 事件流"]
        BaseStream["baseStream 单例广播流"]
    end

    subgraph sg_Native["原生 Android 插件"]
        Native["com.jieli.ble_plugin<br/>原生 BLE 实现"]
        BLE["BLE 硬件 / 蓝牙栈"]
    end

    UI -->|"startScan / connectDevice<br/>/ disconnectBtDevice"| BleMethod
    BleMethod -->|"invokeMethod"| Native
    Native -->|"扫描结果 / 连接状态<br/>广播事件"| BaseStream
    BaseStream --> BleEventStream
    BleEventStream -->|"scanDeviceListStream<br/>deviceConnectionStream"| UI
    BleEventStream -->|"otaConnectionStream<br/>deviceConnectionStream"| ConnMgr
    ConnMgr -->|"onOtaDataCleaned"| UI
    Native <-->|"GATT / 扫描回调"| BLE

架构要点:

  • 指令下行:UI 层只依赖 BleMethod 的静态方法,不直接接触 MethodChannel,屏蔽了平台通道细节;方法内部统一捕获 PlatformException 并 rethrow,保证错误向上层传播且可被调用方感知。
  • 事件上行:原生端把扫描设备列表、连接状态等事件推入 EventChannel;BleEventStream 用 where + map 组合子按 KEY_TYPE 过滤出各语义流(扫描列表流、连接状态流等),并对 Map 数据执行 ScanDevice.fromMap / DeviceConnection.fromMap 反序列化,UI 层拿到的是强类型对象而非原始 Map。
  • 会话联动:OtaConnectionManager 是两个订阅的汇聚点——设备连接流(判断断开)与 OTA 连接流(判断 OTA 会话变化)任一触发清理逻辑,确保 OTA 数据与当前设备绑定。

扫描流程详解

设备扫描是「发现可连接设备」的第一步。Flutter 侧只负责下发指令与接收结果,实际的 BLE 扫描由原生插件驱动。

扫描的发起与停止

BleMethod 提供三个与扫描直接相关的静态方法:

// 检查是否正在扫描
static Future<bool> isScanning() async {
  try {
    return await _methodChannel.invokeMethod(
          BleMethodConstants.METHOD_IS_SCANNING,
        ) ??
        false;
  } on PlatformException catch (e) {
    print("Failed to check if scanning: ${e.message}");
    rethrow;
  }
}

// 开始扫描
static Future<void> startScan() async {
  try {
    await _methodChannel.invokeMethod(BleMethodConstants.METHOD_START_SCAN);
  } on PlatformException catch (e) {
    print("Failed to start scan: ${e.message}");
    rethrow;
  }
}

// 停止扫描
static Future<void> stopScan() async {
  try {
    await _methodChannel.invokeMethod(BleMethodConstants.METHOD_STOP_SCAN);
  } on PlatformException catch (e) {
    print("Failed to stop scan: ${e.message}");
    rethrow;
  }
}

Source: ble_method.dart

设计意图:

  • 扫描是"发后不管"的异步操作。startScan() 立即返回,扫描到的设备通过事件流持续推送,因此调用方不需要等待任何结果,只需在 UI 生命周期合适时机(如页面进入/退出)调用 start/stop 配对。
  • 幂等检查。isScanning() 用于在 UI 层避免重复启动扫描(例如下拉刷新时先检查),返回值 ?? false 意味着原生端异常时按"未扫描"处理,不会阻塞界面。
  • 统一错误出口。每个方法都捕获 PlatformException 打印日志后 rethrow,让上层(页面或管理器)可以决定是提示用户还是静默处理。

扫描过滤

原生端维护一个"过滤字符串",用于在扫描时只上报名称或地址匹配的设备,减少无效事件:

// 读取当前过滤字符串
static Future<String?> getScanFilter() async {
  try {
    return await _methodChannel.invokeMethod<String>(
      BleMethodConstants.METHOD_GET_SCAN_FILTER,
    );
  } on PlatformException catch (e) {
    print("Failed to get scan filter: ${e.message}");
    rethrow;
  }
}

// 设置新的过滤字符串
static Future<void> setScanFilter(String? filter) async {
  try {
    await _methodChannel.invokeMethod(
      BleMethodConstants.METHOD_SET_SCAN_FILTER,
      {BleMethodConstants.ARG_FILTER: filter},
    );
  } on PlatformException catch (e) {
    print("Failed to set scan filter: ${e.message}");
    rethrow;
  }
}

Source: ble_method.dart

过滤逻辑发生在原生侧,而非 Flutter 侧,这样扫描结果从源头就被裁剪,降低事件通道的负载与 UI 层的过滤成本。示例应用中的 device_filter_dialog.dart 即为该能力的 UI 入口。

扫描结果接收

原生端扫描到设备后,通过 EventChannel 推送类型为 TYPE_SCAN_DEVICE_LIST 的事件,BleEventStream 将其转换为强类型流:

// 扫描设备列表流
static Stream<List<ScanDevice>> get scanDeviceListStream {
  return baseStream
      .where((event) => event is Map && event[BleEventConstants.KEY_TYPE] == BleEventConstants.TYPE_SCAN_DEVICE_LIST)
      .map((event) {
    final list = event[BleEventConstants.KEY_VALUE][BleEventConstants.KEY_LIST] as List? ?? [];
    return list
        .whereType<Map>()
        .map((deviceMap) => ScanDevice.fromMap(deviceMap))
        .toList();
  });
}

Source: ble_event_stream.dart

转换管线分三步:先按事件类型过滤,再从 KEY_VALUE.KEY_LIST 提取设备数组,最后逐个 ScanDevice.fromMap 反序列化。?? [] 与 whereType<Map>() 的防御性处理保证原生端返回异常结构时流不会崩溃,而是产出空列表——扫描页面据此刷新为"暂无设备"状态。每次事件推送的都是完整列表(而非增量),因此 UI 层订阅后直接整体替换即可,天然规避了增量合并的竞态问题。

连接管理详解

连接管理负责把扫描列表中的设备建立/断开 GATT 连接,并把连接状态反馈给业务层。

连接与断开指令

// 连接设备
static Future<void> connectDevice(int index) async {
  try {
    await _methodChannel.invokeMethod(
      BleMethodConstants.METHOD_CONNECT_DEVICE,
      {BleMethodConstants.ARG_INDEX: index},
    );
  } on PlatformException catch (e) {
    print("Failed to connect device at index $index: ${e.message}");
    rethrow;
  }
}

// 断开设备连接
static Future<void> disconnectBtDevice(int index) async {
  try {
    await _methodChannel.invokeMethod(
      BleMethodConstants.METHOD_DISCONNECT_BT_DEVICE,
      {BleMethodConstants.ARG_INDEX: index},
    );
  } on PlatformException catch (e) {
    print("Failed to disconnect device at index $index: ${e.message}");
    rethrow;
  }
}

Source: ble_method.dart

关键设计:按索引寻址而非按地址寻址。 两个方法都以扫描列表中的 index 为参数,这意味着调用方必须持有与原生端一致的设备列表顺序。示例应用的扫描页面将 scanDeviceListStream 的列表顺序视为唯一事实来源,用户点击列表项时直接把该行索引传给 connectDevice。这样的好处是:原生端不需要暴露完整的设备地址/名称协议,Flutter 侧只传一个 int,通道载荷极小;代价是两端列表必须严格同步——这也是为什么扫描列表采用"整表推送"而非增量推送。

连接状态接收

// 设备连接状态流
static Stream<DeviceConnection> get deviceConnectionStream {
  return baseStream
      .where((event) {
    return event is Map && event[BleEventConstants.KEY_TYPE] == BleEventConstants.TYPE_DEVICE_CONNECTION;
  })
      .map((event) {
    final data = event[BleEventConstants.KEY_VALUE];
    return DeviceConnection.fromMap(data);
  });
}

Source: ble_event_stream.dart

原生端在连接状态变化(连接中、已连接、断开等)时推送 TYPE_DEVICE_CONNECTION 事件,DeviceConnection 对象携带 state 字段。业务层通过 AppConstants.connectionDisconnect 常量判定"已断开",从而触发后续清理逻辑(见下文 OtaConnectionManager)。

通讯方式与 SDK 蓝牙开关

BleMethod 还暴露了连接相关的运行时配置读写接口,用于切换通讯方式(如 BLE 经典/低功耗)以及是否使用 SDK 自带的蓝牙连接实现:

// 读取当前使用的通讯方式
static Future<int> getConnectWay() async {
  try {
    return await _methodChannel.invokeMethod(
          BleMethodConstants.METHOD_GET_CONNECT_WAY,
        ) ??
        true;
  } on PlatformException catch (e) {
    print("Failed to check if BLE way is used: ${e.message}");
    rethrow;
  }
}

// 设置当前使用的通讯方式
static Future<void> setConnectWay(int connectWay) async {
  await _methodChannel.invokeMethod(BleMethodConstants.METHOD_SET_CONNECT_WAY, {
    BleMethodConstants.ARG_CONNECT_WAY: connectWay,
  });
}

Source: ble_method.dart

这些配置属于持久化的连接偏好,通常在进入扫描页面前由设置管理(setting_manager.dart)读取并写入,扫描与连接行为随后按此偏好执行。注意 getConnectWay 的兜底值写法为 ?? true(int 类型的布尔兜底),这是插件封装层的一个既有实现细节,语义上表示"原生端无返回时默认走 BLE 方式"。

OtaConnectionManager:连接事件与会话数据的联动

OtaConnectionManager 是连接管理链路在业务侧的核心消费者。它不直接发起扫描或连接,而是监听两个事件流,把「连接生命周期」翻译成「OTA 会话数据清理」动作:

/// Manages OTA update connections and device connections.
class OtaConnectionManager {
  final Function onOtaDataCleaned;
  StreamSubscription<Map<String, dynamic>>? _otaConnectionSubscription;
  StreamSubscription<DeviceConnection>? _deviceConnectionSubscription;

  OtaConnectionManager({required this.onOtaDataCleaned});

  void subscribeToOtaConnectionStream() {
    _otaConnectionSubscription?.cancel();
    _otaConnectionSubscription = BleEventStream.otaConnectionStream.listen((otaData) {
      onOtaDataCleaned();
    });
  }

  void subscribeToDeviceConnectionStream() {
    _deviceConnectionSubscription?.cancel();
    _deviceConnectionSubscription = BleEventStream.deviceConnectionStream.listen((connection) {
      if (connection.state == AppConstants.connectionDisconnect) {
        onOtaDataCleaned();
      }
    }) as StreamSubscription<DeviceConnection>?;
  }

  void dispose() {
    _otaConnectionSubscription?.cancel();
    _deviceConnectionSubscription?.cancel();
  }
}

Source: ota_connection_manager.dart

设计意图逐点拆解:

  • 职责单一。管理器只做"事件 → 回调"的翻译:OTA 连接事件一到就清理(表示进入了新的 OTA 会话),设备断开事件一到也清理(表示当前会话的设备已离开)。实际的数据清理由外部注入的 onOtaDataCleaned 回调完成,管理器不感知 OTA 数据的具体形态,便于替换与测试。
  • 重复订阅保护。每个 subscribeToXxxStream 先 cancel() 旧订阅再重新订阅,防止页面重建或重复初始化时产生多个监听者导致回调多次触发。
  • 状态过滤。设备连接流里只对 connectionDisconnect 状态响应,忽略连接中/已连接等中间态——因为只有断开才意味着"上一轮 OTA 数据必须失效"。
  • 资源释放。dispose() 成对取消两个订阅,与订阅方法对称,避免内存泄漏。

这一联动解决了真实场景中的关键一致性问题:用户给设备 A 做完 OTA 后断开,再连接设备 B 时,若不清理,残留的升级进度、临时文件或日志会串到设备 B 的会话中。连接断开即清理,从根上保证了「一个设备一个会话」。

Core Flow:扫描 → 连接 → 状态回传

sequenceDiagram
    participant UI as 扫描页面 / 业务层
    participant BM as BleMethod (MethodChannel)
    participant Native as 原生 BLE 插件
    participant ES as BleEventStream (EventChannel)
    participant OCM as OtaConnectionManager

    UI->>BM: checkBluetoothEnvironment()
    BM-->>UI: 环境可用
    UI->>BM: startScan()
    BM->>Native: METHOD_START_SCAN
    Native->>Native: 底层 BLE 扫描
    Native->>ES: TYPE_SCAN_DEVICE_LIST 事件(整表)
    ES-->>UI: scanDeviceListStream 推送 List&lt;ScanDevice&gt;
    UI->>UI: 渲染设备列表
    UI->>BM: connectDevice(index)
    BM->>Native: METHOD_CONNECT_DEVICE (index)
    Native->>Native: GATT 连接流程
    Native->>ES: TYPE_DEVICE_CONNECTION 事件
    ES-->>UI: deviceConnectionStream 推送 DeviceConnection
    ES-->>OCM: deviceConnectionStream 推送 DeviceConnection
    OCM->>OCM: state == connectionDisconnect ?<br/>onOtaDataCleaned() : 忽略
    UI->>BM: disconnectBtDevice(index) 或 stopScan()

流程说明:

  1. 进入扫描页前先调用 checkBluetoothEnvironment() 确认蓝牙可用,失败时引导用户开启蓝牙(对应事件流中的 bluetoothStateStream 也用于监听运行时开关状态)。
  2. startScan() 下发指令后,原生端持续扫描,每次结果变化都以完整列表形式推送 TYPE_SCAN_DEVICE_LIST 事件。
  3. scanDeviceListStream 反序列化出 List<ScanDevice>,UI 层整体替换列表渲染。
  4. 用户点击某一项,把该行 index 传给 connectDevice(index);原生端建立 GATT 连接。
  5. 连接状态变化通过 TYPE_DEVICE_CONNECTION 事件广播,deviceConnectionStream 同时被 UI 层与 OtaConnectionManager 订阅——UI 更新界面状态,管理器判断是否为断开事件并决定是否清理 OTA 数据。
  6. 页面退出或主动断开时调用 disconnectBtDevice(index) / stopScan(),指令侧与事件侧形成完整闭环。

Usage Examples

示例一:启动扫描并订阅设备列表

以下模式取自示例应用的扫描页典型用法——先检查环境,再启动扫描,同时订阅设备列表流:

// 检查蓝牙环境是否可用
final bool isAvailable = await BleMethod.checkBluetoothEnvironment();
if (isAvailable) {
  await BleMethod.startScan();
}

// 订阅扫描设备列表(整表推送,直接替换)
BleEventStream.scanDeviceListStream.listen((devices) {
  // 用 devices 刷新列表 UI
});

Source: ble_method.dart 与 ble_event_stream.dart

示例二:按索引连接设备

// 用户点击设备列表第 index 项
await BleMethod.connectDevice(index);

// 通过连接状态流感知结果
BleEventStream.deviceConnectionStream.listen((connection) {
  if (connection.state == AppConstants.connectionDisconnect) {
    // 设备断开:刷新 UI 为未连接状态
  }
});

Source: ble_method.dart 与 ble_event_stream.dart

示例三:连接管理器的订阅与释放

final manager = OtaConnectionManager(onOtaDataCleaned: () {
  // 清空上一轮 OTA 的临时文件与进度数据
});
manager.subscribeToOtaConnectionStream();
manager.subscribeToDeviceConnectionStream();
// ... 页面销毁时
manager.dispose();

Source: ota_connection_manager.dart

API Reference

BleMethod(指令封装,静态方法)

方法签名说明平台方法/参数
Future<bool> isScanning()查询原生端是否正在扫描,失败兜底 falseMETHOD_IS_SCANNING
Future<bool> checkBluetoothEnvironment()检查蓝牙环境(开关、权限)是否可用METHOD_CHECK_BLUETOOTH_ENVIRONMENT
Future<void> startScan()启动 BLE 扫描,异步返回,结果走事件流METHOD_START_SCAN
Future<void> stopScan()停止 BLE 扫描METHOD_STOP_SCAN
Future<String?> getScanFilter()读取当前扫描过滤字符串METHOD_GET_SCAN_FILTER
Future<void> setScanFilter(String? filter)设置扫描过滤字符串METHOD_SET_SCAN_FILTER,参数 ARG_FILTER
Future<void> connectDevice(int index)按扫描列表索引连接设备METHOD_CONNECT_DEVICE,参数 ARG_INDEX
Future<void> disconnectBtDevice(int index)按索引断开设备METHOD_DISCONNECT_BT_DEVICE,参数 ARG_INDEX
Future<int> getConnectWay()读取当前通讯方式METHOD_GET_CONNECT_WAY
Future<void> setConnectWay(int connectWay)设置通讯方式METHOD_SET_CONNECT_WAY,参数 ARG_CONNECT_WAY
Future<bool> isUseSdkBluetooth()是否使用 SDK 蓝牙连接实现METHOD_IS_USING_SDK_BLUETOOTH
Future<void> setConnectUsingSdkBluetooth(bool isUsingSDKBluetooth)设置是否使用 SDK 蓝牙连接METHOD_SET_USING_SDK_BLUETOOTH,参数 ARG_IS_USING_SDK_BLUETOOTH

Throws(所有方法): PlatformException —— 原生端调用失败时抛出,封装层打印日志后 rethrow,由调用方决定如何处理。

BleEventStream(事件封装,静态流属性)

流属性返回类型事件类型说明
baseStreamStream<dynamic>—单例原始广播流,所有语义流的数据源
bluetoothStateStreamStream<bool>TYPE_BLUETOOTH_STATE蓝牙开关状态变化
scanStateStreamStream<String>TYPE_SCAN_DEVICE_LIST扫描状态(如扫描中/停止)
scanDeviceListStreamStream<List<ScanDevice>>TYPE_SCAN_DEVICE_LIST扫描设备完整列表(整表推送)
deviceConnectionStreamStream<DeviceConnection>TYPE_DEVICE_CONNECTION设备连接状态(含 state 字段)
otaConnectionStreamStream<Map<String, dynamic>>TYPE_OTA_CONNECTIONOTA 连接状态(含 state、deviceType)

OtaConnectionManager(会话联动管理器)

方法说明
OtaConnectionManager({required Function onOtaDataCleaned})构造器,注入清理回调
void subscribeToOtaConnectionStream()订阅 OTA 连接流,每次事件触发 onOtaDataCleaned()
void subscribeToDeviceConnectionStream()订阅设备连接流,仅当 state == connectionDisconnect 时触发清理
void dispose()取消全部订阅,释放资源

Configuration Options

扫描与连接行为没有独立的配置文件,运行时偏好通过 BleMethod 的 setter 下发并在原生端持久化:

配置项类型默认/兜底说明
扫描过滤字符串String?null(不过滤)setScanFilter 设置,原生端按名称/地址过滤扫描结果
通讯方式int?? true(原生无返回时默认 BLE)setConnectWay 设置,决定连接使用的蓝牙传输方式
是否使用 SDK 蓝牙bool?? truesetConnectUsingSdkBluetooth 设置,切换 SDK 自带连接实现与系统默认连接

Failure Modes, Edge Cases & Concurrency

PlatformException 与重抛策略

BleMethod 的所有方法在 PlatformException 时打印日志并 rethrow。这意味着:

  • 调用方必须捕获异常,否则会冒泡为未处理异常。扫描页通常在进入时对 checkBluetoothEnvironment 做 try/catch 并引导用户处理。
  • 打印日志只做诊断,不吞错误——错误语义完整保留给上层。

扫描/连接的异步竞态

  • 整表推送规避增量竞态:扫描列表每次推送完整列表,UI 直接替换,不会出现两次增量事件交错导致列表错乱。
  • 索引寻址的前提:connectDevice(index) 依赖列表顺序与原生端一致。若用户在扫描停止后仍持有旧索引,或列表被新扫描结果替换,索引可能指向错误设备甚至越界——示例应用通过"停止扫描后才允许点击连接"或"每次列表刷新重置选中态"来规避。
  • 重复订阅:OtaConnectionManager 的订阅方法先 cancel 再订阅;若业务代码不遵守该模式(如页面热重载反复 listen),回调可能重复触发,清理逻辑执行多次。虽无害(清理是幂等的),但属于应避免的模式。

连接断开的边界

  • 设备物理断开(走远、关机)时原生端推送断开事件,OtaConnectionManager 据此清理 OTA 数据;若原生端未及时上报,UI 可能短暂停留在"已连接"假象——deviceConnectionStream 的被动性决定了该延迟无法完全消除。
  • 蓝牙全局关闭时,bluetoothStateStream 推送 false,UI 应同时停止扫描并置灰连接入口,避免 connectDevice 在不可用环境下发。

Performance & Operational Notes

  • 事件通道为共享单例:baseStream 只初始化一次,多个订阅者共享同一原生流,无重复注册开销;但订阅者不使用时必须取消订阅,否则会持续接收事件。
  • 扫描结果负载:扫描列表整表推送,设备数量大时单次事件载荷较高。可通过 setScanFilter 在原生侧裁剪结果,这是推荐的降载手段。
  • 连接状态事件频率:连接过程会产生多次状态变化事件,OtaConnectionManager 通过状态过滤只关心断开态,业务 UI 也应按需订阅、及时取消,避免不必要的重建。

Extension Points

  • 新增连接相关指令:在原生插件 MethodChannel 注册新方法名,并在 BleMethod 中增加静态方法封装,保持"指令走 Method、事件走 EventChannel"的既有约定。
  • 扩展设备模型:ScanDevice / DeviceConnection 的 fromMap 是反序列化唯一入口,新增字段只需在模型中补充映射,事件流管线无需改动。
  • 替换清理逻辑:OtaConnectionManager.onOtaDataCleaned 为注入式回调,可在示例应用外层替换为自定义清理策略(如保留断点续传数据)而不修改管理器本身。

Related Links

  • BLE 事件常量定义(事件类型与键名来源)
  • BLE 方法常量定义(MethodChannel 方法名与参数键来源)
  • BLE 插件原生实现(com.jieli.ble_plugin 原生侧扫描/GATT 逻辑)
  • 设备过滤对话框(扫描过滤功能的 UI 入口)
  • 同一示例应用的兄弟页面:OTA 升级流程、文件管理(ota_file_manager.dart)、设置管理(setting_manager.dart)——这些能力在各自目录页中单独说明。
Prev
页面结构与用户旅程
Next
固件文件管理