You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

问题排查与解决建议

核心问题分析

  1. USB模式不匹配:Windows端用串口(COM5)连接,说明Android当前处于MTP/ADB等串口类模式,而非USB配件模式。USB配件模式要求Windows端实现Android Accessory协议,而非简单的串口通信。
  2. 配件标识不匹配:accessory_filter.xml配置的厂商、型号是Google DemoKit,但Windows端未模拟对应标识的配件,导致Android无法识别。
  3. 代码逻辑错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 08:45:46