文章目录
- MAUI项目架构设计
- 平台特定实现
- 接口定义
- Windows平台实现
- Android平台实现
- MAUI主界面实现
- 依赖注入配置
- 相关学习资源
- .NET MAUI开发
- 移动端开发
- 平台特定实现
- 依赖注入与架构
- 移动应用发布
- 跨平台开发最佳实践
- 性能优化
- 测试与调试
- 开源项目参考
MAUI项目架构设计
平台特定实现
接口定义
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;
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;
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){if (IsSerialDevice(device)){portNames.Add($"USB-{device.DeviceName}");}}return portNames.ToArray();}public async Task<bool> ConnectAsync(string portName, int baudRate){try{var deviceList = _usbManager.DeviceList;foreach (var device in deviceList.Values){if ($"USB-{device.DeviceName}" == portName){_usbDevice = device;break;}}if (_usbDevice == null)return false;if (!_usbManager.HasPermission(_usbDevice)){return false;}_connection = _usbManager.OpenDevice(_usbDevice);if (_connection == null)return false;_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){return device.DeviceClass == UsbClass.CdcData || device.DeviceClass == UsbClass.Comm;}
}
#endif
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){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();}
}
依赖注入配置
public static class MauiProgram
{public static MauiApp CreateMauiApp(){var builder = MauiApp.CreateBuilder();builder.UseMauiApp<App>().ConfigureFonts(fonts =>{fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");});
#if WINDOWSbuilder.Services.AddSingleton<ISerialPortService, WindowsSerialPortService>();
#elif ANDROIDbuilder.Services.AddSingleton<ISerialPortService, AndroidSerialPortService>();
#elif IOSbuilder.Services.AddSingleton<ISerialPortService, iOSSerialPortService>();
#elif MACCATALYSTbuilder.Services.AddSingleton<ISerialPortService, MacCatalystSerialPortService>();
#endifbuilder.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 - 天气应用示例
