Flutter硬件接口访问插件hid的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter硬件接口访问插件hid的使用

hid 插件是一个多平台插件,允许应用程序在 Linux、Windows、Android 和 macOS 上与 USB HID 类设备进行交互。

完整示例代码

以下是一个完整的示例代码,展示了如何使用 hid 插件来列出连接到设备的所有 HID 设备,并展示其相关信息。

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:hid/hid.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Device>? _hidDevices;

  @override
  void initState() {
    super.initState();
    _listDevices();
  }

  // 平台消息是异步的,因此我们在异步方法中初始化。
  Future<void> _listDevices() async {
    setState(() {
      _hidDevices = null;
    });

    final hidDevices = await getDeviceList();
    hidDevices.sort((a, b) => a.usage?.compareTo(b.usage ?? 0) ?? 0);
    hidDevices.sort((a, b) => a.usagePage?.compareTo(b.usagePage ?? 0) ?? 0);
    hidDevices.sort((a, b) => a.productId.compareTo(b.productId));
    hidDevices.sort((a, b) => a.vendorId.compareTo(b.vendorId));
    hidDevices.sort((a, b) => a.productName.compareTo(b.productName));

    // 如果小部件在异步平台消息还在飞行时从树中移除,则我们希望丢弃回复而不是调用
    // setState 更新我们的不存在的外观。
    if (!mounted) return;

    setState(() {
      _hidDevices = hidDevices;
    });
  }

  _getUsagePageIcon(int? usagePage, int? usage) {
    // 根据 usagePage 和 usage 返回相应的图标
    switch (usagePage) {
      case 0x01:
        switch (usage) {
          case 0x01:
            return Icons.north_west;
          case 0x02:
            return Icons.mouse;
          case 0x04:
          case 0x05:
            return Icons.gamepad;
          case 0x06:
            return Icons.keyboard;
        }
        return Icons.computer;
      case 0x0b:
        switch (usage) {
          case 0x04:
          case 0x05:
            return Icons.headset_mic;
        }
        return Icons.phone;
      case 0x0c:
        return Icons.toggle_on;
      case 0x0d:
        return Icons.touch_app;
      case 0xf1d0:
        return Icons.security;
    }
    return Icons.usb;
  }

  @override
  Widget build(BuildContext context) {
    final dev = _hidDevices;

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('HID 插件示例应用'),
        ),
        body: dev == null
            ? const Center(child: CircularProgressIndicator())
            : ListView.builder(
                itemCount: dev.length,
                itemBuilder: (context, index) => ListTile(
                  leading: Icon(_getUsagePageIcon(
                      dev[index].usagePage, dev[index].usage)),
                  title: Text(dev[index].productName),
                  subtitle: Text(
                      '${dev[index].vendorId.toRadixString(16).padLeft(4, '0')}:${dev[index].productId.toRadixString(16).padLeft(4, '0')}   ${dev[index].serialNumber}'),
                ),
              ),
        floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.refresh),
          onPressed: dev == null ? null : _listDevices,
        ),
      ),
    );
  }
}

代码说明

  1. 导入必要的库

    import 'dart:async';
    import 'package:flutter/material.dart';
    import 'package:hid/hid.dart';
    
  2. 主函数

    void main() {
      runApp(const MyApp());
    }
    
  3. 创建一个状态管理类 _MyAppState

    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
  4. 初始化设备列表

    class _MyAppState extends State<MyApp> {
      List<Device>? _hidDevices;
    
      @override
      void initState() {
        super.initState();
        _listDevices();
      }
    
  5. 获取设备列表

    Future<void> _listDevices() async {
      setState(() {
        _hidDevices = null;
      });
    
      final hidDevices = await getDeviceList();
      hidDevices.sort((a, b) => a.usage?.compareTo(b.usage ?? 0) ?? 0);
      hidDevices.sort((a, b) => a.usagePage?.compareTo(b.usagePage ?? 0) ?? 0);
      hidDevices.sort((a, b) => a.productId.compareTo(b.productId));
      hidDevices.sort((a, b) => a.vendorId.compareTo(b.vendorId));
      hidDevices.sort((a, b) => a.productName.compareTo(b.productName));
    
      if (!mounted) return;
    
      setState(() {
        _hidDevices = hidDevices;
      });
    }
    
  6. 根据设备类型返回对应的图标

    _getUsagePageIcon(int? usagePage, int? usage) {
      switch (usagePage) {
        case 0x01:
          switch (usage) {
            case 0x01:
              return Icons.north_west;
            case 0x02:
              return Icons.mouse;
            case 0x04:
            case 0x05:
              return Icons.gamepad;
            case 0x06:
              return Icons.keyboard;
          }
          return Icons.computer;
        case 0x0b:
          switch (usage) {
            case 0x04:
            case 0x05:
              return Icons.headset_mic;
          }
          return Icons.phone;
        case 0x0c:
          return Icons.toggle_on;
        case 0x0d:
          return Icons.touch_app;
        case 0xf1d0:
          return Icons.security;
      }
      return Icons.usb;
    }
    
  7. 构建界面

    @override
    Widget build(BuildContext context) {
      final dev = _hidDevices;
    
      return MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('HID 插件示例应用'),
          ),
          body: dev == null
              ? const Center(child: CircularProgressIndicator())
              : ListView.builder(
                  itemCount: dev.length,
                  itemBuilder: (context, index) => ListTile(
                    leading: Icon(_getUsagePageIcon(
                        dev[index].usagePage, dev[index].usage)),
                    title: Text(dev[index].productName),
                    subtitle: Text(
                        '${dev[index].vendorId.toRadixString(16).padLeft(4, '0')}:${dev[index].productId.toRadixString(16).padLeft(4, '0')}   ${dev[index].serialNumber}'),
                  ),
                ),
          floatingActionButton: FloatingActionButton(
            child: const Icon(Icons.refresh),
            onPressed: dev == null ? null : _listDevices,
          ),
        ),
      );
    }
    

