Library / SDK
mik3y/usb-serial-for-android avatar
mik3y/usb-serial-for-android

usb-serial-for-android: a Java USB host serial driver for Android OTG

Android USB host serial driver library for CDC, FTDI, Arduino and other devices.

5,694 stars1,694 forksJavaMIT

At a glance

What is it?
The library gives Android apps a raw serial port over USB Host Mode with no root and no kernel drivers. It is a Gradle dependency, not an app, and its limits are as concrete as its device list.
Who is it for?
Adopt usb-serial-for-android if you are writing a native Android app in Java or Kotlin, your device speaks one of the supported chip protocols or generic CDC/ACM, and you need read() and write() rather than a terminal. Do not adopt it if you are targeting Flutter or React Native without writing a platform channel, or if your hardware uses a converter chip outside the supported list and you cannot supply a custom prober.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 74 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What usb-serial-for-android actually solves

Android's USB Host Mode, available since Android 3.1 and described in the README as working reliably since Android 4.2, exposes USB devices to apps through UsbManager. What it does not expose is a serial port. A USB to serial converter appears as a USB device with vendor-specific interfaces, and without a driver the app sees raw endpoints and bulk transfers, not bytes on a line at 115200 baud.

This library fills that gap in Java. The README states that no root access, ADK, or special kernel drivers are required, and that all drivers are implemented in Java. The audience is narrow and specific: Android developers writing native apps that talk to Arduinos, FTDI cables, PL2303 adapters, CP2102 boards, CH340 and CH341A converters, and devices speaking generic CDC/ACM. If your app is written in Flutter or React Native, this library does not drop in; you would need a platform channel or an existing plugin wrapping it.

The prober and driver architecture

The mechanism is a two-stage lookup. UsbSerialProber walks the tree of connected UsbDevices and produces a list of UsbSerialDriver instances. The default prober, returned by UsbSerialProber.getDefaultProber(), matches on USB interface types plus a built-in table of well-known vendor and product IDs. Each driver class knows how to talk to one chip family: FTDI, Prolific PL2303, Silabs CP210x, Qinheng CH34x, plus device-specific drivers for GsmModem devices such as Unisoc based Fibocom modems and Chrome OS CCD (Closed Case Debugging).

Once a driver is found, you open a UsbDeviceConnection through UsbManager, take a UsbSerialPort from driver.getPorts(), and call port.open(connection). Port parameters are set explicitly, as in the README's example: port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE). From there you have two read paths. Direct calls to port.write() and port.read() with millisecond timeouts, or a SerialInputOutputManager started with start() that delivers data to an onNewData(byte[]) callback. The event-driven path exists because blocking reads on the main thread are not viable in an Android app.

One design note from the README is easy to miss: as of v3.5.0 the library detects CDC/ACM devices by USB interface types instead of fixed VID and PID pairs, so custom probers are typically not required any more for CDC/ACM devices. That change reduces the maintenance burden for anyone whose hardware follows the class specification, and it is why a brand new CDC/ACM board often works without a library update.

Installing it and opening a first port

The library is distributed through JitPack, not Maven Central. Add the repository to your root build.gradle, then add the dependency. The README shows version 3.11.0 in the dependency line, which matches the most recent release listed.

gradle
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
gradle
dependencies {
    implementation 'com.github.mik3y:usb-serial-for-android:3.11.0'
}

If you want the app notified when a device is attached, copy device_filter.xml into your project's res/xml/ directory and declare the intent filter in AndroidManifest.xml. The README gives the exact activity block, with the action android.hardware.usb.action.USB_DEVICE_ATTACHED and a meta-data element pointing at @xml/device_filter.

xml
<activity
    android:name="..."
    ...>
    <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" />
</activity>

With that in place, the first real use is finding a driver and opening the port. The README's snippet queries UsbSerialProber.getDefaultProber().findAllDrivers(manager), returns early if the list is empty, opens the first driver, and configures 115200 8N1.

java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
    return;
}

UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
    // add UsbManager.requestPermission(driver.getDevice(), ..) handling here
    return;
}

UsbSerialPort port = driver.getPorts().get(0);
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);

What you should see after this runs is a non-null connection and an open port; writes then go out with port.write(request, WRITE_WAIT_MILLIS) and reads come back with port.read(response, READ_WAIT_MILLIS). For a working reference, the repository ships a usbSerialExamples folder, and the README points to the separate SimpleUsbTerminal project for a more complete example with a background service and flow control.

Permission handling is the part that bites

The snippet above contains the library's most common failure mode, and the README flags it in a comment rather than in prose: if manager.openDevice() returns null, the app has no permission for that device. The README tells you to add UsbManager.requestPermission(driver.getDevice(), ..) handling there. An app that copies the example and stops at the null check will work on a device where permission was previously granted and silently do nothing everywhere else.

There is a second boundary worth stating plainly. The library is not a terminal application and does not ship a UI. It gives you a raw port and read() and write() calls; framing, line endings, retries and protocol logic are yours. The README's onNewData example appends new String(data) straight into a TextView, which is fine for a demo and wrong for binary protocols, since it decodes bytes as text on every callback.

