Claude
Skills
Sign in
Back

dotnet-maui-aot

Included with Lifetime
$97 forever

Optimizing MAUI for iOS/Catalyst. Native AOT pipeline, size/startup gains, library gaps, trimming.

General

What this skill does


# dotnet-maui-aot

Native AOT compilation for .NET MAUI on iOS and Mac Catalyst: compilation pipeline, publish profiles, up to 50% app size reduction and up to 50% startup improvement, library compatibility gaps, opt-out mechanisms, trimming interplay (RD.xml, source generators), and testing AOT builds on device.

**Version assumptions:** .NET 8.0+ baseline. Native AOT for MAUI is available on iOS and Mac Catalyst. Android uses a different compilation model (CoreCLR in .NET 11, Mono/AOT in .NET 8-10).

**Scope boundary:** This skill owns MAUI-specific Native AOT on iOS/Mac Catalyst -- the compilation pipeline, publish configuration, size/startup improvements, library compatibility for MAUI apps, and testing AOT builds. General Native AOT patterns are owned by [skill:dotnet-native-aot]; AOT architecture decisions by [skill:dotnet-aot-architecture].

**Out of scope:** MAUI development patterns (project structure, XAML, MVVM) -- see [skill:dotnet-maui-development]. MAUI testing -- see [skill:dotnet-maui-testing]. WASM AOT (Blazor/Uno) -- see [skill:dotnet-aot-wasm]. General AOT architecture -- see [skill:dotnet-native-aot].

Cross-references: [skill:dotnet-maui-development] for MAUI patterns, [skill:dotnet-maui-testing] for testing AOT builds, [skill:dotnet-native-aot] for general AOT patterns, [skill:dotnet-aot-wasm] for WASM AOT, [skill:dotnet-ui-chooser] for framework selection.

---

## iOS/Mac Catalyst AOT Compilation Pipeline

Native AOT on iOS and Mac Catalyst compiles .NET IL directly to native machine code at publish time, eliminating the need for a JIT compiler or IL interpreter at runtime. This produces a self-contained native binary that links against platform frameworks.

### How It Works

1. **IL compilation:** The .NET IL is compiled to native code by the NativeAOT compiler (ILC)
2. **Tree shaking:** Unused code is trimmed based on static analysis of reachable types and methods
3. **Native linking:** The generated native code is linked with iOS/Catalyst frameworks and the minimal .NET runtime
4. **App bundle:** The result is a standard `.app` bundle with a native executable (no IL assemblies shipped)

### Publish Configuration

```xml
<!-- Enable Native AOT for iOS/Mac Catalyst -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0-ios' Or
                          '$(TargetFramework)' == 'net8.0-maccatalyst'">
  <PublishAot>true</PublishAot>
  <!-- Optional: strip debug symbols for smaller binary -->
  <StripSymbols>true</StripSymbols>
</PropertyGroup>
```

```bash
# Publish with AOT for iOS
dotnet publish -f net8.0-ios -c Release -r ios-arm64

# Publish with AOT for Mac Catalyst
dotnet publish -f net8.0-maccatalyst -c Release -r maccatalyst-arm64

# Publish for iOS simulator (for AOT testing without device)
dotnet publish -f net8.0-ios -c Release -r iossimulator-arm64
```

### Entitlements and Provisioning

AOT builds require the same entitlements and provisioning profiles as regular iOS/Catalyst builds. No additional entitlements are needed for AOT specifically.

```xml
<!-- iOS entitlements (Entitlements.plist) -->
<!-- Standard entitlements; AOT does not require special entries -->
```

---

## Size Reduction

Native AOT can achieve **up to 50% app size reduction** compared to interpreter/JIT mode on iOS. The size improvement comes from:

- **Tree shaking:** Only reachable code is included in the final binary
- **No IL shipping:** The app bundle does not include .NET IL assemblies
- **No runtime JIT:** The JIT compiler and associated metadata are not packaged

### Typical Size Comparison

| Mode | Approximate Size | Notes |
|------|-----------------|-------|
| Interpreter (default .NET 8 iOS) | ~60-80 MB | Includes IL assemblies + interpreter |
| Native AOT | ~30-45 MB | Native binary only, no IL |
| Native AOT + StripSymbols | ~25-40 MB | Debug symbols stripped |

