游刃有余 —— PC 端 USB 设备检测实现

224 阅读3分钟

Flutter PC项目中USB设备检测实现指南

一、需求背景

在Flutter桌面(PC)应用开发中,USB设备检测是一个常见需求

  • 工业控制与自动化应用

  • 硬件调试工具

  • 物联网设备管理

  • 数据采集与传输系统

本文详细介绍如何通过 在Flutter PC项目中实现USB设备检测功能。

二、插件选型分析

2.1 为什么选择usb_serial插件?

在评估了多个可能的解决方案后,本项目选择了usb_serial ^0.5.0插件,主要基于以下理由:

选型因素usb_serial 优势其他方案不足
跨平台支持支持 Windows、macOS 和 Linux许多 USB 插件仅支持移动平台
易用性API 设计直观,易于集成某些原生 API 封装复杂
社区活跃度持续更新维护部分插件已停止更新
功能完整性支持设备列表获取、连接和通信部分轻量级插件功能有限
权限处理内置基本的权限处理机制需自行实现复杂的权限逻辑

2.2 辅助插件选择

usb_serial外,项目还集成了device_info_plus ^10.1.2插件,用于获取当前操作系统信息,帮助更好地处理平台差异性。

三、实现架构与核心代码解析

3.1 整体架构设计

本项目采用分层架构实现USB设备检测功能:

  • 服务层UsbDetectionService类负责核心检测逻辑

  • 模型层UsbDeviceInfo类定义设备信息结构

  • UI层MyHomePage组件负责界面展示与交互


flowchart TD

A[用户界面] --> |初始化请求| B[UsbDetectionService]

B --> |调用API| C[usb_serial插件]

B --> |获取系统信息| D[device_info_plus插件]

C --> |返回设备列表| B

B --> |状态更新| A

B --> |设备数据| A

E[定期扫描] --> |触发刷新| B

3.2 核心服务实现

UsbDetectionService类是整个USB检测功能的核心,采用单例模式实现:


class UsbDetectionService {

static final UsbDetectionService _instance = UsbDetectionService._internal();

    factory UsbDetectionService() => _instance;
    UsbDetectionService._internal();

    // 成员变量...

