.NET MAUI跨平台串口通讯方案

文章目录

      • MAUI项目架构设计
      • 平台特定实现
        • 接口定义
        • Windows平台实现
        • Android平台实现
      • MAUI主界面实现
      • 依赖注入配置
      • 相关学习资源
        • .NET MAUI开发
        • 移动端开发
        • 平台特定实现
        • 依赖注入与架构
        • 移动应用发布
        • 跨平台开发最佳实践
        • 性能优化
        • 测试与调试
        • 开源项目参考

MAUI项目架构设计

MAUI App
共享业务逻辑
串口服务接口
Windows实现
Android实现
iOS实现
macOS实现
System.IO.Ports
Android USB/Serial
External Accessory
IOKit Framework

平台特定实现

接口定义
/// 
/// 跨平台串口服务接口
/// 
public interface ISerialPortService
{
    /// 
    /// 获取可用串口列表
    /// 
    Task<string[]> GetAvailablePortsAsync();
    
    /// 
    /// 连接到指定串口
    /// 
    Task<bool> ConnectAsync(string portName, int baudRate);
    
    /// 
    /// 断开串口连接
    /// 
    Task DisconnectAsync();
    
    /// 
    /// 发送数据
    /// 
    Task SendDataAsync(byte[] data);
    
    /// 
    /// 发送文本数据
    /// 
    Task SendTextAsync(string text);
    
    /// 
    /// 数据接收事件
    /// 
    event EventHandler<SerialDataEventArgs> DataReceived;
    
    /// 
    /// 连接状态变化事件
    /// 
    event EventHandler<bool> ConnectionChanged;
    
    /// 
    /// 是否已连接
    /// 
    bool IsConnected { get; }
}

/// 
/// 串口数据事件参数
/// 
public class SerialDataEventArgs : EventArgs
{
    public byte[] Data { get; set; }
    public string Text { get; set; }
    public DateTime Timestamp { get; set; }
}
Windows平台实现
#if WINDOWS
using System.IO.Ports;

/// 
/// Windows平台串口服务实现
/// 
public class WindowsSerialPortService : ISerialPortService
{
    private SerialPort _serialPort;
    private bool _isConnected;

    public bool IsConnected => _isConnected;
    
    public event EventHandler<SerialDataEventArgs> DataReceived;
    public event EventHandler<bool> ConnectionChanged;

    public WindowsSerialPortService()
    {
        _serialPort = new SerialPort();
        _serialPort.DataReceived += OnDataReceived;
    }

    public async Task<string[]> GetAvailablePortsAsync()
    {
        return await Task.FromResult(SerialPort.GetPortNames());
    }

    public async Task<bool> ConnectAsync(string portName, int baudRate)
    {
        try
        {
            if (_isConnected)
                await DisconnectAsync();

            _serialPort.PortName = portName;
            _serialPort.BaudRate = baudRate;
            _serialPort.DataBits = 8;
            _serialPort.Parity = Parity.None;
            _serialPort.StopBits = StopBits.One;

            _serialPort.Open();
            _isConnected = true;
            
            ConnectionChanged?.Invoke(this, true);
            return true;
        }
        catch (Exception ex)
        {
            _isConnected = false;
            ConnectionChanged?.Invoke(this, false);
            return false;
        }
    }

    public async Task DisconnectAsync()
    {
        try
        {
            if (_serialPort?.IsOpen == true)
            {
                _serialPort.Close();
            }
            _isConnected = false;
            ConnectionChanged?.Invoke(this, false);
        }
        catch (Exception)
        {
            // 忽略关闭时的异常
        }
    }

    public async Task SendDataAsync(byte[] data)
    {
        if (!_isConnected || !_serialPort.IsOpen)
            throw new InvalidOperationException("串口未连接");

        await Task.Run(() => _serialPort.Write(data, 0, data.Length));
    }

    public async Task SendTextAsync(string text)
    {
        var data = System.Text.Encoding.UTF8.GetBytes(text);
        await SendDataAsync(data);
    }

