
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
react-native-serial-transport
Advanced tools
USB Serial Port communication for React Native with ESP32/ESP8266 flashing support.
npm install react-native-serial-transport
# or
yarn add react-native-serial-transport
Choose your setup method based on your project type:
If you're using Expo (SDK 48+), setup is automatic!
{
"expo": {
"name": "My App",
"plugins": [
"react-native-serial-transport"
]
}
}
# For development builds
npx expo prebuild --clean
npx expo run:android
# For production builds with EAS
eas build --platform android
That's it! The plugin automatically:
If you need to support additional USB vendor IDs:
{
"expo": {
"plugins": [
[
"react-native-serial-transport",
{
"vendorIds": [4292, 6790, 1027, 1659, 5840]
}
]
]
}
}
Common vendor IDs:
4292 (0x10C4) - Silicon Labs CP210x (ESP32, ESP8266)6790 (0x1A86) - QinHeng CH340/CH3411027 (0x0403) - FTDI chips1659 (0x067B) - Prolific PL23035840 (0x16D0) - MCS (some ESP boards)For bare React Native projects or Expo projects with custom native code:
For React Native 0.60+, auto-linking handles this automatically. No manual linking needed!
# Just install and rebuild
yarn add react-native-serial-transport
cd android && ./gradlew clean
cd .. && npx react-native run-android
Add to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- USB Permissions -->
<uses-permission android:name="android.permission.USB_PERMISSION" />
<!-- USB Feature (not required but recommended) -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<application>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<!-- Main intent filter (already exists) -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- ADD THIS: USB device attached intent filter -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<!-- ADD THIS: Reference to device filter -->
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>
Create android/app/src/main/res/xml/device_filter.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- CP210x Silicon Labs (ESP32, ESP8266) -->
<usb-device vendor-id="4292" />
<!-- CH340/CH341 USB to Serial -->
<usb-device vendor-id="6790" />
<!-- FTDI chips -->
<usb-device vendor-id="1027" />
<!-- Prolific PL2303 -->
<usb-device vendor-id="1659" />
<!-- Optional: Specific product IDs -->
<!-- <usb-device vendor-id="4292" product-id="60000" /> -->
</resources>
Note: You may need to create the xml directory if it doesn't exist:
mkdir -p android/app/src/main/res/xml
cd android && ./gradlew clean
cd .. && npx react-native run-android
If you've already ejected from Expo or are using a bare workflow:
app.config.js (even in bare projects)import { SerialTransport } from 'react-native-serial-transport';
async function connectToESP() {
const transport = new SerialTransport();
try {
// List available USB devices
const devices = await transport.listDevices();
console.log('Available devices:', devices);
// Connect to device (auto-selects ESP device)
const result = await transport.connect(undefined, 115200);
console.log(result); // 'Connected to <device> at 115200 band'
// Write data
const data = new Uint8Array([0x01, 0x02, 0x03]);
await transport.write(data);
// Read data with timeout
const received = await transport.rawRead(1000);
console.log('Received:', received);
// Control DTR/RTS for ESP32 reset
await transport.setDTR(false);
await transport.setRTS(true);
await new Promise(resolve => setTimeout(resolve, 100));
await transport.setDTR(true);
await transport.setRTS(false);
// Disconnect
await transport.disconnect();
} catch (error) {
console.error('Error:', error);
}
}
import NativeSerialPort from 'react-native-serial-transport';
const devices = await NativeSerialPort.listDevices();
devices.forEach(device => {
console.log(`Device: ${device.productName}`);
console.log(`Vendor ID: 0x${device.vendorId.toString(16)}`);
console.log(`Product ID: 0x${device.productId.toString(16)}`);
console.log(`Serial Number: ${device.serialNumber}`);
});
import { SerialTransport } from 'react-native-serial-transport';
const transport = new SerialTransport();
// Connect to specific device by name
await transport.connect('/dev/bus/usb/001/002', 115200);
// Or let it auto-select ESP device
await transport.connect(undefined, 115200);
This library is designed to be compatible with esptool-js:
import { ESPLoader } from 'esptool-js';
import { SerialTransport } from 'react-native-serial-transport';
async function flashESP32() {
// Create transport
const transport = new SerialTransport();
await transport.connect(undefined, 115200);
// Create ESPLoader with custom transport
const loader = new ESPLoader({
transport: transport,
baudrate: 115200,
terminal: {
clean: () => {},
writeLine: (text: string) => console.log(text),
write: (text: string) => console.log(text)
}
});
try {
// Connect and detect chip
await loader.connect();
console.log(`Connected to ${loader.chip.CHIP_NAME}`);
// Flash firmware
await loader.writeFlash({
fileArray: [{
data: firmwareData,
address: 0x1000
}],
flashSize: 'keep',
flashMode: 'dio',
flashFreq: '40m',
eraseAll: false,
compress: true,
reportProgress: (fileIndex, written, total) => {
console.log(`Progress: ${written}/${total}`);
}
});
console.log('Flash complete!');
} finally {
await loader.disconnect();
await transport.disconnect();
}
}
import { NativeEventEmitter, NativeModules } from 'react-native';
const { RNSerialPort } = NativeModules;
const eventEmitter = new NativeEventEmitter(RNSerialPort);
// USB device attached
const attachListener = eventEmitter.addListener('onUsbAttached', () => {
console.log('USB device attached');
});
// USB device detached
const detachListener = eventEmitter.addListener('onUsbDetached', () => {
console.log('USB device detached');
});
// Data received (if using streaming mode)
const dataListener = eventEmitter.addListener('onDataReceived', (event) => {
console.log('Data received:', event.data);
});
// Cleanup
attachListener.remove();
detachListener.remove();
dataListener.remove();
listDevices(): Promise<USBDevice[]>Returns a list of connected USB serial devices.
const devices = await transport.listDevices();
connect(deviceName?: string, baudRate?: number): Promise<string>Connects to a USB serial device.
deviceName: Optional device path. If omitted, auto-selects ESP device.baudRate: Baud rate (default: 115200)await transport.connect(undefined, 115200);
write(data: Uint8Array): Promise<number>Writes data to the serial port. Returns the number of bytes written.
const data = new Uint8Array([0x01, 0x02, 0x03]);
const bytesWritten = await transport.write(data);
console.log(`Wrote ${bytesWritten} bytes`);
read(timeout: number): AsyncGenerator<Uint8Array>Reads data from the serial port (generator function).
for await (const data of transport.read(3000)) {
console.log('Received:', data);
}
rawRead(timeout: number): Promise<Uint8Array>Reads data from the serial port (promise-based).
const data = await transport.rawRead(1000);
setRTS(state: boolean): Promise<void>Sets the RTS (Request To Send) control line.
await transport.setRTS(true);
setDTR(state: boolean): Promise<void>Sets the DTR (Data Terminal Ready) control line.
await transport.setDTR(false);
setBaudRate(baudRate: number): Promise<boolean>Changes the baud rate of an open connection.
await transport.setBaudRate(921600);
disconnect(): Promise<boolean>Closes the serial port connection. Returns true if successful.
await transport.disconnect();
For advanced use cases, you can use the native module directly:
import NativeSerialPort from 'react-native-serial-transport';
// List devices
const devices = await NativeSerialPort.listDevices();
// Connect
await NativeSerialPort.connect('/dev/bus/usb/001/002', 115200);
// Write (accepts number array)
await NativeSerialPort.write([0x01, 0x02, 0x03]);
// Read (returns number array)
const data: number[] = await NativeSerialPort.read(1000);
// Control lines
await NativeSerialPort.setRTS(true);
await NativeSerialPort.setDTR(false);
// Disconnect
await NativeSerialPort.disconnect();
device_filter.xmlThe app will automatically request USB permissions when connecting. If you see permission errors:
android.permission.USB_PERMISSION is in your AndroidManifest.xmladb shell ls /dev/bus/usb/If your ESP device isn't auto-detected, you can specify it manually:
// List all devices first
const devices = await transport.listDevices();
console.log(devices);
// Connect to specific device
await transport.connect(devices[0].deviceName, 115200);
For React Native < 0.60, you need to manually link:
react-native link react-native-serial-transport
Then follow the manual setup steps in Option 2.
Clean build:
cd android && ./gradlew clean
cd .. && npx react-native run-android
Clear Metro cache:
npx react-native start --reset-cache
Reinstall dependencies:
rm -rf node_modules
yarn install
cd android && ./gradlew clean
cd .. && npx react-native run-android
| Chip Family | Vendor ID | Common On | Notes |
|---|---|---|---|
| CP210x | 0x10C4 (4292) | ESP32, ESP8266, NodeMCU | Silicon Labs |
| CH340/CH341 | 0x1A86 (6790) | Many ESP boards, Arduino clones | QinHeng Electronics |
| FTDI | 0x0403 (1027) | Arduino, various dev boards | Future Technology Devices |
| PL2303 | 0x067B (1659) | Older USB-serial adapters | Prolific |
⚠️ iOS does not support USB serial communication through standard APIs. For iOS:
Consider using react-native-ble-plx for cross-platform wireless communication.
Contributions are welcome! Please open an issue or submit a pull request.
MIT
Made with ❤️ for the React Native and ESP32 communities
FAQs
USB Serial Port support for React Native for Android
The npm package react-native-serial-transport receives a total of 10 weekly downloads. As such, react-native-serial-transport popularity was classified as not popular.
We found that react-native-serial-transport demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.