.NET MAUI 跨平台:一套代码多端运行
.NET MAUI 跨平台入门:用一套代码征服多端
在移动与桌面应用开发领域,多平台重复造轮子一直是团队效率的隐形杀手。.NET MAUI(Multi-platform App UI)的出现彻底改变了这一局面——它允许你使用单一的 C# 和 XAML 代码库,构建同时运行于 Android、iOS、macOS、Windows 以及 Tizen 的原生应用。本教程将从零开始,带你掌握 .NET MAUI 的核心概念与实战流程,让“Write Once, Run Anywhere”不再是一句口号。
先决条件与开发环境
开始之前,请确认你的开发机满足以下要求:
- 操作系统:Windows 10 1809+(推荐 Windows 11)或 macOS 11+(用于 iOS/macOS 构建)
- 开发工具:Visual Studio 2022 17.3+(需安装“.NET Multi-platform App UI 开发”工作负载),或 JetBrains Rider 2022.2+,也可使用命令行 + VS Code
- SDK:.NET 6 或 .NET 7/8(MAUI 从 .NET 6 开始正式支持)
- 硬件:至少 8 GB 内存,并开启 Hyper-V(Windows)或通过 Mac 构建机(iOS)
安装完工作负载后,打开终端执行以下命令验证环境:
dotnet workload list
若 maui 出现在列表中,即表示环境就绪。
第一个 .NET MAUI 项目
创建项目
在 Visual Studio 中选择“创建新项目” -> 搜索“MAUI” -> 选取“.NET MAUI 应用”。也可以通过 CLI 创建:
dotnet new maui -n MyFirstMauiApp
cd MyFirstMauiApp
项目结构解析
生成的项目包含以下关键文件:
- MauiProgram.cs:应用入口,类似
Main,负责配置服务、字体、平台特定初始化。 - App.xaml / App.xaml.cs:定义全局资源字典,并通过
Application.Current访问。 - AppShell.xaml:基于
Shell的导航结构,管理页面路由、Flyout 菜单和 Tab。 - MainPage.xaml:默认首页,用于展示 UI。
- Platforms/ 文件夹:存放各平台的入口代码(Android 的
MainApplication、iOS 的AppDelegate等),通常无需手动修改。
运行项目,你将看到一个带有“Hello, World!”和计数器按钮的默认应用。
跨平台 UI 设计:XAML 与控件
MAUI 提供了一套丰富的跨平台控件,它们会自动渲染为各平台的原生等效控件。例如:
<Button>在 Android 上是 Material Design 按钮,在 iOS 上则是 UIKit 的UIButton。<Label>、<Entry>、<ListView>等均遵循统一抽象。
布局系统
使用灵活的布局容器构建自适应界面:
<ContentPage xmlns="...">
<Grid ColumnDefinitions="*, 2*" RowDefinitions="Auto, *">
<BoxView Color="Blue" Grid.Row="0" Grid.Column="0" />
<VerticalStackLayout Grid.Row="1" Grid.Column="1" Spacing="10">
<Label Text="欢迎使用 MAUI" FontSize="24" HorizontalOptions="Center"/>
<Button Text="点击我" Clicked="OnButtonClicked"/>
</VerticalStackLayout>
</Grid>
</ContentPage>
MAUI 支持 HorizontalStackLayout、VerticalStackLayout、Grid、FlexLayout 和 AbsoluteLayout,组合使用可应对绝大多数布局场景。
数据绑定与 MVVM 模式
MAUI 内置强大的数据绑定引擎,与 MVVM 模式天然契合。以下是一个简单的双向绑定示例:
ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
// INotifyPropertyChanged implementation...
}
XAML 绑定:
<Entry Text="{Binding Name, Mode=TwoWay}" Placeholder="输入你的名字" />
<Label Text="{Binding Name, StringFormat='你好, {0}!'}" />
在 MauiProgram.cs 中注册 ViewModel 与页面,并使用依赖注入:
builder.Services.AddSingleton<MainPage>();
builder.Services.AddSingleton<MainViewModel>();
然后在页面构造函数中接收 ViewModel 并设置 BindingContext。
导航与 Shell
使用 Shell 可实现复杂的导航结构,而无需手动管理导航栈。
定义路由:
<Shell ...>
<FlyoutItem Title="首页" Icon="home.png">
<ShellContent ContentTemplate="{DataTemplate local:MainPage}" Route="main" />
</FlyoutItem>
<FlyoutItem Title="详情" Icon="detail.png">
<ShellContent ContentTemplate="{DataTemplate local:DetailPage}" Route="detail" />
</FlyoutItem>
</Shell>
代码导航:
await Shell.Current.GoToAsync("detail?itemId=42");
接收参数时,为目标页面的 QueryProperty 装饰:
[QueryProperty(nameof(ItemId), "itemId")]
public partial class DetailPage : ContentPage
{
public string ItemId { get; set; }
}
处理平台差异:条件编译与部分类
即使 MAUI 让大部分代码共享,有时仍需调用平台特定的 API 或调整行为。
条件编译:
#if ANDROID
// 调用 Android 特有功能
#elif IOS
// 调用 iOS 特有功能
#endif
部分类与平台文件夹:
为需要平台实现的类创建一个共享的抽象类,然后在 Platforms/Android、Platforms/iOS 等目录下添加对应的部分类文件。例如定义 IBatteryInfo 接口,各平台分别实现,最后通过依赖注入注册。
MAUI 也内置了大量实用 API(如连接性、地理定位、传感器等),大多封装在 Microsoft.Maui.Devices 等命名空间下,只需调用通用 API 即可,无需自行编写平台代码。
访问原生 API 与第三方库
当内置 API 无法满足需求时,可以使用 .NET for Android/iOS/macOS 的绑定方式直接调用原生 SDK。例如,在 MAUI 项目中直接引用 Xamarin.Firebase.* 或 Plugin.Maui.Audio 等 NuGet 包,它们会帮你处理平台隔离。
示例:播放音频
var player = AudioManager.Current.CreatePlayer(await FileSystem.OpenAppPackageFileAsync("sound.mp3"));
player.Play();
第三方库生态日益丰富,常见的有:
- CommunityToolkit.Maui:补充控件、动画和行为
- SkiaSharp:跨平台 2D 图形渲染
- ZXing.Net.Maui:条码扫描
自定义控件与处理程序
MAUI 的渲染层通过处理程序将虚拟控件映射到原生视图。你可以修改现有控件的处理程序或创建全新的自定义控件。
自定义控件示例(RatingView):
public class RatingView : View
{
public static readonly BindableProperty ValueProperty = ...;
public int Value { get; set; }
}
然后为各平台实现 IRatingViewHandler,在 MauiProgram.cs 中注册:
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<RatingView, RatingViewHandler>();
});
调试与多平台测试
Visual Studio 集成了多种调试手段:
- 热重载:修改 XAML 或 C# 代码后无需重新部署即可看到效果。
- XAML 实时可视化树:检查运行时 UI 树结构与属性。
- 平台目标切换:从工具栏直接选择 Android 模拟器、iOS 模拟器(需要 Mac 连接)、Windows 本地应用等。
对于 UI 测试,可以使用 UITest 或 Appium 编写跨平台的自动化测试脚本。
应用打包与发布
MAUI 项目通过 dotnet publish 命令完成打包,各平台输出标准包格式:
- Android:
.apk或.aab(Google Play) - iOS:
.ipa(需使用 macOS 的Archive流程,并通过 Xcode 或 Transporter 上传) - Windows:MSIX 包或纯
.exe - macOS:
.app包(需代码签名)
配置版本号、签名证书等都可以在项目 .csproj 文件中通过 MSBuild 属性完成。
例如构建 Android 的发行包:
dotnet publish -f net8.0-android -c Release -p:AndroidPackageFormats=apk
常见问题与最佳实践
- 性能优化:尽量使用
CollectionView替代ListView,启用虚拟化;异步加载数据,避免阻塞 UI 线程。 - 图片资源:将 SVG 或 PNG 放在
Resources/Images中,MAUI 自动生成多平台尺寸,无需手动切图。 - 字体图标:引入字体文件(如 FontAwesome),在
MauiProgram.cs中注册,然后以标签形式使用。 - 应用生命周期:通过
Application.Current的事件(如Sleep、Resume)管理前后台切换。 - 避免过多嵌套布局:优先选择相对简单的布局组合,减少布局传递次数。
结语
.NET MAUI 不仅是一个 UI 框架,它更是一套完整的跨平台构建生态。从 UI 抽象、数据绑定、导航到原生 API 调用,一切都围绕“代码共享最大化”展开。你只需写一次业务逻辑和界面,就能在六个主流平台上获得原生体验。随着 .NET 8 及后续版本的长周期支持,现在正是投入学习 MAUI 的最佳时机。
即刻动手,用 dotnet new maui 开启你的跨平台之旅吧!