Native AOT deployment on iOS and Mac Catalyst

Native AOT deployment produces a .NET Multi-platform App UI (.NET MAUI) app on iOS and Mac Catalyst that's been ahead-of-time (AOT) compiled to native code. Native AOT performs static program analysis, full trimming of your app, which is aggressive in removing code that's not statically referenced, and ahead-of-time code generation.

Publishing and deploying a Native AOT app produces the following benefits:

  • Reduced app package size.
  • Faster startup time.
  • Faster build time.

Native AOT will introduce limitations on usage of certain aspects of the .NET runtime, and should only be used in scenarios where app size and performance are important. It'll require you to adapt your apps to Native AOT requirements, which means ensuring that they are fully trimming and AOT compatible. For more information about Native AOT limitations, see Native AOT limitations.

When Native AOT deployment is enabled, the build system analyzes your code, and all its dependencies, to verify if it's suitable for full trimming and AOT compilation. If incompatibilities are detected, trimming and AOT warnings are produced. A single trimming or AOT warning means that the app isn't compatible with Native AOT deployment, and that it might not work correctly. Therefore, when building an app for Native AOT deployment you should review and correct all trimming and AOT warnings. Failure to do this may result in exceptions at runtime since necessary code could have been removed. If you suppress the warnings the AOT deployed app must be thoroughly tested to verify that functionality hasn't changed from the untrimmed app. For more information, see Introduction to trim warnings and Introduction to AOT warnings.

Note

There may be cases where fixing trimming and AOT warnings isn't possible, such as when they occur for third-party libraries. In such cases, third-party libraries will need to be updated to become fully compatible.

Native AOT performance benefits

Publishing and deployment a Native AOT app produces an app that's typically up to 2.5x smaller, and an app that starts up typically up to 2x faster. However, the exact performance benefits are dependent upon multiple factors which include the platform being used, the device on which the app is running, and the app itself.

Important

The following charts show typical performance benefits of Native AOT deployment for a dotnet new maui app on iOS and Mac Catalyst. However, the exact data is hardware dependent and may change in future releases.

The following chart shows app package size for a dotnet new maui app on iOS and Mac Catalyst across different deployment models:

Chart showing app package size across different deployment models.

The preceding chart shows that, typically, Native AOT produces more than 2x smaller apps for both iOS and Mac Catalyst compared to the default deployment model.

The following chart shows average startup time, on specific hardware, for a dotnet new maui app on iOS and Mac Catalyst on Mono and Native AOT deployment:

Chart showing average app startup time on Mono and Native AOT.

The preceding chart shows that Native AOT typically has up to 2x faster startup times on iOS devices and 1.2x faster startup time on Mac Catalyst, compared to Mono deployment.

The following chart shows the average build time, on specific hardware, for a dotnet new maui app on iOS and Mac Catalyst across different deployment models:

Chart showing average app build time on Mono and Native AOT.

The preceding chart shows that typically Native AOT has up to 2.8x faster build times on iOS devices compared to the default deployment model. For Mac Catalyst, build times are comparable for arm64 single RID apps, but are slightly slower for universal apps when compared to Mono deployment.

Important

In many scenarios Native AOT will produce smaller and faster apps. However, in some scenarios Native AOT might not produce smaller and faster apps. Therefore, it's important to test and profile your app to determine the result of enabling Native AOT deployment.

Publish using Native AOT

The Native AOT deployment model is enabled with the $(PublishAot) build property, and the dotnet publish command. The following example shows how to modify a project file to enable Native AOT deployment on iOS and Mac Catalyst:

<PropertyGroup>
  <!-- enable trimming and AOT analyzers on all platforms -->
  <IsAotCompatible>true</IsAotCompatible>

  <!-- select platforms to use with NativeAOT -->
  <PublishAot Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">true</PublishAot>
  <PublishAot Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">true</PublishAot>
</PropertyGroup>

Setting the $(IsAotCompatible) build property to true, for all platforms, enables trimming and AOT analyzers. These analyzers help you identify code that's not compatible with trimming or AOT.

Conditionally setting $(PublishAot) to true, for iOS and Mac Catalyst, enables dynamic code usage analysis during build and Native AOT compilation during publish. Native AOT analysis includes all of the app's code and any libraries the app depends on.

Warning

The $(PublishAot) build property shouldn't be conditioned by build configuration. This is because trimming features switches are enabled or disabled based on the value of the $(PublishAot) build property, and the same features should be enabled or disabled in all build configurations so that your code behaves identically. For more information about trimming feature switches, see Trimming feature switches.

The only way to verify that a Native AOT app works correctly is to publish it using dotnet publish and verify that there are no trimming or AOT warnings produced by your code and its dependencies. In particular, dotnet build -t:Publish isn't equivalent to dotnet publish.

Use the following dotnet publish command to publish your app on iOS and Mac Catalyst using Native AOT deployment:

# iOS
dotnet publish -f net9.0-ios -r ios-arm64

# Mac Catalyst
dotnet publish -f net9.0-maccatalyst -r maccatalyst-arm64
dotnet publish -f net9.0-maccatalyst -r maccatalyst-x64

# Universal Mac Catalyst apps
# (when <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> is set in the project file)
dotnet publish -f net9.0-maccatalyst

Tip

Publish apps frequently to discover trimming or AOT issues early in the development lifecycle.

Native AOT limitations

Native AOT will introduce limitations on usage of certain aspects of the .NET runtime, and should only be used in scenarios where app size and performance are important. It'll require you to adapt your apps to Native AOT requirements, which means ensuring that they are fully trimming and AOT compatible, and this can require a lot of work. In addition to the .NET limitations of Native AOT deployment, Native AOT deployment for .NET MAUI has additional limitations.

Third-party libraries your apps depend on might not be AOT compatible. The only way to ensure that a library is trimming and AOT compatible is to publish your app using Native AOT deployment and the dotnet publish command, and see if the Native AOT compiler produces any warnings for the library. For information about making your own libraries AOT compatible, see How to make libraries compatible with native AOT.

Reflection and dynamic code

Native AOT deployment limits the use of reflection in your code and its dependencies, and it can become necessary to use annotations to help the Native AOT compiler understand reflection patterns. When the compiler encounters a reflection pattern it can't statically analyze, and hence can't build the app, it produces trim warnings. Native AOT also prevents you from using dynamic code in your app. For example, compiling System.Linq.Expressions won't work as expected, and it isn't possible to load and execute assemblies at runtime. When the compiler encounters a dynamic pattern it can't ahead-of-time compile, it will produce an AOT warning.

In .NET MAUI app this means that:

Important

The Mono interpreter isn't compatible with Native AOT deployment, and therefore the $(UseInterpreter) and $(MtouchInterpreter) MSBuild properties have no effect when using Native AOT. For more information about the Mono interpreter, see Mono interpreter on iOS and Mac Catalyst.

For more information about trim warnings, see Introduction to trim warnings. For more information about AOT warnings, see Introduction to AOT warnings.

Adapt an app to Native AOT deployment

Use the following checklist to help you adapt your app to Native AOT deployment requirements:

See also