Mobile Development 14 min read

Integrating Serial Port, USB, Printers, and Input Devices in Android Applications

This article provides a comprehensive guide for Android developers on how to connect and use serial ports, USB peripherals, printers, barcode scanners, payment boxes, keyboards, and mice, including required permissions, configuration steps, and sample Kotlin/Java code snippets for each device type.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Integrating Serial Port, USB, Printers, and Input Devices in Android Applications

In Android embedded device development, developers often need to interface with serial ports, USB devices, printers, barcode scanners, payment boxes, keyboards, and mice. This guide outlines the essential steps and code examples for each scenario.

Serial Port Integration

Download the serial port library (containing libprt_serial_port.so ) and use the provided SerialPort class. Example Kotlin code demonstrates opening the device, obtaining input/output streams, and handling I/O:

public class SerialPort {
    private static final String TAG = "SerialPort";
    private FileDescriptor mFd;
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;
    public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
        mFd = open(device.getAbsolutePath(), baudrate, flags);
        if (mFd == null) {
            Log.e(TAG, "native open returns null");
            throw new IOException();
        }
        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }
    public InputStream getInputStream() { return mFileInputStream; }
    public OutputStream getOutputStream() { return mFileOutputStream; }
    private native static FileDescriptor open(String path, int baudrate, int flags);
    public native void close();
    static { System.loadLibrary("serial_port"); }
}

To use the port, configure the device path (e.g., /dev/ttyS4 ) and baud rate (e.g., 9600), then read/write via the streams:

val serialPort = SerialPort(File("/dev/ttyS4"), 9600, 0)
val inputStream = serialPort.inputStream
val outputStream = serialPort.outputStream
val length = inputStream!!.available()
val bytes = ByteArray(length)
inputStream.read(bytes)

USB Integration

Add the necessary permissions and features to AndroidManifest.xml :

<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-feature android:name="android.hardware.usb.host" />
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />

Prevent activity recreation on USB plug/unplug by adding android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation" to the activity declaration.

Example Kotlin code shows how to obtain the UsbManager , request permission, detect attached devices, and connect to a USB printer:

mUsbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
mPermissionIntent = PendingIntent.getBroadcast(context, 0, Intent(ACTION_USB_PERMISSION), 0)
val filter = IntentFilter(USBPrinter.ACTION_USB_PERMISSION)
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
context.registerReceiver(mUsbDeviceReceiver, filter)
setUsbDevices()

private fun setUsbDevices() {
    mUsbManager?.deviceList?.let {
        for (device in it.values) {
            val usbInterface = device.getInterface(0)
            if (usbInterface.interfaceClass == 7) { // USB printer class
                if (!mUsbManager!!.hasPermission(device)) {
                    mUsbManager!!.requestPermission(device, mPermissionIntent)
                } else {
                    connectUsbPrinter(device)
                }
                break
            }
        }
    }
}

private val mUsbDeviceReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        if (ACTION_USB_PERMISSION == action) {
            synchronized(this) {
                val usbDevice = intent.getParcelableExtra
(UsbManager.EXTRA_DEVICE)
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    mUsbDevice = usbDevice
                    if (mUsbDevice != null) connectUsbPrinter(mUsbDevice)
                } else {
                    WLog.e(this, "Permission denied for device $usbDevice")
                }
            }
        } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED == action) {
            // device attached
        } else if (UsbManager.ACTION_USB_DEVICE_DETACHED == action) {
            if (mUsbDevice != null) {
                WLog.e(this, "Device closed")
                mUsbDeviceConnection?.close()
            }
        }
    }
}

After obtaining the UsbEndpoint and UsbInterface , data can be sent to the printer using bulkTransfer :

fun write(bytes: ByteArray) {
    if (mUsbDeviceConnection != null) {
        try {
            mUsbDeviceConnection!!.claimInterface(usbInterface, true)
            val result = mUsbDeviceConnection!!.bulkTransfer(printerEp, bytes, bytes.size, USBPrinter.TIME_OUT)
            mUsbDeviceConnection!!.releaseInterface(usbInterface)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

Printer Command Set

Common ESC/POS commands are provided as static Java methods, e.g., initializing the printer, setting alignment, and cutting paper:

public static byte[] init_printer() {
    byte[] result = new byte[2];
    result[0] = ESC;
    result[1] = 0x40;
    return result;
}

public static byte[] alignLeft() {
    byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 97;
    result[2] = 0;
    return result;
}

public static byte[] cutter() {
    byte[] box = new byte[6];
    box[0] = 0x1B;
    box[1] = 0x64;
    box[2] = 0x01;
    box[3] = 0x1d;
    box[4] = 0x56;
    box[5] = 0x31;
    return box;
}

Printing text is done by converting the string to GBK bytes and sending them via the write method.

fun printText(msg: String) {
    try {
        write(msg.toByteArray(charset("gbk")))
    } catch (e: UnsupportedEncodingException) {
        e.printStackTrace()
    }
}

Bitmap printing uses the raster command sequence:

public static byte[] printBitmap(Bitmap bitmap) {
    byte[] header = new byte[]{GS, 0x76, 0x30, 0x00};
    byte[] data = getBytesFromBitMap(bitmap);
    return byteMerger(header, data);
}

Barcode Scanner, Payment Box, Keyboard, and Mouse

These devices are also USB HID peripherals. They can be handled either via broadcast receivers (e.g., registering a SCAN_ACTION intent) or by intercepting key events in an activity:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    if (KeyUtils.doNotSwitchViewPagerByKey(keyCode)) return true
    scanHelpL.get().acceptKey(this, keyCode) { viewModel.scanByBarcode(it) }
    return super.onKeyDown(keyCode, event)
}

The utility class KeyUtils maps key codes to characters, handling shift states and special keys. When the Enter key is detected, the accumulated barcode string is submitted for further processing.

It is important to avoid focusing editable UI components (e.g., EditText ) when using these input devices, as they would automatically capture the scanned data.

Conclusion

The article demonstrates how Android developers can quickly integrate serial ports, USB peripherals, printers, barcode scanners, payment boxes, keyboards, and mice into their applications, providing code snippets and configuration details. Future articles will cover Bluetooth devices, multi‑screen handling, and more advanced scenarios.

JavaandroidKotlinusbBarcode ScannerPrinterSerial Port
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.