Push Validation

Libusb Android Helper

libusb_android has the restriction on (unrooted) Android that no USB devices can be listed and found. See libusb android readme

This helper plugin closes this gap by using the native Java API to find and open the devices and retrieve the native file descriptor to continue working with it in libusb_android.

Flutter plugins cannot contain native C (ffi) and Java code at the same time, hence the split into two plugins.

Getting Started

Add a dependency to your pubspec.yaml

dependencies:
	libusb_android_helper: ^1.0.0

include the libusb_android_helper package at the top of your dart file.

import 'package:libusb_android_helper/libusb_android_helper.dart';

Optional

Add

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-feature android:name="android.hardware.usb.host" />
    ...
    <application ... >
        <activity ... >
        ...
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/>
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                    android:resource="@xml/device_filter" />
            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_DETACHED"
                android:resource="@xml/device_filter" />
        </activity>
    </application>
<manifest>

to your AndroidManifest.xml

and place device_filter.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="[Your vid]" product-id="[Your pid]" />
</resources>

in the res/xml directory. This will notify your app when one of the specified devices is connected or disconnected.

Usage

List all devices already connected:

Future<List<UsbDevice>> getUsbDevices() async {
    List<UsbDevice>? devices;
    try {
        devices = await LibusbAndroidHelper.listDevices();
    } on PlatformException catch (e) {
        return List<UsbDevice>.empty();
    }
    if (devices != null) {
        return devices;
    } else {
        return List<UsbDevice>.empty();
    }
}

Get notified when a USB device is connected or disconnected:

LibusbAndroidHelper.usbEventStream?.listen((event) {
    try {
        if (event.action == UsbAction.usbDeviceAttached) {
            _device = event.device;
        } else if (event.action == UsbAction.usbDeviceDetached) {
            _device = null;
        }
    } on PlatformException catch (e) {
        // error
    }
});

Request authorization to access the USB device from the user:

if (!(await device.hasPermission())){
    await device.requestPermission();
}

Open the device and pass the native handle to libusb_android

const String _libName = 'libusb_android';
final DynamicLibrary _dynamicLibrary = () {
  if (Platform.isAndroid) {
    return DynamicLibrary.open('lib$_libName.so');
  }
  throw UnsupportedError('Unsupported platform: ${Platform.operatingSystem}');
}();
final LibusbAndroidBindings _bindings = LibusbAndroidBindings(_dynamicLibrary);
// ...
if (await device?.open()) {
    int retValue = 0;
    Pointer<Pointer<libusb_context>> context = calloc<Pointer<libusb_context>>();
    Pointer<Pointer<libusb_device_handle>> deviceHandle = calloc<Pointer<libusb_device_handle>>();
    
    retValue = _bindings.libusb_set_option(context.value, libusb_option.LIBUSB_OPTION_NO_DEVICE_DISCOVERY);
    if (retValue < 0) {
        return;
    }

    retValue =_bindings.libusb_init(context);
    if (retValue < 0) {
        return;
    }

    retValue = _bindings.libusb_wrap_sys_device(context.value, device!.handle, deviceHandle);
    if (retValue < 0) {
        return;
    }

    Pointer<libusb_device> device = _bindings.libusb_get_device(deviceHandle.value);

    // Work with device
}
// ...
// Don't forget
calloc.free(context);
calloc.free(dev_handle);