**Caveat:** Actual size reduction depends on app complexity, third-party library usage, and how much code is reachable after trimming. Libraries that use heavy reflection may prevent aggressive trimming and reduce size gains.

---

## Startup Improvement

Native AOT provides **up to 50% faster cold startup** on iOS and Mac Catalyst. The startup improvement comes from:

- **No JIT warmup:** Code is already native; no compilation at app launch
- **No IL loading:** No need to load and parse .NET assemblies
- **Reduced memory pressure:** Smaller working set during startup

### Measuring Startup

```csharp
// Instrument startup timing
public partial class App : Application
{
    private static readonly long StartTicks = Stopwatch.GetTimestamp();

    public App()
    {
        InitializeComponent();
        MainPage = new AppShell();

        var elapsed = Stopwatch.GetElapsedTime(StartTicks);
        System.Diagnostics.Debug.WriteLine(
            $"App startup: {elapsed.TotalMilliseconds:F0}ms");
    }
}
```

```bash
# Use Xcode Instruments for precise startup measurement
# Time Profiler template → measure "pre-main" + "post-main" time
# Compare AOT vs non-AOT builds on the same device
```

---

## Library Compatibility

Many .NET libraries are not fully AOT-compatible. Common compatibility issues stem from:

- **Reflection:** Runtime type inspection, `Type.GetType()`, `Activator.CreateInstance()`
- **Dynamic code generation:** `System.Reflection.Emit`, `System.Linq.Expressions.Compile()`
- **Serialization without source generators:** JSON/XML serializers that use reflection

### Compatibility Matrix

| Library / Feature | AOT Status | Workaround |
|------------------|------------|------------|
| System.Text.Json (source gen) | Compatible | Use `[JsonSerializable]` context |
| System.Text.Json (reflection) | Breaks | Switch to source generators |
| CommunityToolkit.Mvvm | Compatible | Source-gen based, AOT-safe |
| Entity Framework Core | Partial | Precompiled queries; no dynamic LINQ |
| Newtonsoft.Json | Breaks | Migrate to System.Text.Json with source gen |
| AutoMapper | Breaks | Use Mapperly (source gen) |
| MediatR | Partial | Register handlers explicitly, avoid assembly scanning |
| HttpClient | Compatible | Standard usage works |
| MAUI Essentials | Compatible | Platform APIs are AOT-safe |
| SQLite-net | Compatible | Uses P/Invoke, AOT-safe |
| Refit | Breaks | Use Refit 7+ (includes source generator; enable with `[GenerateRefitClient]`) |
| FluentValidation | Partial | Avoid runtime expression compilation |

### Detecting Incompatible Code

```xml
<!-- Enable AOT analysis warnings during development -->
<PropertyGroup>
  <EnableAotAnalyzer>true</EnableAotAnalyzer>
  <!-- Also enable trim analyzer (AOT requires trimming) -->
  <EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
```

AOT analysis produces warnings like `IL3050` (RequiresDynamicCode) and `IL2026` (RequiresUnreferencedCode). Address these before publishing with AOT.

---

## Opt-Out Mechanisms

### Disabling AOT Entirely

```xml
<!-- Disable Native AOT (use interpreter/JIT mode) -->
<PropertyGroup>
  <PublishAot>false</PublishAot>
</PropertyGroup>
```

### Per-Assembly Trimming Overrides

When a specific library is not AOT-compatible, you can preserve it from trimming while still using AOT for the rest of the app:

```xml
<!-- Preserve a specific assembly from trimming -->
<ItemGroup>
  <TrimmerRootAssembly Include="IncompatibleLibrary" />
</ItemGroup>
```

### Opt-Out of .NET 11 Defaults

.NET 11 introduces new defaults that interact with AOT:

```xml
<!-- Revert XAML source gen (use legacy XAMLC) -->
<PropertyGroup>
  <MauiXamlInflator>XamlC</MauiXamlInflator>
</PropertyGroup>

<!-- Revert to Mono runtime on Android (not related to iOS AOT,
     but relevant for the overall MAUI AOT story) -->
<PropertyGroup>
  <UseMonoRuntime>true</UseMonoRuntime>
</PropertyGroup>
```

---

## Trimming Interplay

Native AOT requires trimming. When `PublishAot` is true, trimming is automatically enabled. Understanding trimming configuration is essential for a successful AOT build.

### ILLink Desc
Files: 1
Size: 14.6 KB
Complexity: 17/100
Category: General

Related in General