    private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        try
        {
            var buffer = new byte[_serialPort.BytesToRead];
            var bytesRead = _serialPort.Read(buffer, 0, buffer.Length);
            
            var eventArgs = new SerialDataEventArgs
            {
                Data = buffer.Take(bytesRead).ToArray(),
                Text = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead),
                Timestamp = DateTime.Now
            };
            
            DataReceived?.Invoke(this, eventArgs);
        }
        catch (Exception)
        {
            // 处理读取异常
        }
    }
}
#endif
Android平台实现
#if ANDROID
using Android.Hardware.Usb;
using AndroidX.Core.Content;

/// 
/// Android平台串口服务实现
/// 基于USB Host模式
/// 
public class AndroidSerialPortService : ISerialPortService
{
    private UsbManager _usbManager;
    private UsbDevice _usbDevice;
    private UsbDeviceConnection _connection;
    private UsbInterface _interface;
    private UsbEndpoint _endpointIn;
    private UsbEndpoint _endpointOut;
    private bool _isConnected;
    private CancellationTokenSource _readCancellation;

    public bool IsConnected => _isConnected;
    
    public event EventHandler<SerialDataEventArgs> DataReceived;
    public event EventHandler<bool> ConnectionChanged;

    public AndroidSerialPortService()
    {
        var context = Platform.CurrentActivity ?? Android.App.Application.Context;
        _usbManager = (UsbManager)context.GetSystemService(Android.Content.Context.UsbService);
    }

    public async Task<string[]> GetAvailablePortsAsync()
    {
        var deviceList = _usbManager.DeviceList;
        var portNames = new List<string>();

        foreach (var device in deviceList.Values)
        {
            // 检查是否为串口设备(根据VID/PID或设备类型判断)
            if (IsSerialDevice(device))
            {
                portNames.Add($"USB-{device.DeviceName}");
            }
        }

        return portNames.ToArray();
    }

    public async Task<bool> ConnectAsync(string portName, int baudRate)
    {
        try
        {
            // Android USB串口连接实现
            // 这里需要根据具体的USB转串口芯片实现
            var deviceList = _usbManager.DeviceList;
            
            foreach (var device in deviceList.Values)
            {
                if ($"USB-{device.DeviceName}" == portName)
                {
                    _usbDevice = device;
                    break;
                }
            }

            if (_usbDevice == null)
                return false;

            // 请求USB权限
            if (!_usbManager.HasPermission(_usbDevice))
            {
                // 需要请求权限
                return false;
            }

            _connection = _usbManager.OpenDevice(_usbDevice);
            if (_connection == null)
                return false;

            // 配置USB设备
            _interface = _usbDevice.GetInterface(0);
            _connection.ClaimInterface(_interface, true);

            // 找到输入输出端点
            for (int i = 0; i < _interface.EndpointCount; i++)
            {
                var endpoint = _interface.GetEndpoint(i);
                if (endpoint.Direction == UsbAddressing.In)
                    _endpointIn = endpoint;
                else if (endpoint.Direction == UsbAddressing.Out)
                    _endpointOut = endpoint;
            }

            _isConnected = true;
            ConnectionChanged?.Invoke(this, true);

            // 启动数据读取
            StartDataReading();

            return true;
        }
        catch (Exception)
        {
            _isConnected = false;
            ConnectionChanged?.Invoke(this, false);
            return false;
        }
    }

    public async Task DisconnectAsync()
    {
        _isConnected = false;
        _readCancellation?.Cancel();
        
        _connection?.ReleaseInterface(_interface);
        _connection?.Close();
        
        ConnectionChanged?.Invoke(this, false);
    }

    public async Task SendDataAsync(byte[] data)
    {
        if (!_isConnected || _connection == null || _endpointOut == null)
            throw new InvalidOperationException("设备未连接");

        await Task.Run(() =>
        {
            _connection.BulkTransfer(_endpointOut, data, data.Length, 1000);
        });
    }