The third limit is hardware. The compatible device list is explicit: FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD; Prolific PL2303; Silabs CP2102 and CP210*; Qinheng CH340 and CH341A; plus GsmModem devices, Chrome OS CCD, and generic CDC/ACM implementations such as Qinheng CH343 and CH9102, Microchip MCP2221, Arduino boards using ATmega32U4, and Digispark devices using V-USB software USB. A converter outside that set is not automatically supported. The README's answer is the custom prober: build a ProbeTable, call addProduct with your VID and PID and a driver class, and pass the table to a new UsbSerialProber.

A custom prober for an unrecognized converter

When a device is compatible with a built-in driver but uses a VID and PID the library does not know, the README shows the escape hatch. You register the product IDs against a driver class and probe with your own table instead of the default one.

java
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class);
customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class);

UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);

This is the right tool when you know the chip family and only the identifiers are new. It is the wrong tool when the chip is genuinely different, because you are asserting a driver match on the basis of VID and PID alone. The README also notes that nothing requires UsbSerialProber at all: you can instantiate driver classes directly if you know what you are doing, as long as you supply a compatible UsbDevice.

How it compares to the Android USB API alone

The realistic alternative is not another library; it is writing the driver yourself against Android's UsbDeviceConnection and UsbEndpoint classes. The difference in approach is substantial. With the raw API you enumerate interfaces, claim them, find bulk-in and bulk-out endpoints, and implement the control transfers each chip family needs for baud rate, stop bits and parity. That is a per-chip effort, and it is exactly the work this library has already done for FTDI, PL2303, CP210x, CH34x and CDC/ACM.

The trade-off runs the other way too. The raw API has no opinion about your hardware and never tells you a device is unsupported, because you are the one writing the matching logic. This library's default prober will not return a driver for a device outside its table, and its abstraction assumes a serial port shape: one or more ports, settable parameters, bulk reads and writes. If your USB device is not a serial port at all, this library adds nothing. For a device that is a serial port on a supported chip, it removes the largest block of low-level work in the project.

Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-07-18, the same day as the 3.11.0 release. The two releases before that were 3.10.0 on 2025-12-05 and v3.9.0 on 2025-03-10. The spacing suggests a release cadence measured in months rather than weeks, which matters if you depend on a chip that was added recently.

The licence is MIT, stated in the repository metadata and present as LICENSE.txt at the top level. MIT is permissive: it allows commercial and closed-source use with the copyright notice and permission notice retained. That is a description of the licence text, not legal advice, and your own compliance review should confirm how attribution is handled in your app's notices.

Upgrade cost is low but not zero. The dependency is pinned to a JitPack coordinate that includes the version, for example com.github.mik3y:usb-serial-for-android:3.11.0, so upgrades are explicit edits to build.gradle. The README documents one behaviour change with real upgrade impact: since v3.5.0, CDC/ACM detection uses USB interface types rather than fixed VID and PID pairs. If you maintain a custom prober for a CDC/ACM device from before that change, it may now be redundant. The CHANGELOG.txt at the repository root is where the project records release-level detail beyond the README.

Editorial conclusion

Adopt usb-serial-for-android if you are writing a native Android app in Java or Kotlin, your device speaks one of the supported chip protocols or generic CDC/ACM, and you need read() and write() rather than a terminal. Do not adopt it if you are targeting Flutter or React Native without writing a platform channel, or if your hardware uses a converter chip outside the supported list and you cannot supply a custom prober. Before committing, verify two things: that your exact VID and PID appear in the prober's built-in table, and that your app handles UsbManager.requestPermission, because the README's own example returns early when openDevice returns null.

Frequently asked questions

Does usb-serial-for-android require root on the Android device?

No. The README states that no root access, ADK, or special kernel drivers are required, and that all drivers are implemented in Java. It relies on Android USB Host Mode, available since Android 3.1 and described as working reliably since Android 4.2.

How do I install usb-serial-for-android in a Gradle project?

Add the JitPack repository, maven { url 'https://jitpack.io' }, to your root build.gradle or settings.gradle, then add the dependency implementation 'com.github.mik3y:usb-serial-for-android:3.11.0'. The README also gives a Kotlin DSL variant using maven(url = "https://jitpack.io").

Which USB to serial chips does usb-serial-for-android support?

The README lists FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X and FT234XD, Prolific PL2303, Silabs CP2102 and CP210*, and Qinheng CH340 and CH341A, plus GsmModem devices and Chrome OS CCD, and generic CDC/ACM devices such as Qinheng CH343 and CH9102, Microchip MCP2221, Arduino boards using ATmega32U4 and Digispark.

What should I do if my device is not recognized by the default prober?

Build a ProbeTable, register your vendor and product IDs against a driver class with addProduct, and construct a UsbSerialProber from that table instead of using UsbSerialProber.getDefaultProber(). The README notes that since v3.5.0 CDC/ACM devices are detected by USB interface types, so a custom prober is usually unnecessary for those.

Does usb-serial-for-android work with Flutter or React Native?

The README describes a Java library consumed as a Gradle dependency and does not document Flutter or React Native bindings. Using it from those frameworks would require a platform channel or a separate plugin that wraps it.

Official sources

  1. Issues
  2. License: MIT
  3. mik3y/usb-serial-for-android on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mik3y-usb-serial-for-android.svg)](https://hysenlabs.com/projects/mik3y-usb-serial-for-android)