    Future<bool> initialize() async {

        try {

            _statusStreamController.add('正在初始化USB服务...');

        // USB Serial 不需要显式初始化
            _isInitialized = true;
            if (_isInitialized) {
                _statusStreamController.add('USB服务初始化成功');
                await _refreshDeviceList();
            _startPeriodicScanning();

        }

        // ...

}

整体调用

sequenceDiagram

participant UI as 用户界面 (main.dart)

participant Service as USB检测服务 (UsbDetectionService)

participant Plugin as USB Serial插件

participant Device as USB设备

  


UI->>Service: 初始化服务(initialize)

Service-->>Plugin: 调用listDevices()

Plugin-->>Device: 扫描USB设备

Device-->>Plugin: 返回设备列表

Plugin-->>Service: 返回原始设备信息

Service-->>Service: 转换为UsbDeviceInfo

Service-->>UI: 通过deviceStream推送设备信息

UI-->>UI: 更新设备列表显示

  


loop 定期扫描

Service->>Plugin: 每3秒调用listDevices()

Plugin->>Device: 扫描USB设备

Device->>Plugin: 返回更新的设备列表

Plugin->>Service: 返回设备信息

Service->>UI: 通过deviceStream推送更新

UI->>UI: 更新设备列表显示

end

  


UI->>Service: 手动刷新(refreshDevices)

Service->>Plugin: 调用listDevices()

Plugin->>Device: 立即扫描设备

Device->>Plugin: 返回设备列表

Plugin->>Service: 返回设备信息

Service->>UI: 通过deviceStream推送更新

UI->>UI: 更新设备列表显示

  

UI->>Service: 获取系统信息(getSystemInfo)

Service-->>UI: 返回系统信息

该服务主要包含以下关键功能:

  1. 设备扫描机制:通过_refreshDeviceList()方法获取连接的USB设备列表

Future<void> _refreshDeviceList() async {

    if (!_isInitialized) return;

        try {
            _statusStreamController.add('正在扫描USB设备...');
            List<UsbDevice> devices = await UsbSerial.listDevices();
            List<UsbDeviceInfo> deviceInfoList = [];
            // 处理设备信息...
            _connectedDevices = deviceInfoList;
            _deviceStreamController.add(_connectedDevices);
            _statusStreamController.add('发现 ${_connectedDevices.length} 个USB设备');

        }

    // ...

}

  1. 定期检测功能:通过定时器实现设备状态的持续监控

void _startPeriodicScanning() {
    _periodicTimer?.cancel();
    _periodicTimer = Timer.periodic(
    const Duration(seconds: 3),
    (timer) => _refreshDeviceList(),
    );

}

  1. 事件流通信:使用StreamController实现UI与服务层的解耦

final StreamController<List<UsbDeviceInfo>> _deviceStreamController = StreamController<List<UsbDeviceInfo>>.broadcast();

final StreamController<String> _statusStreamController = StreamController<String>.broadcast();

3.3 设备信息模型

UsbDeviceInfo类定义了USB设备的数据结构,并提供了一些辅助方法:


class UsbDeviceInfo {
    final int vendorId;
    final int productId;
    final String? manufacturer;
    final String? product;
    final String? serialNumber;
    final UsbDeviceStatus status;
    final DateTime lastSeen;
    // 构造函数...

    String get displayName {
    // 生成显示名称...
    }

    String get deviceId => '${vendorId.toRadixString(16).padLeft(4,'0')}:${productId.toRadixString(16).padLeft(4, '0')}'.toUpperCase();

}

3.4 UI层集成

在主界面MyHomePage中,通过状态管理与服务层进行交互:


class _MyHomePageState extends State<MyHomePage> {
    final UsbDetectionService _usbService = UsbDetectionService();
    List<UsbDeviceInfo> _devices = [];
    String _statusMessage = '正在初始化...';

    Future<void> _initializeUsb() async {
        bool initialized = await _usbService.initialize();
        String systemInfo = await _usbService.getSystemInfo();
        _isInitialized = initialized;
        _systemInfo = systemInfo;

        // 监听设备和状态变化
        _usbService.deviceStream.listen((devices) {
            setState(() {
                _devices = devices;
            });
        });

        _usbService.statusStream.listen((status) {
            setState(() {
                _statusMessage = status;
            });

        });
    }
}

四、使用流程与最佳实践

4.1 基本使用流程

  1. 添加依赖
dependencies:
    usb_serial: ^0.5.0
    device_info_plus: ^10.1.2
  1. 初始化服务

final UsbDetectionService _usbService = UsbDetectionService();
await _usbService.initialize();

  1. 监听设备变化

_usbService.deviceStream.listen((devices) {
// 处理设备列表更新
});

  1. 手动刷新设备
await _usbService.refreshDevices();

4.2 最佳实践

  1. 服务生命周期管理
  • 在Widget的initState()中初始化服务

  • dispose()中释放资源,避免内存泄漏


@override
void dispose() {
    _usbService.dispose();
    super.dispose();
}

  1. 错误处理机制
  • 对异步操作进行try-catch包装

  • 提供友好的错误提示给用户

  1. 定期扫描间隔调整
  • 根据应用需求调整扫描频率,避免过高频率影响性能
_periodicTimer = Timer.periodic(
    const Duration(seconds: 3), // 可根据需求调整
    (timer) => _refreshDeviceList(),

);

总结

介绍了在Flutter PC项目中实现USB设备检测的完整流程,通过使用usb_serial插件并结合适当的架构设计,可以有效地解决Flutter桌面应用中的USB设备检测需求,为工业控制、硬件调试、物联网等场景提供可靠的技术支持。

通过采用单例模式的服务设计、事件流通信机制和定期扫描策略,可以构建出高性能、可维护的USB设备检测功能,同时保持良好的用户体验。在实际应用中,还需要根据具体需求和平台特性进行适当的调整和优化。

image.png

GitHub:flutter_study/usb_detector_demo at master · lizy-coding/flutter_study