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

Unity C#安卓应用OTG连接Arduino串口通信权限问题求助

问题

Unity开发的Arduino串口通信游戏在Windows、Linux平台可正常运行,但在Android上报错:

Error Unity IOException: Permission denied
Error Unity Rethrow as UnauthorizedAccessException: Access to the path '/dev' is denied.

已尝试添加自定义AndroidManifest.xml并添加权限,但未解决问题:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools">
    
    <!--ADDED THESE PERMISSIONS: START-->
    <uses-permission android:name="android.permission.MANAGE_USB" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-feature android:name="android.hardware.usb.host" android:required="true" />
    <!--ADDED THESE PERMISSIONS: END-->

    <application>
        <activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="@style/UnityThemeSelector"> 
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
</manifest>

现希望无需开发Java/Kotlin插件,找到最简的权限获取及串口通信解决方案。

# 最简解决方案
- **补充权限并动态申请**
  Android 6.0及以上版本需要动态申请危险权限,除Manifest中已添加的权限,需额外添加存储权限(部分设备访问/dev下串口依赖此权限):
  ```xml
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

同时在C#脚本中动态申请权限,并触发USB设备授权弹窗:

using UnityEngine;
using UnityEngine.Android;

public class USBPermissionHandler : MonoBehaviour
{
    void Start()
    {
        // 申请存储权限
        if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead))
            Permission.RequestUserPermission(Permission.ExternalStorageRead);
        if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
            Permission.RequestUserPermission(Permission.ExternalStorageWrite);
        
        // 请求USB设备权限
        RequestArduinoUSBPermission();
    }

    void RequestArduinoUSBPermission()
    {
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject usbManager = currentActivity.Call<AndroidJavaObject>("getSystemService", "usb");
        
        // 获取已连接的USB设备列表,筛选Arduino设备(需替换为对应VID/PID)
        AndroidJavaObject deviceList = usbManager.Call<AndroidJavaObject>("getDeviceList");
        AndroidJavaObject iterator = deviceList.Call<AndroidJavaObject>("entrySet").Call<AndroidJavaObject>("iterator");
        
        while (iterator.Call<bool>("hasNext"))
        {
            AndroidJavaObject entry = iterator.Call<AndroidJavaObject>("next");
            AndroidJavaObject device = entry.Call<AndroidJavaObject>("getValue");
            int vid = device.Call<int>("getVendorId");
            int pid = device.Call<int>("getProductId");
            
            // 匹配Arduino Uno的VID/PID,其他型号需修改对应值
            if (vid == 0x2341 && pid == 0x0043)
            {
                AndroidJavaClass usbManagerClass = new AndroidJavaClass("android.hardware.usb.UsbManager");
                string permissionIntentAction = usbManagerClass.GetStatic<string>("ACTION_USB_DEVICE_ATTACHED");
                AndroidJavaObject permissionIntent = new AndroidJavaObject("android.content.Intent", permissionIntentAction);
                permissionIntent.Call<AndroidJavaObject>("putExtra", usbManagerClass.GetStatic<string>("EXTRA_DEVICE"), device);
                currentActivity.Call("startActivityForResult", permissionIntent, 1);
                break;
            }
        }
    }
}
  • 跳过/dev遍历,直接指定常见Arduino串口路径
    Android下Arduino串口通常为/dev/ttyUSB0或/dev/ttyACM0,直接尝试连接这两个路径,避免因遍历/dev目录触发权限拒绝:

    using System.IO.Ports;
    
    public class ArduinoSerial : MonoBehaviour
    {
        void ConnectToArduino()
        {
            string[] targetPorts = { "/dev/ttyUSB0", "/dev/ttyACM0" };
            SerialPort activePort = null;
    
            foreach (string port in targetPorts)
            {
                try
                {
                    activePort = new SerialPort(port, 9600);
                    activePort.Open();
                    Debug.Log($"Successfully connected to {port}");
                    break;
                }
                catch (System.Exception e)
                {
                    Debug.Log($"Failed to open {port}: {e.Message}");
                    activePort = null;
                }
            }
    
            // 使用activePort进行后续通信
        }
    }
    
  • 使用现成Unity串口插件
    直接导入Unity Asset Store中的成熟串口插件(如Serial Port Utility for Android),这类插件已封装好权限申请、设备检测和通信逻辑,无需编写Java/Kotlin代码,调用插件API即可快速实现功能。

内容的提问来源于stack exchange,提问作者Aarat Satsangi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:02:11