    public async Task SendTextAsync(string text)
    {
        var data = System.Text.Encoding.UTF8.GetBytes(text);
        await SendDataAsync(data);
    }

    private void StartDataReading()
    {
        _readCancellation = new CancellationTokenSource();
        
        Task.Run(async () =>
        {
            var buffer = new byte[1024];
            
            while (!_readCancellation.Token.IsCancellationRequested && _isConnected)
            {
                try
                {
                    var bytesRead = _connection.BulkTransfer(_endpointIn, buffer, buffer.Length, 100);
                    
                    if (bytesRead > 0)
                    {
                        var eventArgs = new SerialDataEventArgs
                        {
                            Data = buffer.Take(bytesRead).ToArray(),
                            Text = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead),
                            Timestamp = DateTime.Now
                        };
                        
                        DataReceived?.Invoke(this, eventArgs);
                    }
                    
                    await Task.Delay(10);
                }
                catch (Exception)
                {
                    // 处理读取异常
                }
            }
        });
    }

    private bool IsSerialDevice(UsbDevice device)
    {
        // 根据VID/PID或设备类型判断是否为串口设备
        // 这里可以添加常见USB转串口芯片的识别逻辑
        return device.DeviceClass == UsbClass.CdcData || 
               device.DeviceClass == UsbClass.Comm;
    }
}
#endif

MAUI主界面实现

/// 
/// MAUI主页面
/// 
public partial class MainPage : ContentPage
{
    private readonly ISerialPortService _serialService;
    private readonly ObservableCollection<string> _receivedMessages;

    public MainPage(ISerialPortService serialService)
    {
        InitializeComponent();
        _serialService = serialService;
        _receivedMessages = new ObservableCollection<string>();
        
        MessagesCollectionView.ItemsSource = _receivedMessages;
        
        // 绑定事件
        _serialService.DataReceived += OnDataReceived;
        _serialService.ConnectionChanged += OnConnectionChanged;
        
        // 加载可用串口
        LoadAvailablePorts();
    }

    private async void LoadAvailablePorts()
    {
        try
        {
            var ports = await _serialService.GetAvailablePortsAsync();
            PortPicker.ItemsSource = ports;
            
            if (ports.Length > 0)
                PortPicker.SelectedIndex = 0;
        }
        catch (Exception ex)
        {
            await DisplayAlert("错误", $"加载串口列表失败: {ex.Message}", "确定");
        }
    }

    private async void OnConnectClicked(object sender, EventArgs e)
    {
        try
        {
            if (_serialService.IsConnected)
            {
                await _serialService.DisconnectAsync();
            }
            else
            {
                if (PortPicker.SelectedItem == null)
                {
                    await DisplayAlert("提示", "请选择串口", "确定");
                    return;
                }

                var portName = PortPicker.SelectedItem.ToString();
                var baudRate = int.Parse(BaudRatePicker.SelectedItem?.ToString() ?? "9600");
                
                var success = await _serialService.ConnectAsync(portName, baudRate);
                if (!success)
                {
                    await DisplayAlert("错误", "连接失败", "确定");
                }
            }
        }
        catch (Exception ex)
        {
            await DisplayAlert("错误", $"连接操作失败: {ex.Message}", "确定");
        }
    }

    private async void OnSendClicked(object sender, EventArgs e)
    {
        try
        {
            if (!_serialService.IsConnected)
            {
                await DisplayAlert("提示", "请先连接串口", "确定");
                return;
            }

            var text = SendEntry.Text;
            if (string.IsNullOrWhiteSpace(text))
            {
                await DisplayAlert("提示", "请输入要发送的内容", "确定");
                return;
            }

            await _serialService.SendTextAsync(text + "\r\n");
            SendEntry.Text = string.Empty;
            
            // 在消息列表中显示发送的内容
            _receivedMessages.Add($"[发送] {DateTime.Now:HH:mm:ss} - {text}");
        }
        catch (Exception ex)
        {
            await DisplayAlert("错误", $"发送失败: {ex.Message}", "确定");
        }
    }