更多关于Flutter硬件接口访问插件hid的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter硬件接口访问插件hid的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中访问硬件接口(如HID设备)通常需要使用平台通道(Platform Channels)与原生代码进行交互。由于HID(Human Interface Devices)设备的访问涉及到底层系统API,Flutter本身并不直接提供对HID设备的访问能力,因此我们需要通过插件来实现这一功能。

以下是一个简单的示例,展示如何创建一个Flutter插件来访问HID设备。这个示例将分为两部分:Flutter前端代码和原生后端代码(包括Android和iOS)。

Flutter 前端代码

首先,创建一个新的Flutter项目,并添加一个自定义插件。

  1. 创建一个新的Flutter项目:
flutter create flutter_hid_example
cd flutter_hid_example
  1. 添加自定义插件:

flutter_hid_example/目录下,运行以下命令来生成插件模板:

flutter create --template=plugin flutter_hid_plugin

这将创建一个名为flutter_hid_plugin的目录,其中包含插件的代码结构。

  1. flutter_hid_example/pubspec.yaml中添加对插件的依赖:
dependencies:
  flutter:
    sdk: flutter
  flutter_hid_plugin:
    path: ../flutter_hid_plugin
  1. 使用插件在Flutter中访问HID设备:

flutter_hid_example/lib/main.dart中,编写如下代码:

import 'package:flutter/material.dart';
import 'package:flutter_hid_plugin/flutter_hid_plugin.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String deviceInfo = "";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter HID Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('HID Device Info:'),
              Text(deviceInfo),
              ElevatedButton(
                onPressed: _listDevices,
                child: Text('List HID Devices'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _listDevices() async {
    try {
      String result = await FlutterHidPlugin.listDevices();
      setState(() {
        deviceInfo = result;
      });
    } catch (e) {
      setState(() {
        deviceInfo = "Error: ${e.message}";
      });
    }
  }
}

原生后端代码

接下来,我们需要在原生代码中实现HID设备的访问逻辑。

Android

  1. flutter_hid_plugin/android/src/main/java/com/example/flutter_hid_plugin/FlutterHidPlugin.java中,编写如下代码:
package com.example.flutter_hid_plugin;

import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceManager;
import android.hardware.usb.UsbManager;
import java.util.List;

public class FlutterHidPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  private MethodChannel channel;
  private ActivityPluginBinding activityBinding;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_hid_plugin");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("listDevices")) {
      List<UsbDevice> devices = getUsbDevices();
      StringBuilder sb = new StringBuilder();
      for (UsbDevice device : devices) {
        sb.append(device.getDeviceName()).append("\n");
      }
      result.success(sb.toString());
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  private List<UsbDevice> getUsbDevices() {
    UsbManager usbManager = (UsbManager) activityBinding.getActivity().getSystemService(android.content.Context.USB_SERVICE);
    return (usbManager != null) ? usbManager.getDeviceList().values() : null;
  }

  @Override
  public void onAttachedToActivity(ActivityPluginBinding binding) {
    activityBinding = binding;
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {
    activityBinding = null;
  }

  @Override
  public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
    activityBinding = binding;
  }

  @Override
  public void onDetachedFromActivity() {
    activityBinding = null;
  }
}

注意:这个示例仅列出了USB设备,并没有进行HID设备的具体筛选和访问。实际项目中,你可能需要使用更具体的HID API或库来处理HID设备。

iOS

iOS上访问HID设备通常需要使用IOKit框架。由于iOS开发的复杂性,这里仅提供一个简单的框架搭建思路,具体实现需要更深入的iOS开发知识。

  1. flutter_hid_plugin/ios/Classes/FlutterHidPlugin.swift中,编写如下代码:
import Flutter
import IOKit.hid

public class FlutterHidPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterRegistrar) {
    let channel = FlutterMethodChannel(name: "flutter_hid_plugin", binaryMessenger: registrar.messenger())
    let instance = FlutterHidPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    if call.method == "listDevices" {
      let devices = listDevices()
      result(devices)
    } else {
      result(FlutterMethodNotImplementedError(methodName: call.method))
    }
  }

  private func listDevices() -> [String] {
    var deviceNames: [String] = []
    // TODO: Implement HID device listing using IOKit
    return deviceNames
  }
}

注意:在iOS上,你需要使用IOKit框架来列出和访问HID设备。这通常涉及到底层C语言的调用和Objective-C/Swift的桥接,可能需要较深的iOS系统级开发知识。

总结

上述代码提供了一个基本的框架,展示了如何在Flutter中通过平台通道访问原生代码。然而,由于HID设备的访问涉及到底层系统API,实际项目中你可能需要更深入地了解相关平台的API和库,以完成HID设备的具体访问和操作。

请根据你的具体需求和目标平台的API文档,进一步完善和扩展上述代码。

回到顶部