Open source · BSD-3-Clause · 4 packages on pub.dev
Flutter plugins for real hardware.
skio connects Flutter apps to USB serial devices, UART ports and USB cameras,
on Android, macOS, Windows, Linux and in the browser.
It calls native APIs directly with jnigen, dart:ffi and
dart:js_interop, so there are no platform channels, and the logic lives in
testable Dart.
Illustration of the calls in the code sample below.
ESP32
STM32
Nordic nRF
Arduino
CP210x
CH340
FTDI
PL2303
CDC-ACM
Android USB OTG
macOS
Web Serial
UART
RS-232
RS-485
Android panels
Jetson
Raspberry Pi
Windows COM ports
UVC cameras
Endoscopes
Microscopes
USB webcams
ESP32
STM32
Nordic nRF
Arduino
CP210x
CH340
FTDI
PL2303
CDC-ACM
Android USB OTG
macOS
Web Serial
UART
RS-232
RS-485
Android panels
Jetson
Raspberry Pi
Windows COM ports
UVC cameras
Endoscopes
Microscopes
USB webcams
Packages
One family, one way of doing things.
Each package covers one transport. They share permissions, errors, serial settings and device matching through skio_core.
Stable · v0.2
skio_usb_serial
Send and receive data with USB serial devices: Arduino and ESP32 boards, USB-to-serial adapters, instruments. Android over USB OTG, macOS apps, and Chrome or Edge with Web Serial. Windows and Linux are in progress.
Open serial ports by path: the UART, RS-232 and RS-485 ports built into Android panels, Jetson and Raspberry Pi boards, Windows COM ports and USB adapters on Linux and macOS. Pure Dart FFI, nothing native to build, and it also runs in Dart command-line tools.
USB cameras (endoscopes, microscopes, webcams) on Android and the web: live preview, JPEG photos, the camera's snapshot button, and your choice of resolution. macOS, Windows and Linux are in progress.
skio calls the platform APIs through generated bindings and dart:ffi. Buffering, framing and timeouts run in Dart, where you can test them. The diagram shows USB serial; skio_uart goes through dart:ffi to libc on Android, Linux and macOS and to kernel32 on Windows, and skio_uvc_camera takes the same path to UVCAndroid on Android and getUserMedia in the browser.
Your app
Flutter UIWidgets, state and your device's protocol.
skio · Dart
UsbSerialPortOrdered writes, timeouts, LineReader, one HardwareException type.
Android
jnigen → UsbManagerDirect JNI calls, USB OTG.
macOS
dart:ffi → IOKit + termiosNo native code to compile.
Web
js_interop → Web SerialChrome and Edge.
Hardware
Your deviceCP210x, CH340, FTDI or CDC-ACM over USB.
MethodChannelNo platform channel in between: no message codec, no stringly-typed method names. Typed calls go from Dart to the OS.
What it looks like
A small API that stays out of your way.
Open a USB adapter or a UART and exchange bytes, or open a camera and take a photo. Errors come from one sealed type, so a switch can handle every case.
DeviceFilterto match ports by vendor and product ID
SerialConfigfor baud rate, data bits, parity, stop bits and flow control
dtr / rtsset in the config, so ESP32 and Arduino boards don't reset on open
LineReaderfor lines and UTF-8 split across reads
UvcSizeto choose the camera resolution from what it supports
SkioLogopt-in logs, down to every byte, for bug reports
final ports = awaitUsbSerialPort.list();
final port = awaitUsbSerialPort.open(ports.first,
config: constSerialConfig(baudRate: 115200));
port.input.listen((bytes) => print(bytes));
await port.write(utf8.encode('hello\n'));
await port.close();
// '/dev/ttyS3' on a panel, 'COM3' on Windows, '/dev/ttyTHS1' on a Jetsonfinal port = awaitSerialPort.open('/dev/ttyS3',
config: constSerialConfig(baudRate: 9600));
port.input.transform(constLineReader()).listen(print);
await port.write(utf8.encode('READ\r\n'));
await port.close();
final cameras = awaitUvcCamera.devices();
awaitUvcCamera.access.requestAccess(cameras.first);
final cam = awaitUvcCamera.open(cameras.first,
preferred: const [UvcSize(1920, 1080), UvcSize(1280, 720)]);
// in build(): UvcPreview(camera: cam)final photo = await cam.capture(quality: 90);
cam.buttonPresses.listen((_) => cam.capture());
try {
// ... call any skio plugin
} onHardwareExceptioncatch (e) {
final advice = switch (e) {
AccessDenied() => 'Please allow access.',
Disconnected() || DeviceNotFound() => 'Reconnect the device.',
DeviceBusy() => 'Close other apps using it.',
_ => e.message,
};
}
Platform support
Where each package runs.
All four packages are on pub.dev. The stable ones have been tested with real hardware on Android, macOS and the web; skio_uart is new and in beta.
Package
Android
macOS
Windows
Linux
Web
skio_usb_serialUSB serial adapters and boards
stableUSB OTG, Android 7.0+
stableAny /dev/cu.* port
in progressUse skio_uart today
in progressUse skio_uart today
stableWeb Serial, Chrome and Edge
skio_uartSerial ports by path
betaBuilt-in UARTs, /dev/ttyS*
beta/dev/cu.*
betaAny COM port
betaJetson, Raspberry Pi, PCs
n/aNo serial ports in browsers
skio_uvc_cameraUSB (UVC) cameras
stableUSB OTG, Android 7.0+
in progress
in progress
in progress
stablegetUserMedia; no snapshot button
skio_coreShared types
pure Dart
pure Dart
pure Dart
pure Dart
pure Dart
In progress
in progressWindowsUSB serial and USB cameras. Serial ports already work with skio_uart.
in progressLinuxUSB serial and USB cameras, starting with Ubuntu. Serial ports already work with skio_uart.
in progressmacOSUSB cameras. USB serial already works on macOS.
coming sooniPadUSB cameras on iPadOS 17 and later. Apple does not let iPhone or iPad apps use USB serial adapters.
Tested on:
vivo
OPPO
Samsung
POCO
Mac
Chrome on macOS
USB serial boards and chips:
ESP32
STM32
Nordic nRF
CP210x
CH340 / CH9102
FTDI
PL2303
CDC-ACM
Get started
Add it to your app in one line.
Each package's README on pub.dev explains every feature with examples.
Add a package
One command each. skio_core comes with them. skio_uart also works with dart pub add.