.NET Maui Android平台USB串口读写权限及代码崩溃问题求助
.NET Maui USB串口设备权限修复与读取方案
一、解决PendingIntent崩溃问题
你的代码崩溃核心原因是Android 12+(API 31及以上)要求创建PendingIntent必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,旧版的0值flag已被废弃。修改PendingIntent创建代码:
string ACTION_USB_PERMISSION = "com.MauiAndroidSerialPort.USB_PERMISSION"; PendingIntent mPermissionIntent; if (Build.VERSION.SdkInt >= BuildVersionCodes.S) { mPermissionIntent = PendingIntent.GetBroadcast(Platform.CurrentActivity, 0, new Intent(ACTION_USB_PERMISSION), PendingIntentFlags.Immutable); } else { mPermissionIntent = PendingIntent.GetBroadcast(Platform.CurrentActivity, 0, new Intent(ACTION_USB_PERMISSION), 0); }
二、正确的USB权限处理流程
权限请求是异步操作,不能直接在请求后立即调用OpenDevice,必须通过广播接收器接收权限结果:
- 定义全局变量
private BroadcastReceiver _usbPermissionReceiver; private UsbManager _usbManager; private UsbDevice _targetDevice; private UsbInterface _serialInterface; private UsbEndpoint _readEndpoint; private UsbDeviceConnection _deviceConnection;
- 页面初始化时注册广播接收器
_usbManager = (UsbManager)Platform.CurrentActivity.GetSystemService(Context.UsbService); string ACTION_USB_PERMISSION = "com.MauiAndroidSerialPort.USB_PERMISSION"; _usbPermissionReceiver = new BroadcastReceiver() { OnReceive = (context, intent) => { if (ACTION_USB_PERMISSION.Equals(intent.Action)) { lock (this) { UsbDevice device = (UsbDevice)intent.GetParcelableExtra(UsbManager.ExtraDevice); if (intent.GetBooleanExtra(UsbManager.ExtraPermissionGranted, false)) { device?.InitializeSerialConnection(); } else { Console.WriteLine("USB权限被拒绝"); } } } } }; // 注册广播过滤器 IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); Platform.CurrentActivity.RegisterReceiver(_usbPermissionReceiver, filter);
- 发起权限请求
// 假设已找到目标设备_targetDevice if (!_usbManager.HasPermission(_targetDevice)) { PendingIntent permissionIntent; if (Build.VERSION.SdkInt >= BuildVersionCodes.S) { permissionIntent = PendingIntent.GetBroadcast(Platform.CurrentActivity, 0, new Intent(ACTION_USB_PERMISSION), PendingIntentFlags.Immutable); } else { permissionIntent = PendingIntent.GetBroadcast(Platform.CurrentActivity, 0, new Intent(ACTION_USB_PERMISSION), 0); } _usbManager.RequestPermission(_targetDevice, permissionIntent); } else { _targetDevice.InitializeSerialConnection(); }
三、正确识别串口接口与端点
不要硬编码GetInterface(1),遍历设备接口找到符合串口特征的接口(通常是CDC数据类接口,端点为BULK类型):
private void InitializeSerialConnection(UsbDevice device) { // 遍历设备接口,找到串口接口 for (int i = 0; i < device.InterfaceCount; i++) { UsbInterface usbInterface = device.GetInterface(i); // 筛选CDC数据类接口(可根据设备实际类型调整) if (usbInterface.InterfaceClass == (int)UsbClass.CdcData) { _serialInterface = usbInterface; // 遍历端点,找到读取端点(IN方向) for (int j = 0; j < usbInterface.EndpointCount; j++) { UsbEndpoint endpoint = usbInterface.GetEndpoint(j); if (endpoint.Type == UsbAddressing.Bulk && endpoint.Direction == UsbDirection.In) { _readEndpoint = endpoint; break; } } break; } } if (_serialInterface == null || _readEndpoint == null) { Console.WriteLine("未找到有效的串口接口或读取端点"); return; } // 打开设备连接并声明接口 _deviceConnection = _usbManager.OpenDevice(device); if (_deviceConnection != null) { bool claimed = _deviceConnection.ClaimInterface(_serialInterface, true); if (claimed) { Console.WriteLine("接口声明成功,开始读取数据"); // 启动读取线程 Task.Run(ReadSerialData); } else { Console.WriteLine("接口声明失败"); _deviceConnection.Close(); } } else { Console.WriteLine("无法打开设备连接"); } }
四、串口数据读取实现
通过后台线程循环读取数据,避免阻塞UI线程:
private void ReadSerialData() { byte[] buffer = new byte[1024]; // 根据设备调整缓冲区大小 while (_deviceConnection != null && _serialInterface != null) { int bytesRead = _deviceConnection.BulkTransfer(_readEndpoint, buffer, buffer.Length, 5000); if (bytesRead > 0) { // 转换为字符串(根据设备编码调整,通常为UTF-8或ASCII) string data = Encoding.UTF8.GetString(buffer, 0, bytesRead).Trim(); Console.WriteLine($"读取到数据:{data}"); // 回到UI线程更新界面 MainThread.BeginInvokeOnMainThread(() => { // 在这里更新UI,例如绑定到Label控件 // BarcodeLabel.Text = data; }); } else if (bytesRead < 0) { Console.WriteLine("读取出错,断开连接"); break; } } // 清理资源 if (_deviceConnection != null) { _deviceConnection.ReleaseInterface(_serialInterface); _deviceConnection.Close(); _deviceConnection = null; } }
五、页面销毁时清理资源
在页面的OnDisappearing方法中注销广播接收器并释放资源:
protected override void OnDisappearing() { base.OnDisappearing(); if (_usbPermissionReceiver != null) { Platform.CurrentActivity.UnregisterReceiver(_usbPermissionReceiver); _usbPermissionReceiver = null; } if (_deviceConnection != null) { _deviceConnection.ReleaseInterface(_serialInterface); _deviceConnection.Close(); _deviceConnection = null; } }
内容的提问来源于stack exchange,提问作者PeNo
相关产品推荐
相关产品推荐