    private void OnDataReceived(object sender, SerialDataEventArgs e)
    {
        // 在UI线程中更新界面
        MainThread.BeginInvokeOnMainThread(() =>
        {
            _receivedMessages.Add($"[接收] {e.Timestamp:HH:mm:ss} - {e.Text.Trim()}");
            
            // 自动滚动到最新消息
            if (_receivedMessages.Count > 0)
            {
                MessagesCollectionView.ScrollTo(_receivedMessages.Last());
            }
        });
    }

    private void OnConnectionChanged(object sender, bool isConnected)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            ConnectButton.Text = isConnected ? "断开" : "连接";
            StatusLabel.Text = isConnected ? "已连接" : "未连接";
            StatusLabel.TextColor = isConnected ? Colors.Green : Colors.Red;
            
            // 控制界面元素的启用状态
            PortPicker.IsEnabled = !isConnected;
            BaudRatePicker.IsEnabled = !isConnected;
            SendButton.IsEnabled = isConnected;
            SendEntry.IsEnabled = isConnected;
        });
    }

    private async void OnRefreshPortsClicked(object sender, EventArgs e)
    {
        await LoadAvailablePorts();
    }
}

依赖注入配置

/// 
/// MAUI应用程序配置
/// 
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });

        // 注册平台特定的串口服务
#if WINDOWS
        builder.Services.AddSingleton<ISerialPortService, WindowsSerialPortService>();
#elif ANDROID
        builder.Services.AddSingleton<ISerialPortService, AndroidSerialPortService>();
#elif IOS
        builder.Services.AddSingleton<ISerialPortService, iOSSerialPortService>();
#elif MACCATALYST
        builder.Services.AddSingleton<ISerialPortService, MacCatalystSerialPortService>();
#endif

        // 注册页面
        builder.Services.AddTransient<MainPage>();

        return builder.Build();
    }
}

相关学习资源

.NET MAUI开发
  • .NET MAUI官方文档 - 微软官方MAUI开发指南
  • MAUI Community Toolkit - MAUI社区工具包
  • .NET MAUI Samples - 官方MAUI示例项目
  • MAUI Blazor - MAUI混合应用开发
移动端开发
  • Android开发者文档 - Google官方Android开发指南
  • iOS开发文档 - Apple官方iOS开发文档
  • Xamarin.Forms指南 - Xamarin.Forms开发文档
  • Mobile DevOps - 移动应用DevOps平台
平台特定实现
  • Android USB Host - Android USB主机模式
  • iOS External Accessory - iOS外部配件框架
  • Windows Runtime API - Windows Runtime API文档
  • macOS IOKit - macOS硬件访问框架
依赖注入与架构
  • Microsoft.Extensions.DependencyInjection - .NET依赖注入
  • MVVM Pattern - MVVM架构模式
  • CommunityToolkit.Mvvm - MVVM工具包
  • Prism Framework - 企业级MVVM框架
移动应用发布
  • Google Play Console - Android应用发布平台
  • App Store Connect - iOS应用发布平台
  • Microsoft Store - Windows应用商店
  • App Center Distribution - 应用分发服务
跨平台开发最佳实践
  • Platform Behaviors - 平台集成最佳实践
  • Conditional Compilation - 条件编译指令
性能优化
  • MAUI Performance - MAUI性能优化指南
  • Memory Management - 内存管理最佳实践
  • Battery Optimization - 电池优化策略
测试与调试
  • MAUI Unit Testing - MAUI单元测试
  • UI Testing - UI自动化测试
  • Remote Debugging - 远程调试工具
  • App Center Analytics - 应用分析服务
开源项目参考
  • .NET Podcasts App - 微软MAUI示例应用
  • Weather MAUI App - 天气应用示例

你可能感兴趣的:(C#通讯编程,#,串口通讯,.net,IOT,MAUI,串口通讯)