C# SerialPort连接Android UsbAccessory问题:accessories始终为空
需求与现状
- 开发Windows应用(C#)作为USB主机,与作为USB配件的Android手机建立连接
- 实现设备间的数据收发
- C#端已识别到Android设备的COM5端口,可通过串口代码成功连接:
serialPort1.PortName = this.devicesList.Text; // COM5 serialPort1.Open(); addToList("SerialPort is opened", Color.Green);
Android端问题
调用以下代码获取USB配件列表时,accessories始终返回null:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbAccessory[] accessories = manager.getAccessoryList();
补充代码与配置
Android Studio代码(Java)
package com.example.camerausb; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.widget.Toast; import androidx.annotation.Nullable; import java.io.FileInputStream; import java.io.FileOutputStream; public class UsbConnector extends Activity { private static final String ACTION_USB_PERMISSION = "com.example.camerausb.UsbConnector.USB_PERMISSION"; public UsbManager usbManager; public UsbAccessory usbAccessory; public PendingIntent mPermissionIntent; public Context global_context; private IntentFilter filter; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { Toast.makeText(global_context, "Allow Usb Permission", Toast.LENGTH_LONG).show(); // TODO:: open Accessory method } else { Toast.makeText(global_context, "Deny Usb Permission", Toast.LENGTH_LONG).show(); } } } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { Toast.makeText(global_context, "Usb detached", Toast.LENGTH_LONG).show(); } else { Toast.makeText(global_context, "something else", Toast.LENGTH_LONG).show(); } } }; public UsbConnector(Context context) { super(); global_context = context; Toast.makeText(global_context, "started", Toast.LENGTH_LONG).show(); usbManager = (UsbManager) global_context.getSystemService(Context.USB_SERVICE); mPermissionIntent = PendingIntent.getBroadcast(global_context, 0, new Intent(ACTION_USB_PERMISSION), 0); filter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); usbManager.requestPermission(usbAccessory, mPermissionIntent); global_context.registerReceiver(mUsbReceiver, filter); } public BroadcastReceiver getReceiver() { return this.mUsbReceiver; } public IntentFilter getFilter() { return this.filter; } public void resumeAccessory(Intent intent) { // Intent intent = getIntent(); String action = intent.getAction(); Toast.makeText(global_context, "resume: " + action, Toast.LENGTH_LONG).show(); UsbAccessory[] accessories = usbManager.getAccessoryList(); if (accessories != null) { Toast.makeText(global_context, "Accessory not NULL", Toast.LENGTH_LONG).show(); } else { Toast.makeText(global_context, "Accessory is NULL", Toast.LENGTH_LONG).show(); } } }
Manifest配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.camerausb"> <uses-sdk android:minSdkVersion="12" /> <uses-feature android:name="android.hardware.usb.accessory" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.CameraUsb"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest>
xml/accessory_filter配置
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0" /> </resources>
问题排查与解决建议
核心问题分析
- USB模式不匹配:Windows端用串口(COM5)连接,说明Android当前处于MTP/ADB等串口类模式,而非USB配件模式。USB配件模式要求Windows端实现Android Accessory协议,而非简单的串口通信。
- 配件标识不匹配:
accessory_filter.xml配置的厂商、型号是Google DemoKit,但Windows端未模拟对应标识的配件,导致Android无法识别。 - 代码逻辑错误:
UsbConnector构造函数中,请求权限时usbAccessory为null,且重复添加了同一广播Action到过滤器;resumeAccessory方法未正确触发,且触发时USB模式也不符合要求。
修复步骤
1. 调整Windows端实现Android Accessory协议
Windows端不能直接用串口连接,需实现Android USB Accessory协议:
- 参考Google官方ADK开发包实现主机端逻辑,模拟符合
accessory_filter.xml标识的配件设备 - 或使用第三方适配库完成主机端协议对接
2. 修正Android代码逻辑
- 修复构造函数权限请求逻辑:
public UsbConnector(Context context) { super(); global_context = context; Toast.makeText(global_context, "started", Toast.LENGTH_LONG).show(); usbManager = (UsbManager) global_context.getSystemService(Context.USB_SERVICE); mPermissionIntent = PendingIntent.getBroadcast(global_context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); filter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); // 先获取配件列表再处理权限 UsbAccessory[] accessories = usbManager.getAccessoryList(); if (accessories != null && accessories.length > 0) { usbAccessory = accessories[0]; if (!usbManager.hasPermission(usbAccessory)) { usbManager.requestPermission(usbAccessory, mPermissionIntent); } } global_context.registerReceiver(mUsbReceiver, filter); }
- 在
MainActivity的onResume中触发配件检测:
@Override protected void onResume() { super.onResume(); UsbConnector connector = new UsbConnector(this); connector.resumeAccessory(getIntent()); }
3. 同步配件标识配置
修改xml/accessory_filter.xml,使其与Windows端模拟的配件标识完全一致:
<resources> <usb-accessory model="WindowsHost" manufacturer="YourCompany" version="1.0" /> </resources>
4. 切换Android到USB配件模式
连接USB线后,在Android通知栏的「USB连接方式」中选择「USB配件模式」。
内容的提问来源于stack exchange,提问作者obeid salem
相关产品推荐
相关产品推荐

