我有一个 React Native 应用程序,在连接外部 USB 设备时需要找到某个根目录。 DataXYZ.txt 文件并能够共享它,因为据我所知 React Native 不提供这样的功能,我决定用 java 编写一个模块,但我无法弄清楚,请帮忙
这是一个检查设备是否已连接的模块,您需要扩展它
package com.awesomeproject.usb;
import 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 androidx.annotation.NonNull;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.util.HashMap;
public class UsbDeviceListenerModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
private final ReactApplicationContext reactContext;
private final BroadcastReceiver usbReceiver;
private boolean isInitialized = false;
public UsbDeviceListenerModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
// Регистрация слушателя жизненного цикла
reactContext.addLifecycleEventListener(this);
usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
sendDeviceConnectedEvent(device);
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
sendDeviceDisconnectedEvent(device);
}
}
}
};
// Регистрация ресивера для прослушивания подключений и отключений
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
reactContext.registerReceiver(usbReceiver, filter);
}
@NonNull
@Override
public String getName() {
return "UsbDeviceListener";
}
@Override
public void invalidate() {
super.invalidate();
// Отмена регистрации ресивера при уничтожении модуля
reactContext.unregisterReceiver(usbReceiver);
reactContext.removeLifecycleEventListener(this);
}
@Override
public void onHostResume() {
if (!isInitialized) {
checkForConnectedUsbDevices();
isInitialized = true;
}
}
@Override
public void onHostPause() {
// Не требуется действия при паузе
}
@Override
public void onHostDestroy() {
// Не требуется действия при уничтожении
}
private void checkForConnectedUsbDevices() {
UsbManager usbManager = (UsbManager) reactContext.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
if (!deviceList.isEmpty()) {
for (UsbDevice device : deviceList.values()) {
sendDeviceConnectedEvent(device);
}
}
}
private void sendDeviceConnectedEvent(UsbDevice device) {
WritableMap deviceData = Arguments.createMap();
deviceData.putString("deviceName", device.getDeviceName());
deviceData.putInt("vendorId", device.getVendorId());
deviceData.putInt("productId", device.getProductId());
deviceData.putInt("deviceClass", device.getDeviceClass());
deviceData.putInt("deviceSubclass", device.getDeviceSubclass());
deviceData.putInt("deviceProtocol", device.getDeviceProtocol());
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("UsbDeviceConnected", deviceData);
}
}
private void sendDeviceDisconnectedEvent(UsbDevice device) {
WritableMap deviceData = Arguments.createMap();
deviceData.putString("deviceName", device.getDeviceName());
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("UsbDeviceDisconnected", deviceData);
}
}
}
您共享的模块使用“BroadcastReceiver”检测USB设备何时连接或断开。下一步是查看 USB 设备的存储以查找名为 DataXYZ.txt 的文件。如果我们找到它,我们可以创建一个意图,告诉 android 我们想要共享这个文件。我们可以显示可以处理该文件的应用程序列表,用户可以选择一个来共享该文件。这是扩展代码:
package com.awesomeproject.usb;
import 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 android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.documentfile.provider.DocumentFile;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
public class UsbDeviceListenerModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
private static final String TAG = "UsbDeviceListener";
private final ReactApplicationContext reactContext;
private final BroadcastReceiver usbReceiver;
private boolean isInitialized = false;
public UsbDeviceListenerModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
// Регистрация слушателя жизненного цикла
reactContext.addLifecycleEventListener(this);
usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
sendDeviceConnectedEvent(device);
findAndShareFile(device);
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
sendDeviceDisconnectedEvent(device);
}
}
}
};
// Регистрация ресивера для прослушивания подключений и отключений
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
reactContext.registerReceiver(usbReceiver, filter);
}
@NonNull
@Override
public String getName() {
return "UsbDeviceListener";
}
@Override
public void invalidate() {
super.invalidate();
// Отмена регистрации ресивера при уничтожении модуля
reactContext.unregisterReceiver(usbReceiver);
reactContext.removeLifecycleEventListener(this);
}
@Override
public void onHostResume() {
if (!isInitialized) {
checkForConnectedUsbDevices();
isInitialized = true;
}
}
@Override
public void onHostPause() {
// Не требуется действия при паузе
}
@Override
public void onHostDestroy() {
// Не требуется действия при уничтожении
}
private void checkForConnectedUsbDevices() {
UsbManager usbManager = (UsbManager) reactContext.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
if (!deviceList.isEmpty()) {
for (UsbDevice device : deviceList.values()) {
sendDeviceConnectedEvent(device);
findAndShareFile(device);
}
}
}
private void findAndShareFile(UsbDevice device) {
File usbDirectory = new File("/storage");
if (usbDirectory.exists() && usbDirectory.isDirectory()) {
File file = searchFileInDirectory(usbDirectory, "DataXYZ.txt");
if (file != null && file.exists()) {
shareFile(file);
} else {
Log.e(TAG, "DataXYZ.txt not found on USB device: " + device.getDeviceName());
}
} else {
Log.e(TAG, "USB directory not found or is not a directory");
}
}
private File searchFileInDirectory(File directory, String fileName) {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
File foundFile = searchFileInDirectory(file, fileName);
if (foundFile != null) {
return foundFile;
}
} else if (fileName.equalsIgnoreCase(file.getName())) {
return file;
}
}
}
return null;
}
private void shareFile(File file) {
Uri fileUri = Uri.fromFile(file);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent chooserIntent = Intent.createChooser(shareIntent, "Share file via");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
reactContext.startActivity(chooserIntent);
}
private void sendDeviceConnectedEvent(UsbDevice device) {
WritableMap deviceData = Arguments.createMap();
deviceData.putString("deviceName", device.getDeviceName());
deviceData.putInt("vendorId", device.getVendorId());
deviceData.putInt("productId", device.getProductId());
deviceData.putInt("deviceClass", device.getDeviceClass());
deviceData.putInt("deviceSubclass", device.getDeviceSubclass());
deviceData.putInt("deviceProtocol", device.getDeviceProtocol());
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("UsbDeviceConnected", deviceData);
}
}
private void sendDeviceDisconnectedEvent(UsbDevice device) {
WritableMap deviceData = Arguments.createMap();
deviceData.putString("deviceName", device.getDeviceName());
if (reactContext.hasActiveCatalystInstance()) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("UsbDeviceDisconnected", deviceData);
}
}
}
确保添加:“READ_EXTERNAL_STORAGE”权限和任何其他必要的权限。此外,您需要更新文件位置。