flutter_usb_write 0.1.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 68

flutter_usb_write #

Write raw data to USB device on Android.

Unlike USB Serial plugin, this plugin DOES NOT use serial protocol.

For example this can be use to print on USB POS printer by sending ESC\POS bytes.

Supported Android devices #

Only devices with USB Host support (USB OTG) can communicate with USB devices.

Supported USB devices #

Potentially you can write to any USB device (see Limitations).

Plugin has been tested with multiple USB POS printers.

Features #

  • list connected USB devices
  • creates stream to listen on USB attached/detached events
  • obtain permissions automatically (see Permissions)
  • open connection to selected USB device
  • send bytes to USB devices using open connection
  • close open connection
  • send controlTransfer bytes

Limitations #

  • doesn't suppport receiving messages over USB connection (IE. out of paper message)
  • connection is fixed to first interface on selected USB device.
  • only supports USB_ENDPOINT_XFER_BULK endpoints
  • only supports USB endpoints where direction is NOT USB_DIR_IN

Permissions #

If you don't mind asking for permission everytime USB device is physically connected to Android device there's nothing to do. Plugin will ask for permissions when needed. However if you don't want to ask for permission everytime USB device is physically connected add

	<intent-filter>
		<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
	</intent-filter>

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

to your AndroidManifest.xml

and place device_filter.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 0x1CBE / 0x0003: USB POS printer 58 mm -->
    <usb-device vendor-id="7358" product-id="3" />
    <!-- 0x1CB0 / 0x0003: USB POS printer 58 mm -->
    <usb-device vendor-id="7344" product-id="3" />
    <!-- 0x0483 / 0x5740: USB POS printer 58 mm -->
    <usb-device vendor-id="1155" product-id="22336" />
    <!-- 0x0493 / 0x8760: USB POS printer 58 mm -->
    <usb-device vendor-id="1171" product-id="34656" />
    <!-- 0x0416 / 0x5011: USB POS printer 58 mm (Issyzone Pos IMP006B) -->
    <usb-device vendor-id="1046" product-id="20497" />
    <!-- 0x0416 / 0xAABB: USB POS printer 58 mm -->
    <usb-device vendor-id="1046" product-id="43707" />
    <!-- 0x1659 / 0x8965: USB POS printer 58 mm -->
    <usb-device vendor-id="5721" product-id="35173" />
    <!-- 0x0483 / 0x5741: USB POS printer 58 mm -->
    <usb-device vendor-id="1155" product-id="22337" />
    <!-- 0x4B43 / 0x3830: USB POS printer 80 mm (GoojPrt MTP-3) -->
    <usb-device vendor-id="19267" product-id="14384" />
    <!-- 0x0525 / 0xA700: USB POS printer 80 mm (MicroPOS WTP100II) -->
    <usb-device vendor-id="1317" product-id="42752" />
    <!-- 0x0525 / 0xA702: USB POS printer 58 mm (Sewoo LK-P20) -->
    <usb-device vendor-id="1317" product-id="42754" />
    <!-- 0x0416 / 0x5011: USB POS printer 58 mm -->
    <usb-device vendor-id="1046" product-id="20497" />      
</resources>

in the res/xml directory (modify accordingly to your devices). This will automatically open your application when USB device is physically connected. Once permission is allowed it won't ask anymore.

Getting Started #

First, you'll probably want to list all USB devices connected to you Android device.

try {
      List<UsbDevice> devices = await _flutterUsbPos.listDevices();
    } on PlatformException catch (e) {
      print(e.message);
    }

Once you found the device, you'll need to open connection before attempting to write. Each time you open connection device will get new deviceId. To open connection always use vid:pid parameters, method will return new UsbDevice object with deviceId value.

  Future<UsbDevice> _connect(UsbDevice device) async {
    try {
      var result = await _flutterUsbPos.open(
        vendorId: device.vid,
        productId: device.pid,
      );
      return result;
    } on PermissionException {
      print("Not allowed to do that");
      return null;
    } on PlatformException catch (e) {
      print(e.message);
      return null;
    }
  }

After that you can try to write to device. Function returns true if number of bytes written is >= 0;

bool result = await _flutterUsbPos.write(Uint8List.fromList("Hello world".codeUnits));

Once you're done writing, close connection to release resources.

   Future _disconnect() async {
    try {
      await _flutterUsbPos.close();
    } on PlatformException catch (e) {
      print(e.message);
    }
  }

For more info see tests and example project.

0.1.0 #

  • Published as plugin

0.0.1 #

  • First working version

example/lib/main.dart

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

import 'package:flutter_usb_write/flutter_usb_write.dart';
import 'package:pedantic/pedantic.dart';

void main() => runApp(MyApp());

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

