USB Detection in a React Native App

In this article, we will explore how to detect USB devices in a React Native app using a custom native module written in Kotlin. This guide will walk you through the process step by step, explaining how the code works.
Introduction
React Native does not provide built-in support for USB detection, but we can achieve this functionality by integrating native Android code. By using UsbManager
and BroadcastReceiver
, we can listen for USB device connections and disconnections.
Step 1: Creating the USB Detection Module
We will create a custom native module in Kotlin to handle USB device detection.
UsbDetectionModule.kt
package com.youappimport android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModuleclass UsbDetectionModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) { init {
registerUsbReceiver()
} override fun getName(): String {
return "UsbDetection"
} @ReactMethod
fun getConnectedUsbDevices(promise: Promise) {
try {
val usbManager = reactApplicationContext.getSystemService(Context.USB_SERVICE) as UsbManager
val devices: HashMap<String, UsbDevice> = usbManager.deviceList as HashMap<String, UsbDevice> val deviceNames: WritableArray = Arguments.createArray()
for ((_, device) in devices) {
deviceNames.pushString(device.deviceName)
} promise.resolve(deviceNames)
} catch (e: SecurityException) {
promise.reject("USB_PERMISSION_ERROR", "USB permission is missing: ${e.message}")
} catch (e: Exception) {
promise.reject("USB_ERROR", "Failed to get USB devices: ${e.message}")
}
} private fun registerUsbReceiver() {
val filter = IntentFilter().apply {
addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
}
reactApplicationContext.registerReceiver(usbReceiver, filter)
} private val usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action ?: return
reactApplicationContext.getSystemService(Context.USB_SERVICE) as UsbManager
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) when (action) {
UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
if (device != null) {
sendEvent("USB_ATTACHED", device.deviceName)
}
}
UsbManager.ACTION_USB_DEVICE_DETACHED -> {
if (device != null) {
sendEvent("USB_DETACHED", device.deviceName)
}
}
}
}
} private fun sendEvent(eventName: String, deviceName: String) {
reactApplicationContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
?.emit(eventName, deviceName)
}
}
Step 2: Creating the USB Detection Package
We need to package the module so it can be accessed from React Native.
UsbDetectionPackage.kt
package com.youappimport com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManagerclass UsbDetectionPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(UsbDetectionModule(reactContext))
} override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
Step 3: Registering the Package in the Main Application
We need to register our new package in MainApplication.kt
.
MainApplication.kt
package com.youappimport android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoaderclass MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(UsbDetectionPackage()) // Register here
} override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
} override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost) override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
load()
}
}
}
Step 4: Using the USB Detection Module in React Native
We will use the module in our React Native app.
App.tsx
import { NativeEventEmitter, NativeModules } from 'react-native';const UsbDetection = NativeModules.UsbDetection;
const usbEmitter = new NativeEventEmitter(UsbDetection);useEffect(() => {
usbEmitter.addListener('USB_ATTACHED', deviceName => {
console.log('USB Connected:', deviceName);
}); usbEmitter.addListener('USB_DETACHED', deviceName => {
console.log('USB Disconnected:', deviceName);
}); return () => {
usbEmitter.removeAllListeners('USB_ATTACHED');
usbEmitter.removeAllListeners('USB_DETACHED');
};
}, []);
Conclusion
By following these steps, you can successfully detect USB devices in your React Native application. This approach helps in real-time monitoring of USB device connections and disconnections using Kotlin and React Native.