Uno Platform 作为跨平台 .NET UI 框架,针对不同目标平台的特性与约束,设计了四种互补的运行时执行模式。这些模式在启动速度、运行时性能与包体积之间呈现显著的权衡特征,开发者需根据具体场景选择最优配置。
解释器模式是 Uno Platform 的默认执行模式,尤其在 WebAssembly 平台上作为开发阶段的基础配置。该模式下,.NET 中间语言(IL)通过基于 WebAssembly 实现的 Mono 解释器逐条执行,无需预先将 IL 编译为原生机器码。这一设计的核心优势在于极快的构建速度与最小的包体积——仅需传输 .NET 运行时与原始程序集,无需额外的原生代码生成。然而,性能代价同样显著:根据 Uno Platform 官方基准测试,解释器模式的执行速度通常比 WebAssembly 编译代码慢约 30 倍 。这一差距在计算密集型场景(如复杂数据绑定、实时图像处理、大规模集合操作)中尤为明显。解释器模式适用于快速原型开发、内网工具应用,或作为 AOT 编译失败时的降级方案。在移动平台上,解释器模式通常不作为生产环境的推荐配置,但在特定调试场景或动态代码加载需求下仍有其价值。
混合模式(InterpreterAndAOT)代表了 Uno Platform 在性能与包体积之间的工程平衡,是当前 WebAssembly 生产部署的推荐配置。该模式通过选择性编译策略,将应用程序的热路径代码(高频执行的核心代码)预编译为原生 WebAssembly 字节码,而冷路径代码(低频或边缘功能)保留 IL 由解释器执行。这种分层设计使得包体积相比完整 AOT 减少约 50%,同时确保关键性能场景的响应速度接近原生水平 。混合模式的启用通过 WasmShellMonoRuntimeExecutionMode 属性配置,且仅在 dotnet publish 或 dotnet build -c Release 时激活——常规 Debug 构建保持解释器模式以保障开发迭代效率 。现代 Uno Platform 版本已支持方法级别的精细混合编译,这得益于 Profile-Guided AOT 技术的引入,允许开发者通过实际运行数据精确指导 AOT 编译范围。
完整 AOT 模式将应用程序的所有托管代码彻底编译为目标平台的原生机器码,完全消除运行时的 IL 解释开销。在 iOS 平台上,完整 AOT 并非可选优化,而是 Apple 平台政策的强制性要求——iOS 的安全架构禁止动态代码生成,所有 .NET 代码必须在构建阶段静态化 。完整 AOT 的构建产物包含完全剥离 IL 方法体的原生二进制文件,这不仅带来最优的运行时性能,还提供了额外的代码保护(反编译难度显著增加)。然而,代价同样明显:构建时间大幅延长(大型项目可达数十分钟),包体积急剧膨胀(因原生代码密度通常高于 IL),以及某些动态特性(如 System.Reflection.Emit)的兼容性限制。在 Android 平台,完整 AOT 可通过显式禁用 Profile-Guided AOT 实现(-p:AndroidEnableProfiledAot=false),但需充分评估包体积与编译时间的代价 。
Jiterpreter 是 .NET 9 引入的革命性执行技术,为 WebAssembly 平台提供了 AOT 与解释器之外的第三条路径。该模式在解释器执行框架内嵌入了轻量级 JIT 引擎,能够在运行时动态生成部分 WebAssembly 代码——解释器负责初始执行并收集热点信息,Jiterpreter 则识别频繁执行的方法并即时编译为优化代码缓存。与完整 AOT 相比,Jiterpreter 避免了全量预编译的开销,同时获得接近 AOT 的热路径性能;与纯解释器相比,则实现了数量级的执行速度提升。启用配置极为简洁:<WasmShellEnableJiterpreter>true</WasmShellEnableJiterpreter> 。高级调优可通过 WasmShellRuntimeOptions 属性实现,如启用热度估计(--jiterpreter-estimate-heat)或统计输出(--jiterpreter-stats-enable),运行时数据可通过浏览器开发者控制台的 INTERNAL.jiterpreter_dump_stats() 获取。Uno Platform 5.6 及后续版本中,Jiterpreter 与 Profiled AOT 的结合可带来最高 10 倍的执行速度提升 。
Uno Platform 的 AOT 实现并非单一技术方案,而是针对不同目标平台调用最优的底层编译工具链与运行时架构,形成多元化的技术矩阵。
| 目标平台 | AOT 技术栈 | 核心编译器 | 关键依赖 | 典型输出格式 |
|---|---|---|---|---|
| iOS | Mono Full AOT | Mono AOT Compiler | Xcode 工具链 | Mach-O (ARM64) |
| Android | Mono AOT + LLVM (可选) | Mono AOT + LLVM | Android NDK | ELF (.so, ARM64/ARMv7) |
| WebAssembly | Mono AOT + Emscripten | Mono AOT → LLVM IR → Emscripten | Emscripten SDK | WASM 模块 + JS 胶水 |
| Skia Desktop (Linux/macOS/Windows) | .NET Native AOT (CoreCLR) | ILC + RyuJIT | 平台 SDK | 自包含原生可执行文件 |
| WinUI 3 (Windows) | .NET Native AOT (Skia/Win32) | ILC + RyuJIT | Windows App SDK | MSIX 包或单文件 EXE |
Mono AOT 编译器是 Uno Platform 移动端与 Web 平台的核心编译基础设施,其历史可追溯至 Xamarin 技术栈,经过十余年生产环境验证。该编译器将 C# IL 代码转换为各平台的原生代码:在 iOS/Android 上生成 ARM/ARM64 机器码,在 WebAssembly 上生成符合 WASM MVP 规范的字节码。Mono AOT 的关键特征在于保留部分运行时元数据以支持反射等动态特性,这与 .NET Native AOT 的激进静态链接形成对比 。在 WebAssembly 场景中,Mono AOT 输出需通过 Emscripten 工具链进一步处理,形成完整的浏览器可执行模块。
.NET Native AOT(又称 CoreCLR Native AOT)是微软自 .NET 7 起正式推出的静态编译技术,代表了 .NET 运行时架构的重大演进。与 Mono AOT 不同,Native AOT 基于 CoreCLR 的 RyuJIT 编译器,在发布时执行全程序分析,生成完全自包含的原生可执行文件,无需任何 .NET 运行时安装。其核心优势包括:启动速度极快(无运行时初始化开销)、内存占用更低(无 JIT 编译器内存消耗)、部署极度简化(单文件可执行)、以及固有的反编译保护。Uno Platform 对 Native AOT 的支持始于 4.7 版本,最初针对 Skia+GTK 后端,要求 GtkSharp 3.24.24.38 或更高版本 。随着版本演进,Native AOT 的支持范围扩展至所有 Skia 桌面目标以及 Windows WinUI 3 的特定配置。
LLVM(Low Level Virtual Machine)作为模块化编译器基础设施,为 Android 平台的 AOT 编译提供了强大的优化后端。启用 LLVM 优化(通过 -p:EnableLLVM=true)后,Mono AOT 编译器将 IL 代码转换为 LLVM 中间表示(IR),再由 LLVM 工具链执行目标特定的优化与机器码生成。优化流水线包括:指令选择(IR 映射到 ARM/ARM64 指令集)、循环优化(向量化、展开、不变量外提)、寄存器分配(图着色算法最大化利用率)、以及代码布局(基本块重排优化指令缓存)。实测表明,LLVM 优化可带来 20-40% 的运行时性能提升(计算密集型场景),但代价是构建时间显著延长(可能翻倍)以及 Android NDK 的额外依赖 。
Emscripten 是将 C/C++ 代码编译为 WebAssembly 的完整工具链,也是 Mono WebAssembly 运行时的构建基础。Uno Platform 的 WebAssembly AOT 编译流程中,Emscripten 承担关键角色:Mono AOT 编译器生成 LLVM IR,Emscripten 将其转换为 WebAssembly 字节码,并提供 JavaScript 胶水代码以实现浏览器 API 互操作。历史版本(Uno 3.x-4.x)要求开发者手动安装配置 Emscripten SDK,常因版本不匹配导致构建失败 。.NET 9 的重大改进在于:Emscripten 工具链由 .NET SDK 自动管理,无需手动安装,ninja-build 等外部依赖也被移除,同时支持 Windows ARM64、macOS ARM64 与 Linux ARM64 上的 AOT 构建 。
| .NET 版本 | 关键 AOT 特性 | Uno Platform 最低版本 | 影响平台 | 推荐场景 |
|---|---|---|---|---|
| .NET 7 | Native AOT 正式版(桌面) | 4.7 | Skia/GTK | Linux/macOS 桌面部署 |
| .NET 8 | Marshal Methods(Android)、改进修剪分析 | 5.0 | Android、全平台 | 全平台统一升级 |
| .NET 9 | **Jiterpreter**、增量 AOT 构建、**WebCIL**、自动 Emscripten 管理 | 5.5 | WebAssembly、全平台 | **新项目的推荐版本** |
.NET 9 的发布标志着 WebAssembly AOT 构建体验的质变:增量构建显著缩短重复编译时间,WebCIL 格式缓解反病毒软件误报,卫星程序集与 ICU 数据的部分下载优化本地化场景 。对于新启动的项目,强烈建议采用 .NET 9 以获取最优的 AOT 开发体验。
| Uno Platform 版本 | AOT 关键改进 | 推荐升级场景 |
|---|---|---|
| **4.7** | Skia+GTK **Native AOT 正式支持** | Linux/macOS 桌面部署 |
| 5.0 | .NET 8 集成、改进的移动端 AOT | 全平台统一升级 |
| **5.6** | WebAssembly AOT **10x 性能提升**、热重载改进、Visual State 创建效率 **2.5x** 提升 | Web 应用性能优化 |
| **6.0** | **Win32 实现替代 WPF**、**74% 包体积缩减**(Windows)、**35% AOT 构建时间提升**、XAML/资源修剪扩展至 iOS 和桌面 | **Windows 应用现代化、全平台统一** |
Uno Platform 6.0(2025 年 5 月发布)是 AOT 技术的集大成者:统一的 Skia 渲染引擎覆盖所有平台,Win32 后端替代 WPF 实现完整 IL 修剪,空白应用包体积在 Windows 上减少 74%、iOS 上减少 21%,AOT 编译构建时间提升 35% 。
| 平台 | AOT 技术栈 | 成熟度 | 关键限制 | 生产建议 |
|---|---|---|---|---|
| **iOS** | Mono Full AOT | ⭐⭐⭐⭐⭐ **生产就绪** | **强制 AOT**,无动态代码生成 | 默认启用,无需额外配置 |
| **Android** | Mono AOT + LLVM + PG-AOT | ⭐⭐⭐⭐⭐ **生产就绪** | 构建时间较长 | 启用 **Startup Tracing** 优化 |
| **WebAssembly** | Mono AOT Mixed/PG-AOT/**Jiterpreter** | ⭐⭐⭐⭐⭐ **生产就绪** | Safari 大小限制、调试复杂 | 推荐 **PG-AOT + Jiterpreter** |
| **Skia Desktop** (GTK/Linux/macOS/Windows) | **.NET Native AOT** | ⭐⭐⭐⭐⭐ **生产就绪** | P/Invoke 需显式配置 | **推荐配置**,单文件部署 |
| **WPF** (Windows) | **不支持 Native AOT** | ⭐⭐☆☆☆ **受限** | WPF 框架架构限制 | **迁移至 WinUI 3 或 GTK** |
| **WinUI 3** (Windows) | .NET Native AOT (Skia/Win32) | ⭐⭐⭐⭐☆ **成熟** | WinRT API 边界 | **6.0+ 推荐 Skia+Win32 路径** |
iOS 平台的 AOT 编译并非技术选择,而是 Apple 生态系统的强制性安全要求。Apple 的 App Store 审核指南明确禁止应用程序在运行时生成可执行代码,这一政策直接封杀了 JIT 编译在 iOS 上的应用可能性。技术层面,iOS 设备的硬件内存保护机制(W^X,Write XOR Execute)确保内存页不可同时具有写权限与执行权限,从根本上阻止了动态代码生成 。因此,所有基于托管语言(C#、Java、JavaScript 等)的 iOS 应用必须通过 AOT 编译将代码静态化,方能在 App Store 分发。
Uno Platform 的 iOS 实现继承自 Xamarin.iOS(现 .NET for iOS),采用 Mono 完整 AOT(Full AOT) 作为唯一支持的编译模式。与 Android 的可选 AOT 不同,iOS 的 AOT 是构建流程的固有环节,开发者无需(也无法)显式禁用。这一设计决策确保了 Uno Platform 应用与原生 Swift/Objective-C 应用在技术合规性上的等效性,同时继承了 Xamarin 生态十余年的 iOS 适配经验。
Mono AOT 编译器在技术上支持多种编译粒度,但 iOS 平台实际仅启用 完整 AOT 模式。完整 AOT 的核心特征包括:所有托管方法在构建阶段编译为 ARM64 机器码;IL 方法体可选择性剥离以减小包体积;运行时元数据保留以支持反射与序列化。与之相对的部分 AOT(或 "JIT-less" 模式)允许保留部分 IL 由解释器执行,这在 Android 的 Profile-Guided AOT 中有应用,但 iOS 平台因政策限制不予支持。
完整 AOT 的性能特征呈现双刃剑效应:启动速度极快(无运行时编译延迟),执行效率接近原生代码,但二进制体积显著增大,且某些动态特性(如 System.Reflection.Emit)完全不可用。Uno Platform 通过托管链接器(Managed Linker)缓解体积问题,默认启用 "Link Framework SDKs Only" 模式,移除未使用的 BCL(Base Class Library)成员。
Uno Platform 的 iOS 实现与 Xamarin.iOS 运行时深度共享基础设施,这一架构决策带来显著的兼容性优势。开发者可将现有的 Xamarin.iOS 绑定库、自定义渲染器与平台特定代码近乎无缝地迁移至 Uno Platform。运行时层面,两者共享相同的垃圾回收器(SGen 或 .NET 6+ 的 CoreCLR GC)、线程调度模型与 Objective-C 互操作层。
然而,兼容性边界仍需关注:Uno Platform 的 UI 渲染层完全独立实现,不依赖 Xamarin.Forms 的渲染器体系,这意味着 Xamarin.Forms 的自定义渲染器需重写为 Uno Platform 的样式或附加属性系统。此外,Uno Platform 的 WinUI 3 API 表面与 Xamarin.iOS 的 UIKit 直接访问并存,开发者需在跨平台抽象与平台特定优化之间做出权衡。
iOS 项目的 AOT 配置相对简洁,主要依赖 .NET SDK 的默认行为。标准 Uno Platform iOS 项目的 Release 配置已隐含 AOT 启用,关键配置片段如下:
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<!-- iOS 强制 AOT,无需显式设置 PublishAot -->
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
<!-- Uno 6.0+:启用 XAML 修剪 -->
<UnoXamlTrimming>true</UnoXamlTrimming>
</PropertyGroup>
值得注意的是,iOS 项目通常不显式设置 <PublishAot>true</PublishAot>,因为 .NET for iOS 的 SDK 已默认启用 AOT。这一行为与 Android 形成对比,后者需显式配置以启用 AOT 优化。
iOS 应用的发布构建通过 dotnet publish 命令执行,典型参数组合如下:
# 物理设备发布(ARM64,现代 iPhone)
dotnet publish -f net9.0-ios -c Release -r ios-arm64 -p:ArchiveOnBuild=true
# 模拟器发布(Apple Silicon Mac)
dotnet publish -f net9.0-ios -c Release -r iossimulator-arm64
关键参数解析:
-f net9.0-ios:指定目标框架为 .NET 9 iOS-r ios-arm64:限定运行时标识符为 ARM64(iPhone XS 及后续机型)-p:ArchiveOnBuild=true:触发 .ipa 归档生成,用于 App Store 分发-p:PublishAot=true,.NET 8+ 已简化Uno Platform 6.0 引入了对 iOS 的 Skia 渲染后端支持,此前版本仅支持 Native Rendering(UIKit 直接映射)。这一扩展带来了 AOT 配置的微妙差异:
| 渲染后端 | AOT 技术栈 | 包体积影响 | 性能特征 | 注意事项 |
|---|---|---|---|---|
| **Native Rendering** (UIKit) | Mono Full AOT | 较小(原生控件复用) | 启动快,平台原生感强 | 跨引用 UIElement 易致内存泄漏,VisualStateManager 须置于 XAML 根元素 |
| **Skia Rendering** | Mono Full AOT + SkiaSharp AOT | 较大(Skia 二进制) | **像素级跨平台一致性**,渲染性能提升最高 **107x** | 确保 SkiaSharp 类型在 LinkerConfig.xml 中保留 |
选择 Skia 后端的 iOS 项目需确保 SkiaSharp 的 AOT 兼容性,推荐配置:
<!-- LinkerConfig.xml -->
<linker>
<assembly fullname="SkiaSharp" preserve="all" />
<assembly fullname="SkiaSharp.Views.Uno" preserve="all" />
</linker>
iOS 平台的启动性能优化可借鉴 Android 的 Startup Tracing 方法论,尽管实现细节有所差异。核心思路是:通过仪器化构建采集应用启动阶段的实际执行路径,生成自定义 AOT 配置文件,指导编译器优先优化热路径代码。
Uno Platform 6.0 的 统一 Skia 引擎带来了显著的启动性能提升:官方测试显示 iPhone 13 上的启动时间从 1.5 秒降至 0.49 秒,改善幅度达 67% 。这一提升源于渲染架构的简化与更高效的资源加载管道,AOT 编译的代码布局优化也贡献显著。
托管链接器(IL Linker)是控制 iOS 包体积的核心工具。Uno Platform iOS 项目支持三种链接模式:
| 链接模式 | 配置值 | 行为描述 | 适用场景 |
|---|---|---|---|
| **不链接** | None | 保留所有程序集完整 | 调试疑难、链接器缺陷规避 |
| **仅链接 SDK** | SdkOnly(默认) | 链接 BCL 与平台框架,保留用户代码 | **生产默认**,平衡安全与体积 |
| **完全链接** | Full | 链接所有程序集,包括用户代码 | 激进优化,需充分测试 |
完全链接模式可通过以下配置启用:
<PropertyGroup>
<MtouchLink>Full</MtouchLink>
<!-- 或 MSBuild 属性 -->
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
</PropertyGroup>
完全链接的潜在风险在于过度修剪:反射依赖的类型、动态实例化的类、XAML 中引用的资源可能被错误移除。缓解策略包括:使用 [DynamicDependency] 属性标记、配置 LinkerConfig.xml 保留规则、以及启用 <TrimmerSingleWarn>false</TrimmerSingleWarn> 获取详细警告。
iOS 设备的内存约束比桌面平台更为严苛,AOT 编译后的应用需特别关注垃圾回收器配置。Mono SGen GC 的关键调优参数包括:
<PropertyGroup>
<!-- 启用并发 GC 减少暂停 -->
<MtouchEnableSGenConc>true</MtouchEnableSGenConc>
<!-- 调整 nursery 大小(年轻代) -->
<MtouchNurserySize>2m</MtouchNurserySize>
<!-- 设置堆扩展策略 -->
<MtouchHeapSize>256m</MtouchHeapSize>
</PropertyGroup>
或通过代码动态配置:
// Main.iOS.cs 中的 GC 配置
public static void Main(string[] args)
{
Environment.SetEnvironmentVariable(
"MONO_GC_PARAMS",
"soft-heap-limit=256m,nursery-size=8m,major=marksweep-conc");
UIApplication.Main(args, null, typeof(App));
}
参数调优需考虑 iOS 设备的内存约束——低端设备可能需要更保守的配置以避免 OOM(Out of Memory)。
iOS 的 AOT 强制政策彻底禁用了动态代码生成技术,以下 API 与模式在 iOS 上不可用或行为受限:
| 技术/API | iOS 兼容性 | 替代方案 |
|---|---|---|
System.Reflection.Emit | ❌ **完全不可用** | 表达式树(有限)、预生成代码、**源生成器** |
DynamicMethod | ❌ **完全不可用** | 委托缓存、预编译表达式 |
Assembly.Load(byte[]) | ❌ **完全不可用** | 静态链接所有依赖、插件架构重新设计 |
| Roslyn 脚本执行 | ❌ **完全不可用** | 预编译脚本、解释型 DSL |
RegexOptions.Compiled | ⚠️ **忽略标志** | **源生成正则(.NET 7+)** |
Uno Platform 的源生成器(Source Generators)基础设施是应对这一限制的关键——在构建时生成原本需要动态创建的代码,如 XAML 代码后置、依赖属性实现等。开发者应避免在 iOS 代码路径中使用 dynamic,对必要的反射操作使用预缓存模式。
AOT 编译对反射的影响主要体现在元数据修剪:完整 AOT 模式下,IL 方法体可被剥离,但反射所需的类型、成员、属性信息需显式保留。System.Text.Json 与 Newtonsoft.Json 的 AOT 兼容性对比:
| 序列化器 | AOT 兼容性 | 关键配置 |
|---|---|---|
| **Newtonsoft.Json** | ⚠️ 需修剪配置 | 保留 JsonConverter 子类、契约解析器 |
| **System.Text.Json** | ✅ **源生成推荐** | 使用 JsonSerializerContext 源生成器 |
| **MessagePack** | ✅ 良好 | 使用 MessagePackSerializerOptions 预配置 |
推荐迁移至 System.Text.Json 的源生成模式,从根本上消除反射依赖:
[JsonSerializable(typeof(MyViewModel))]
[JsonSerializable(typeof(List<MenuItem>))]
internal partial class AppJsonContext : JsonSerializerContext { }
// 使用:JsonSerializer.Deserialize(json, AppJsonContext.Default.MyViewModel)
引入第三方 NuGet 包前,务必验证其 AOT 兼容性。评估维度包括:
[AssemblyMetadata("IsTrimmable", "True")]dotnet publish 的修剪警告、ILCompiler 的 AOT 分析、以及实际设备测试。
Android 平台的 AOT 编译采用 Mono AOT 编译器与 LLVM 优化后端的组合架构,这一设计在性能与灵活性之间取得了工程平衡。与 iOS 的强制完整 AOT 不同,Android 提供了更灵活的配置空间:开发者可在解释器、混合 AOT、Profile-Guided AOT 和完整 AOT 之间选择,根据应用的性能-包体积-构建时间优先级进行权衡。
基础 AOT 编译流程与 iOS 类似——Mono AOT 编译器将 IL 转换为 ARM64/ARMv7 机器码。关键差异在于 Android 允许运行时回退:AOT 编译失败或缺失的方法可回退至解释器执行,这一容错机制在 iOS 上不存在。LLVM 后端通过 -p:EnableLLVM=true 启用 ,将代码生成委托给 LLVM 的优化管道,带来 10%-30% 的性能提升,但增加构建时间和 NDK 依赖。
Profile-Guided AOT(PG-AOT) 是 Android 平台平衡包体积与运行时性能的关键技术。其核心机制是:通过运行时分析收集应用实际执行的方法调用数据,生成自定义 AOT 配置文件;后续构建仅对配置文件中标记的"热方法"进行 AOT 编译,其余代码保留在解释器中执行。
PG-AOT 的工作流程分为三个阶段:
| 阶段 | 关键操作 | 产出 |
|---|---|---|
| **分析数据采集** | 构建特殊仪器化版本,在目标设备上执行典型用户场景 | 原始执行轨迹数据 |
| **配置文件生成** | 处理原始数据,生成 .aprof 格式的 AOT 配置文件 | custom.aprof 文件 |
| **优化构建集成** | 将配置文件注入发布构建,指导 AOT 编译器的方法选择 | 优化后的 APK/AAB |
PG-AOT 的典型效果:包体积增加 20-40%(对比完整 AOT 的 100-200%),热路径性能接近完整 AOT 的 95%,是大多数 Android 应用的推荐配置。
Marshal Methods 是 .NET 8 引入的 Android 特定优化,旨在减少托管代码与 Java/Kotlin 互操作的开销。传统 JNI(Java Native Interface)调用涉及复杂的参数封送与线程上下文切换,Marshal Methods 通过预生成优化的封送存根(stubs)显著降低这一成本。
启用配置:
<PropertyGroup>
<AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods>
</PropertyGroup>
技术实现上,Marshal Methods 在构建阶段分析托管代码中的 [Java.Interop.Export] 与 [Java.Interop.JniMethodSignature] 标记,生成对应的 JNI 注册表与优化封送代码。这一优化对大量使用 Android SDK API 的 Uno Platform 应用尤为有益,实测可减少 15-25% 的 JNI 调用开销。
Android 项目的 AOT 配置需显式启用,与 iOS 的强制 AOT 形成对比。标准配置如下:
<!-- YourApp.Android.csproj -->
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<!-- 启用 AOT 编译 -->
<RunAOTCompilation>true</RunAOTCompilation>
<!-- 启用 LLVM 优化后端(推荐生产环境) -->
<EnableLLVM>true</EnableLLVM>
<!-- 启用 Marshal Methods(.NET 8+) -->
<AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods>
<!-- 启用托管链接器 -->
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
<!-- 启用 Profile-Guided AOT -->
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
命令行发布验证:
dotnet publish \
-f net9.0-android \
-c Release \
-p:AndroidPackageFormat=aab \
-o ./publish/android
-p:EnableLLVM=true)LLVM 后端的启用已在 3.2.1 节展示,此处补充故障排查要点。LLVM 构建失败的常见原因:
| 错误症状 | 根因分析 | 解决方案 |
|---|---|---|
clang 未找到 | NDK 工具链配置缺失 | 验证 AndroidSdkDirectory 与 AndroidNdkDirectory |
opt 工具崩溃 | LLVM 版本与 NDK 不兼容 | 升级 NDK 至推荐版本(**25c+**) |
| 链接时符号未找到 | 原生库 ABI 不匹配 | 确保所有 .so 文件包含目标 ABI |
-p:AndroidEnableMarshalMethods=true)Marshal Methods 的完整配置(.NET 8+):
<PropertyGroup>
<AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods>
<!-- 可选:启用实验性快速部署 -->
<AndroidFastDeploymentType>Assemblies</AndroidFastDeploymentType>
</PropertyGroup>
已知限制:Marshal Methods 与某些动态代码模式不兼容,如遇 TypeInitializationException,可尝试禁用以隔离问题。
Startup Tracing 的首要步骤是集成 AOT 分析器包:
dotnet add package Mono.AotProfiler.Android --version 7.0.0
包集成后,项目文件自动注入必要的 MSBuild 目标与属性。
分析数据采集的标准工作流:
# 步骤 1:构建并启动分析版本(禁用 AOT 以确保完整覆盖)
dotnet build -t:BuildAndStartAotProfiling \
-f net9.0-android \
-c Release \
-p:AndroidEnableProfiledAot=false
# 步骤 2:在设备/模拟器上执行典型用户场景
# - 冷启动应用
# - 导航至主要功能页面
# - 执行核心交互操作
# 建议执行时间:30-60 秒以覆盖足够代码路径
# 步骤 3:完成分析并提取配置文件
dotnet build -t:FinishAotProfiling -f net9.0-android -c Release
成功执行后,项目目录下生成 custom.aprof 文件,此即 Startup Tracing 的核心产出。
将生成的 Profile 文件集成至发布构建:
# 移动 Profile 至标准位置
mv custom.aprof Android/custom.aprof
<!-- 在 .csproj 中引用 -->
<ItemGroup>
<AndroidAotProfile Include="Android/custom.aprof" />
</ItemGroup>
多环境配置策略:可为不同设备类别(高端/低端)或应用变体(免费/专业版)维护独立的 Profile 文件,通过 MSBuild 条件选择。
-p:AndroidEnableProfiledAot=false)特定场景(高性能计算应用、游戏引擎集成)可能需要完整 AOT 编译:
dotnet publish \
-f net9.0-android \
-c Release \
-p:AndroidEnableProfiledAot=false \
-p:RunAOTCompilation=true \
-p:EnableLLVM=true \
-p:AndroidEnableMarshalMethods=true
代价评估:包体积增加 40-80%,构建时间延长 2-3 倍,启动速度提升 10-20%。建议通过 A/B 测试验证实际收益。
Android 应用的包体积直接影响用户获取成本(下载转化率)与分发渠道限制(Google Play 的 150MB AAB 阈值)。AOT 配置的权衡矩阵:
| 配置组合 | 相对包体积 | 相对启动时间 | 相对运行时性能 | 推荐场景 |
|---|---|---|---|---|
| 解释器(无 AOT) | 100%(基准) | 慢 | 慢(~60%) | 调试、内部测试 |
| **PG-AOT(默认)** | **120-140%** | **快** | **~90%** | **生产默认** |
| PG-AOT + LLVM | 130-150% | 快 | ~95% | 性能敏感应用 |
| Full AOT + LLVM + Marshal Methods | 180-220% | 最快 | 100% | 极致性能需求 |
AOT 构建的时间成本是开发效率的关键瓶颈。优化策略包括:
| 策略 | 实施方式 | 预期效果 |
|---|---|---|
| **增量构建利用** | 确保 IntermediateOutputPath 持久化,避免 CI 环境清理 | 重复构建时间减少 50-70% |
| **构建缓存** | CI/CD 中缓存 obj/ 目录的 AOT 输出 | 跨构建会话重用 |
| **并行化** | 启用 MSBuild 并行编译 /m:8 | 多核利用率提升 |
| **条件化 LLVM** | Debug 构建禁用 LLVM,仅 Release 启用 | 开发迭代加速 |
| **缓存 Profile 文件** | 稳定的 Profile 避免重复采集 | 分析阶段时间节省 |
字符串资源是 Android 包体积的隐性贡献者。启用字符串资源修剪:
<PropertyGroup>
<AndroidLinkResources>true</AndroidLinkResources>
</PropertyGroup>
该选项移除未使用的本地化字符串,对多语言应用效果显著,可减少 10-30% 的资源体积。
Android 特定的 GC 配置通过 environment.conf 文件注入,置于 Android/Assets/ 目录:
MONO_GC_PARAMS=soft-heap-limit=512m,nursery-size=64m,evacuation-threshold=66,major=marksweep
MONO_LOG_LEVEL=error
关键参数解析:
soft-heap-limit=512m:建议堆大小上限,非硬性限制,触发更积极的回收nursery-size=64m:新生代大小,影响短生命周期对象分配效率major=marksweep:老年代收集器选择evacuation-threshold=66:触发堆整理的阈值JNI 互操作是 Android 平台特定的复杂性来源。AOT 编译对 JNI 的影响包括:
RegisterNatives 调用的时机与 AOT 初始化顺序交互[DllImport("__Internal")] 显式声明 JNI 函数,避免运行时反射查找。
Google Play 的 64 位强制政策(2019 年 8 月起)要求所有新应用支持 arm64-v8a。Uno Platform 的 AOT 配置需明确目标 ABI:
<PropertyGroup>
<!-- 推荐:仅 arm64-v8a,减小包体积 -->
<RuntimeIdentifiers>android-arm64</RuntimeIdentifiers>
<!-- 兼容性:多 ABI 支持(如必需) -->
<!-- <RuntimeIdentifiers>android-arm64;android-arm;android-x86;android-x64</RuntimeIdentifiers> -->
</PropertyGroup>
多 ABI 构建的 AOT 时间线性增长,建议 CI/CD 中并行化各 ABI 构建。
Google Play 强制要求 AAB(Android App Bundle) 格式分发,其动态交付机制与 AOT 的交互:
| 交付模式 | AOT 影响 | 配置要点 |
|---|---|---|
| 基础模块 | 完整 AOT 编译 | 核心代码路径优先优化 |
| 动态功能模块 | 延迟 AOT 或解释器 | 模块加载时性能权衡 |
| 配置 APK | 按设备优化 | 利用 Play 的 ABI 过滤 |
构建 AAB:
dotnet publish -f net9.0-android -p:AndroidPackageFormat=aab
Mono WebAssembly 运行时是 Uno Platform Web 目标的核心执行引擎,其架构演进经历了三个主要阶段:早期解释器独占阶段(Uno 1.x-2.x)、AOT 编译引入阶段(3.x-4.x)、以及现代混合执行阶段(5.x+)。当前架构的核心组件包括:
| 组件 | 功能描述 | 配置影响 |
|---|---|---|
| **解释器核心** | 执行 IL 指令的 WebAssembly 模块 | 默认启用,AOT 后备 |
| **AOT 编译模块** | 预编译热路径方法的 WebAssembly 代码 | InterpreterAndAOT 模式 |
| **Jiterpreter 引擎** | 运行时 JIT 生成 WebAssembly 代码 | .NET 9+ 可选启用 |
| **垃圾回收器** | 分代 GC,支持并发标记 | 堆大小配置影响性能 |
| **线程池模拟** | 通过 Web Workers 实现并行 | 需 COOP/COEP 头支持 |
Emscripten 是将 C/C++(及 Mono 运行时)编译为 WebAssembly 的完整工具链,其复杂性曾是 Uno Platform WebAssembly AOT 的主要门槛。历史版本(Uno 3.x-4.x)要求开发者手动安装配置:
# 历史配置(已过时)
git clone https://github.com/emscripten-core/emsdk.git
./emsdk install 3.1.12
./emsdk activate 3.1.12
source ./emsdk_env.sh # 每终端执行
.NET 9 的重大改进:Emscripten 工具链由 .NET SDK 自动管理,无需手动安装,ninja-build 等外部依赖也被移除 。这一改进显著降低了新开发者的入门门槛,同时确保了工具链版本的一致性。
| 链接模式 | 特征描述 | AOT 适用性 | 包体积影响 |
|---|---|---|---|
| **静态链接**(默认) | 所有依赖编译为单一 WASM 模块 | 完全 AOT、混合 AOT | 较大,无重复下载 |
| **动态链接**(实验性) | 主模块 + 侧模块(side modules) | 部分 AOT 场景 | 较小,支持缓存优化 |
Uno Platform 默认采用静态链接以简化部署,动态链接支持仍在积极开发中。
WasmShellMonoRuntimeExecutionMode 配置混合 AOT 模式的启用是 WebAssembly 生产部署的基础配置:
<!-- YourApp.Wasm.csproj -->
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<!-- 混合解释器/AOT 模式 -->
<WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
</PropertyGroup>
可选值:
Interpreter:纯解释器(默认,开发用)InterpreterAndAOT:混合 AOT(推荐生产)AOT:完整 AOT(较少使用,体积大)RunAOTCompilationAfterBuild 开发时启用特殊场景(AOT 行为调试、性能回归测试)需在开发构建中启用 AOT:
<PropertyGroup>
<RunAOTCompilationAfterBuild>true</RunAOTCompilationAfterBuild>
</PropertyGroup>
警告:此配置显著延长构建时间(每次构建增加 2-10 分钟),建议仅在必要时临时启用。
WasmShellGenerateAOTProfile 启用PG-AOT 的配置流程始于分析模式构建:
<PropertyGroup>
<WasmShellGenerateAOTProfile>true</WasmShellGenerateAOTProfile>
</PropertyGroup>
Uno Platform 提供浏览器内的 Profile 采集快捷键:Alt+Shift+P 触发 Profile 数据序列化与下载。采集流程:
Alt+Shift+P,浏览器自动下载 .aotprofile 文件production.aotprofile)WasmShellEnableAotProfile 集成将采集的 Profile 集成至生产构建:
<!-- 使用 Uno.Sdk 时,放置于 Platforms/WebAssembly/ 文件夹即可自动识别 -->
<!-- 非 Uno.Sdk 项目,显式引用: -->
<ItemGroup>
<WasmShellEnableAotProfile Include="production.aotprofile" />
</ItemGroup>
重新执行 dotnet publish,AOT 编译器将仅对 Profile 标记的方法进行原生编译。
WasmShellEnableJiterpreter 启用Jiterpreter 的启用极为简洁:
<PropertyGroup>
<WasmShellEnableJiterpreter>true</WasmShellEnableJiterpreter>
</PropertyGroup>
Jiterpreter 与 AOT 的协同:Jiterpreter 优化解释器执行的热路径,AOT 编译预识别的关键方法,两者互补而非互斥。推荐配置为同时启用混合 AOT 与 Jiterpreter。
高级调优配置:
<PropertyGroup>
<WasmShellEnableJiterpreter>true</WasmShellEnableJiterpreter>
<WasmShellRuntimeOptions>
--jiterpreter-stats-enable
--jiterpreter-estimate-heat
--jiterpreter-wasm-bytes-limit=50000
</WasmShellRuntimeOptions>
</PropertyGroup>
运行时统计查看:浏览器开发者控制台执行 INTERNAL.jiterpreter_dump_stats(),输出各方法的热度估计与 JIT 生成决策。
Uno Platform 官方文档记载的 PG-AOT 包体积优化成果:相比完整 AOT,PG-AOT 可实现 50% 的包体积缩减 。现代版本(5.6+)结合 XAML 修剪、资源优化与改进的 PG-AOT,缩减幅度可达 60-70%。
| 技术 | 配置方式 | 典型收益 |
|---|---|---|
| **PG-AOT** | WasmShellEnableAotProfile | **40-50% 缩减** |
| **IL Linker** | 内置,<PublishTrimmed>true</PublishTrimmed> | 30% 缩减 |
| **XAML 修剪** | UnoXamlTrimming(Uno 6.0+) | 10-20% 缩减 |
| **资源优化** | WasmShellGenerateCompressedFiles | 5-15% 缩减 |
| **IL 剥离** | WasmShellStripILAfterAOT(.NET 9+) | 5-10% 缩减 |
Uno Platform 5.6 的官方发布说明宣称:WebAssembly AOT 编译场景下可实现最高 10 倍的执行速度提升 。这一数字需结合基准测试背景理解——对比基准为纯解释器模式,实际应用中的提升幅度因代码特征而异。
关键性能突破:Uno Platform 5.6 修复了 WebAssembly AOT 编译器的关键 bug——某些包含 catch 和 finally 的方法未被正确 AOT 编译,导致 10 倍性能回退至解释器 。修复后的优化路径:
unsafe 代码:WASM 支持指针操作,关键路径可获显著加速.NET 9 引入了 WebAssembly 的增量 AOT 编译,Uno Platform 5.5+ 自动利用:
<PropertyGroup>
<WasmShellEnableIncrementalAOT>true</WasmShellEnableIncrementalAOT>
</PropertyGroup>
生产部署的缓存优化:
Cache-Control 头:静态资源长期缓存| 浏览器 | WebAssembly 支持 | 多线程 | 异常处理 | 备注 |
|---|---|---|---|---|
| Chrome 90+ | ✅ 完整 | ✅ | ✅ | **推荐基准** |
| Firefox 90+ | ✅ 完整 | ✅ | ✅ | 完整支持 |
| Safari 16+ (macOS) | ✅ 完整 | ⚠️ 受限 | ✅ | — |
| **Safari iOS 16+** | ⚠️ **受限** | ❌ | ⚠️ 受限 | **关键限制:模块大小** |
| Edge 90+ | ✅ 完整 | ✅ | ✅ | Chromium 内核 |
Safari iOS 的历史限制对 WebAssembly 应用影响深远:早期版本对 WebAssembly 模块大小设有硬性上限(约 50MB 解压后),超过此限制将导致应用无法加载 。虽然 iOS 16+ 有所放宽,但仍建议对 iOS 用户进行专项测试。
针对 Safari iOS 的大小限制,推荐策略:
mono.wasm 和 dotnet.wasm 的合并大小| 特性 | Debug 配置 | Release + AOT |
|---|---|---|
| 构建速度 | 快(秒级) | 慢(分钟级) |
| 调试支持 | 完整(Source Maps) | 受限 |
| 性能分析 | 准确 | 需考虑 AOT 影响 |
| 异常堆栈 | 完整符号 | 可能需符号化 |
Windows Defender 等反病毒软件可能误报 WebAssembly 构建产物,导致构建失败或运行时加载异常。缓解措施:
obj 和 bin 目录加入排除列表Skia 桌面端是 Uno Platform 中率先全面支持 .NET Native AOT 的目标类别,标志着框架向现代原生编译技术的战略迁移。.NET Native AOT 基于 CoreCLR 的 RyuJIT 编译器,在发布时执行全程序分析,生成完全自包含的原生可执行文件,无需任何 .NET 运行时安装。
与 Mono AOT 的关键差异:
| 特性 | Mono AOT | .NET Native AOT |
|---|---|---|
| 运行时依赖 | 需 Mono 运行时 | **完全自包含** |
| 包体积 | 较大(运行时包含) | **激进修剪,可达数 MB** |
| 启动速度 | 快 | **极快(无初始化开销)** |
| 动态特性支持 | 较宽松 | **严格限制** |
| 反编译保护 | 一般 | **强(原生代码)** |
Uno Platform 对 Native AOT 的支持始于 4.7 版本,最初针对 Skia+GTK 后端 。随着版本演进,支持范围扩展至所有 Skia 桌面目标(Linux、macOS、Windows)。
SkiaSharp 作为跨平台 2D 图形引擎,在 Native AOT 环境下需要特殊处理:
| 后端 | 平台 | 状态 | AOT 兼容性 | 备注 |
|---|---|---|---|---|
| **GTK3** | Linux, Windows, macOS | **稳定** | ✅ 完全支持 | 当前最成熟 |
| **GTK4** | Linux | 积极开发 | ✅ 完全支持 | Uno 6.0+,改进高 DPI |
| **GLFW** | 跨平台 | 实验性 | ✅ 支持 | 游戏/多媒体场景 |
| **X11(直接)** | Linux | 稳定 | ✅ 支持 | 嵌入式场景 |
| **FrameBuffer** | Linux 嵌入式 | 稳定 | ✅ 支持 | 无头设备 |
| **macOS Native** | macOS | 稳定 | ✅ 支持 | 原生 AppKit 集成 |
<PublishAot>true</PublishAot> 配置启用 Native AOT 的核心配置极为简洁:
<PropertyGroup>
<PublishAot>true</PublishAot>
<!-- 可选:单文件发布 -->
<PublishSingleFile>true</PublishSingleFile>
<!-- 可选:自包含 -->
<SelfContained>true</SelfContained>
</PropertyGroup>
对于同时包含 WebAssembly 等不支持 Native AOT 目标的项目,需要条件化配置以避免构建错误 :
<PropertyGroup Condition="'$(TargetFramework)' == 'net9.0-desktop'">
<PublishAot>true</PublishAot>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
关键注意事项:PublishAot 不能无条件应用于所有目标框架,WebAssembly(browser-wasm)等目标会报告 NETSDK1203 错误 。
推荐的生产部署配置:
# Linux x64
dotnet publish -c Release -r linux-x64 -p:PublishAot=true -p:PublishSingleFile=true
# macOS Apple Silicon
dotnet publish -c Release -r osx-arm64 -p:PublishAot=true -p:PublishSingleFile=true
# Windows x64
dotnet publish -c Release -r win-x64 -p:PublishAot=true -p:PublishSingleFile=true
生成的可执行文件包含所有依赖,无需目标机器预装 .NET 运行时。
-r linux-x64, -r osx-arm64, -r win-x64)| 运行时标识符 | 目标平台 | 说明 |
|---|---|---|
linux-x64 | Linux x86_64 | **主流服务器和桌面** |
linux-arm64 | Linux ARM64 | Raspberry Pi 4, ARM 服务器 |
osx-x64 | macOS Intel | 旧款 Mac |
osx-arm64 | macOS Apple Silicon | **M1/M2/M3 Mac** |
win-x64 | Windows x86_64 | **主流 Windows** |
win-arm64 | Windows ARM64 | Surface Pro X 等 |
重要限制:Native AOT 不支持跨平台编译,必须在目标平台或兼容的容器环境中执行发布 。
Native AOT 支持要求 GtkSharp 3.24.24.38 或更高版本 。Uno Platform 4.7+ 的模板已包含兼容版本,升级现有项目时需显式更新:
dotnet list package --include-transitive | grep GtkSharp
# 如需更新:dotnet add package GtkSharp --version 3.24.24.38
目标 Linux 系统需安装 GTK3 运行时:
# Ubuntu/Debian
sudo apt-get install libgtk-3-0 libgdk-pixbuf2.0-0 libfontconfig1
# Fedora
sudo dnf install gtk3
# Arch
sudo pacman -S gtk3
静态链接选项(实验性)可将 GTK 依赖打包,但增加体积约 20MB。
Windows 上 GTK3 运行时可通过 MSYS2 安装或随应用分发。Uno Platform 的打包工具支持自动包含必要的 DLL。
WPF(Windows Presentation Foundation)当前不支持 .NET Native AOT,核心障碍包括:
| 迁移路径 | 技术栈 | AOT 支持 | 工作量 | 推荐度 |
|---|---|---|---|---|
| **Skia 桌面** | SkiaSharp + GTK/GLFW | ✅ **完整 Native AOT** | 中等 | **⭐⭐⭐⭐⭐ 强烈推荐** |
| **WinUI 3(Windows App SDK)** | 原生 WinUI 3 | ⚠️ 部分(需评估) | 较高 | ⭐⭐⭐☆☆ |
| **Uno Platform WinUI 3 + Skia** | 跨平台 + 现代 Windows | ✅ **Skia 路径完整 AOT** | 中等 | **⭐⭐⭐⭐⭐ 推荐** |
Native AOT 的核心优势之一是消除 JIT 预热延迟。进一步优化杠杆:
Lazy<T> 和异步初始化x:Bind 模式| 配置 | 相对体积 | 说明 |
|---|---|---|
| 框架依赖 | 100% | 需 .NET 运行时 |
| 自包含 | 150% | 包含运行时 |
| 自包含 + AOT | 120% | 修剪后 |
| **自包含 + AOT + 单文件** | **110%** | **压缩后推荐配置** |
Uno Platform 6.0 的体积优化成果:空白应用包体积在 Windows 上减少 74%,iOS 上减少 21% 。
实验性静态链接减少部署依赖:
<PropertyGroup>
<StaticallyLinked>true</StaticallyLinked>
</PropertyGroup>
限制:某些系统库(如图形驱动相关)无法静态链接。
Native AOT 要求 P/Invoke 签名在编译时完全解析:
DllImport 路径[LibraryImport] 和源生成(.NET 7+)COM 互操作在 Native AOT 中受限:
dynamic 和 Type.GetTypeFromCLSIDComWrappers 源生成兼容模式修剪分析器标记的警告需处理:
// 不安全:可能被修剪
var props = typeof(MyType).GetProperties();
// 安全:显式保留
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class MyType { }
或配置修剪描述文件保留整个程序集或类型层次结构。
WinUI 3 作为 Windows 的现代原生 UI 框架,与 Windows App SDK 紧密集成。Uno Platform 提供两种 WinUI 3 目标实现:
| 特性 | WPF 实现(<6.0,已弃用) | Win32 实现(6.0+,推荐) |
|---|---|---|
| **Native AOT 支持** | ❌ **不支持** | ✅ **完整支持** |
| **IL 修剪** | 部分 | **完整** |
| 包体积(空白应用) | ~150MB | **~40MB(-74%)** |
| 启动性能 | 一般 | **优秀** |
| 构建时间 | 长 | **短(-35% AOT)** |
| WinUI 3 功能完整性 | 高 | 高 |
Win32 实现的完整 IL 修剪通过 <TrimMode>full</TrimMode> 和 <TrimmerRemoveSymbols>true</TrimmerRemoveSymbols> 启用,自动分析 XAML 绑定和依赖属性使用,安全移除未引用代码。
Uno Platform 6.0 的 WinUI 3 目标默认使用 Skia 渲染后端,配置与 Skia 桌面端一致:
<PropertyGroup>
<TargetFrameworks>net9.0-windows10.0.19041</TargetFrameworks>
<PublishAot>true</PublishAot>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
-p:PublishAot=true)dotnet publish -c Release -r win-x64 -p:PublishAot=true -p:PublishSingleFile=true -p:SelfContained=true
MSIX 是 Windows 应用的首选打包格式,与 Native AOT 协同:
dotnet publish -p:PublishAot=true -p:WindowsPackageType=MSIX
Uno Platform 的打包工具自动处理 MSIX 清单、资源打包和签名准备。
Uno Platform 6.0 的优化成果:空白应用包体积从 ~150MB(WPF + 自包含)降至 ~40MB(Win32 + Native AOT + 完整 IL 修剪),缩减 74% 。
关键技术杠杆:
Uno Platform 6.0 通过以下改进实现 AOT 构建时间 35% 提升 :
XAML 修剪配置:
<PropertyGroup>
<UnoXamlResourcesTrimming>true</UnoXamlResourcesTrimming>
<UnoXamlResourcesTrimmingVerbosity>Detailed</UnoXamlResourcesTrimmingVerbosity>
</PropertyGroup>
详细日志帮助识别未被修剪的 XAML 资源,指导进一步优化。
Native AOT 对 WinRT API 的调用需通过 CsWinRT 投影。限制包括:
as 运算符)可能失败,需使用显式接口实现CoreDispatcher/CoreWindow 替代方案WinUI 3 移除了 UWP 的 CoreDispatcher 和 CoreWindow API。Uno Platform 应用需迁移至:
DispatcherQueue:线程调度Microsoft.UI.Xaml.Window:窗口管理AppWindow:高级窗口控制第三方控件库的 Native AOT 兼容性需单独验证。Windows Community Toolkit 8.2+ 已正式支持 Native AOT,是兼容性良好的参考实现。评估维度:
DynamicallyAccessedMembers 标注现代 Uno Platform 项目采用 Single Project 结构,通过条件化 MSBuild 属性管理多平台 AOT 配置:
<Project Sdk="Uno.Sdk">
<PropertyGroup>
<TargetFrameworks>
net9.0-desktop;
net9.0-browserwasm;
net9.0-ios;
net9.0-android
</TargetFrameworks>
</PropertyGroup>
<!-- 共享 AOT 配置 -->
<PropertyGroup>
<PublishAot Condition="'$(TargetFramework)'!='net9.0-browserwasm'">true</PublishAot>
</PropertyGroup>
<!-- WebAssembly 特定 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net9.0-browserwasm'">
<WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
</PropertyGroup>
<!-- iOS 特定 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net9.0-ios'">
<MtouchUseLlvm>true</MtouchUseLlvm>
<UnoXamlTrimming>true</UnoXamlTrimming>
</PropertyGroup>
<!-- Android 特定 -->
<PropertyGroup Condition="'$(TargetFramework)'=='net9.0-android'">
<EnableLLVM>true</EnableLLVM>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
<AndroidEnableMarshalMethods>true</AndroidEnableMarshalMethods>
</PropertyGroup>
</Project>
使用 Choose/When 结构实现更复杂的条件逻辑:
<Choose>
<When Condition="'$(TargetFramework)'=='net9.0-desktop'">
<PropertyGroup>
<PublishAot>true</PublishAot>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
</When>
<When Condition="'$(TargetFramework)'=='net9.0-browserwasm'">
<PropertyGroup>
<WasmShellEnableJiterpreter>true</WasmShellEnableJiterpreter>
</PropertyGroup>
</When>
</Choose>
大型解决方案可采用 共享项目(Shared Project) 模式,将平台无关代码集中于 .shproj,平台特定配置分散于各头项目。
# .github/workflows/build.yml
name: Build and Publish
on:
push:
branches: [main]
jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
target: net9.0-desktop
rid: linux-x64
- os: macos-latest
target: net9.0-desktop
rid: osx-arm64
- os: windows-latest
target: net9.0-windows10.0.19041
rid: win-x64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore workloads
run: dotnet workload restore
- name: Build and publish
run: |
dotnet publish \
-f ${{ matrix.target }} \
-r ${{ matrix.rid }} \
-c Release \
-p:PublishAot=true \
-p:PublishSingleFile=true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.rid }}
path: bin/Release/${{ matrix.target }}/${{ matrix.rid }}/publish/
# azure-pipelines.yml
trigger:
- main
strategy:
matrix:
linux:
imageName: 'ubuntu-latest'
rid: 'linux-x64'
macos:
imageName: 'macos-latest'
rid: 'osx-arm64'
windows:
imageName: 'windows-latest'
rid: 'win-x64'
pool:
vmImage: $(imageName)
steps:
- task: UseDotNet@2
inputs:
version: '9.0.x'
- script: dotnet workload restore
displayName: 'Restore workloads'
- script: |
dotnet publish \
-f net9.0-desktop \
-r $(rid) \
-c Release \
-p:PublishAot=true
displayName: 'Build and publish'
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: 'bin/Release/net9.0-desktop/$(rid)/publish/'
artifactName: '$(rid)'
| 平台 | 最低配置 | 推荐配置 | 特殊要求 |
|---|---|---|---|
| Linux | 4 vCPU, 8GB RAM | 8 vCPU, 16GB RAM | GTK3 开发库 |
| macOS | Apple Silicon / Intel | Apple Silicon (M1+) | Xcode Command Line Tools |
| Windows | 4 vCPU, 8GB RAM | 8 vCPU, 16GB RAM | Visual Studio 2022 工作负载 |
WebAssembly AOT 的特殊需求:构建过程内存密集,建议 16GB+ RAM,或启用交换空间。
修剪警告(IL2xxx 系列)是 AOT 兼容性的关键指标:
| 警告代码 | 含义 | 处理方式 |
|---|---|---|
IL2026 | 成员使用 RequiresUnreferencedCode | 添加 [RequiresUnreferencedCode] 或重构 |
IL2045 | COM 互操作可能不兼容 | 使用 ComWrappers 源生成模式 |
IL2055 | 泛型类型参数未保留 | 添加 [DynamicallyAccessedMembers] |
IL2104 | 程序集未标记修剪兼容 | 确认库支持或配置保留 |
抑制非关键警告:
<ItemGroup>
<TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>
常见 AOT 运行时异常:
| 异常类型 | 典型原因 | 诊断方法 |
|---|---|---|
MissingMethodException | 修剪过度移除方法 | 检查 LinkerConfig.xml,添加保留规则 |
TypeLoadException | 泛型实例化失败 | 确认 [DynamicallyAccessedMembers] 标注 |
PlatformNotSupportedException | 动态代码生成尝试 | 重构为源生成器模式 |
DllNotFoundException | 原生库缺失或路径错误 | 验证 DllImport 路径,检查部署目录 |
原生依赖诊断流程:
ldd(Linux)、otool -L(macOS)或 Dependencies(Windows)检查可执行文件依赖.NET 9 及后续版本的 Native AOT 演进方向:
[LibraryImport] 的全面推广微软与 Uno Platform 社区的长期目标:统一 Mono 与 CoreCLR 运行时,最终形成单一的 .NET 运行时支持所有 AOT 场景。这一愿景的实现将:
| 平台/格式 | 状态 | AOT 适用性 | 关键挑战 |
|---|---|---|---|
| **Flatpak** | 社区实验 | ✅ Native AOT 兼容 | 运行时依赖打包 |
| **Snap** | 社区实验 | ✅ Native AOT 兼容 | 沙箱权限配置 |
| **嵌入式 Linux** | 积极开发 | ✅ Skia FrameBuffer 后端 | 资源受限优化 |
| **WebAssembly System Interface (WASI)** | 跟踪中 | ⚠️ 未来可能支持 | 标准演进中 |
| 特性维度 | iOS | Android | WebAssembly | Skia Desktop | WinUI 3 (Skia) |
|---|---|---|---|---|---|
| **AOT 技术栈** | Mono Full AOT | Mono AOT + LLVM | Mono AOT / Jiterpreter | .NET Native AOT | .NET Native AOT |
| **强制/可选** | **强制** | 可选 | 可选 | 可选 | 可选 |
| **推荐模式** | Full AOT | PG-AOT + LLVM | **PG-AOT + Jiterpreter** | Native AOT | Native AOT |
| **典型包体积增幅** | +200-400% | +20-60% | +20-50% | +10-30% | +10-30% |
| **启动时间优化** | 极快 | 快 | 中等 | **极快** | **极快** |
| **运行时性能** | 原生级 | 接近原生 | 接近原生(Jiterpreter) | **原生级** | **原生级** |
| **构建时间影响** | 长 | 中等 | 中等 | 中等 | 中等 |
| **关键版本要求** | Uno 4.0+ | Uno 5.0+, .NET 8+ | **Uno 5.5+, .NET 9+** | **Uno 4.7+, .NET 7+** | **Uno 6.0+, .NET 9+** |
| **主要限制** | 无动态代码 | NDK 依赖 | Safari 限制 | 无跨编译 | WinRT 边界 |
性能最优
▲
/ \
/ \
/ \
/ ◆ \ ← 理想平衡点(因场景而异)
/ PG-AOT \
/ + Jiterp \
/________________\
包体积最优 ◄─────────────► 编译时间最优
(解释器/ (增量构建/
激进修剪) 缓存重用)
选型决策树:
| 应用场景 | 目标平台 | 推荐配置 | 关键属性 |
|---|---|---|---|
| **企业级移动应用** | iOS + Android | iOS: Full AOT + Link SDK; Android: PG-AOT + LLVM + Marshal Methods | MtouchLink, AndroidEnableProfiledAot, EnableLLVM |
| **高性能游戏/图形** | iOS + Android + Desktop | Full AOT(移动); Native AOT(桌面); 共享渲染代码 | PublishAot, AndroidEnableProfiledAot=false |
| **跨平台 Web 应用** | WebAssembly | **PG-AOT + Jiterpreter** | WasmShellEnableAotProfile, WasmShellEnableJiterpreter |
| **桌面工具/实用程序** | Windows + macOS + Linux | **Native AOT + 单文件** | PublishAot, PublishSingleFile |
| **嵌入式/IoT 设备** | Linux (ARM) | Native AOT + FrameBuffer 后端 | PublishAot, Skia FrameBuffer |
| **现代 Windows 应用** | Windows 10/11 | **WinUI 3 + Skia/Win32 + Native AOT** | PublishAot, 避免 WPF 后端 |
还没有人回复