class _MyAppState extends State<MyApp> {
  FlutterUsbWrite _flutterUsbWrite = FlutterUsbWrite();
  UsbEvent _lastEvent;
  StreamSubscription<UsbEvent> _usbStateSubscription;
  List<UsbDevice> _devices = [];
  int _connectedDeviceId;
  TextEditingController _textController =
      TextEditingController(text: "Hello world");
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  bool didInit = false;

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

  @override
  Future didChangeDependencies() async {
    super.didChangeDependencies();
    if (!didInit) {
      didInit = true;
      await _getPorts();
    }
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> createUsbListener() async {
    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _usbStateSubscription =
          _flutterUsbWrite.usbEventStream.listen((UsbEvent event) async {
        setState(() {
          _lastEvent = event;
        });
        await _getPorts();
        if (event.event.endsWith("USB_DEVICE_DETACHED")) {
          //check if connected device was detached
          if (event.device.deviceId == _connectedDeviceId) {
            unawaited(_disconnect());
          }
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: const Text('USB Device Example'),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.only(top: 15, bottom: 15),
                child: Text(
                    _devices.isNotEmpty
                        ? "Available USB Devices"
                        : "No USB devices available",
                    style: Theme.of(context).textTheme.title),
              ),
              ..._portList(),
              getInputTextBox(),
              Padding(
                padding: const EdgeInsets.only(top: 15, bottom: 15),
                child: getEventInfo(),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget getEventInfo() {
    if (_lastEvent == null) return SizedBox.shrink();
    if (_lastEvent.event.endsWith('USB_DEVICE_ATTACHED')) {
      return Text(
        _lastEvent.device.manufacturerName + ' ATTACHED',
        style: TextStyle(
          color: Colors.green,
          fontWeight: FontWeight.bold,
        ),
      );
    }
    return Text(
      _lastEvent.device.manufacturerName + ' DETACHED',
      style: TextStyle(
        color: Colors.red,
        fontWeight: FontWeight.bold,
      ),
    );
  }

  Widget getInputTextBox() {
    return Padding(
      padding: const EdgeInsets.only(top: 15, bottom: 15),
      child: ListTile(
        title: TextField(
          controller: _textController,
          decoration: InputDecoration(
            border: OutlineInputBorder(),
            labelText: 'Text To Send',
          ),
        ),
        trailing: RaisedButton(
          child: Text("Send"),
          onPressed: _connectedDeviceId == null
              ? null
              : () async {
                  if (_connectedDeviceId == null) {
                    return;
                  }
                  String data = _textController.text + "\r\n";
                  await _flutterUsbWrite
                      .write(Uint8List.fromList(data.codeUnits));
                },
        ),
      ),
    );
  }

  Future _getPorts() async {
    try {
      List<UsbDevice> devices = await _flutterUsbWrite.listDevices();
      setState(() {
        _devices = devices;
      });
    } on PlatformException catch (e) {
      showSnackBar(e.message);
    }
  }

  List<Widget> _portList() {
    List<Widget> ports = [];
    _devices.forEach((device) {
      ports.add(
        ListTile(
          leading: Icon(Icons.usb),
          title: Text(device.productName),
          subtitle: Text(device.manufacturerName),
          trailing: RaisedButton(
            child: Text(_connectedDeviceId == device.deviceId
                ? "Disconnect"
                : "Connect"),
            onPressed: () async {
              if (_connectedDeviceId == device.deviceId) {
                await _disconnect();
              } else {
                await _connect(device);
              }
            },
          ),
        ),
      );
    });
    if (ports.isEmpty) {
      ports.add(SizedBox.shrink());
    }
    return ports;
  }

  Future<UsbDevice> _connect(UsbDevice device) async {
    try {
      var result = await _flutterUsbWrite.open(
        vendorId: device.vid,
        productId: device.pid,
      );
      setState(() {
        _connectedDeviceId = result.deviceId;
      });
      return result;
    } on PermissionException {
      showSnackBar("Not allowed to do that");
      return null;
    } on PlatformException catch (e) {
      showSnackBar(e.message);
      return null;
    }
  }

  Future _disconnect() async {
    try {
      await _flutterUsbWrite.close();
      setState(() {
        _connectedDeviceId = null;
      });
    } on PlatformException catch (e) {
      showSnackBar(e.message);
    }
  }

  void showSnackBar(String message) {
    final snackBar = SnackBar(
      content: Text(message),
    );
    _scaffoldKey.currentState.showSnackBar(snackBar);
  }

  @override
  void dispose() {
    super.dispose();
    if (_usbStateSubscription != null) {
      _usbStateSubscription.cancel();
    }
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flutter_usb_write: ^0.1.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_usb_write/flutter_usb_write.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
45
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
75
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

We analyzed this package on Mar 30, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Maintenance suggestions

The package description is too short. (-20 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Homepage URL is insecure. (-5 points)

Update the homepage field and use a secure (https) URL.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.5.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
async ^2.4.0
flutter_test
mockito ^4.1.1
pedantic ^1.8.0