-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
Investigate potential issues and limitations of NativeAOT with .NET MAUI iOS applications:
.NET MAUI template app
.NET MAUI Podcast app
Goals
- Document discovered findings and limitations
- Based on the results propose the follow-up work
- Measure performance of NativeAOT targeting iOS platforms, and compare results against MonoAOT, the measurements should include: the application size: disk size (SOD) and bundle size (.ipa), build and startup time
Preview 6
Our main focus for the initial releases is the application size.
Apps were built and measured using: https://github.com/xamarin/xamarin-macios/tree/release/8.0.1xx-preview6 release
.NET MAUI template app
Building a .NET MAUI iOS sample application dotnet new maui
gives the following results:
.NET MAUI ios app | Mono-p6 | NAOT-p6 | diff (%) |
---|---|---|---|
SOD (Mb) | 40,24 | 50,13 | 25% |
.ipa (Mb) | 14,68 | 16,59 | 13% |
Mono-p6
in the table represents results obtained with Mono .NET8 preview6
, while NAOT-p6
represents results obtained with NativeAOT .NET8 preview6
Identified issues that contribute to the size regression with NativeAOT are:
- Step1 - Exclude assemblies from NativeAOT app bundles macios#18532
- Step2 - NativeAOT: investigate if we want _AggressiveAttributeTrimming set for NativeAOT macios#18479
- Step3 - Respect IsDynamicCodeSupported in more places in Linq.Expressions #88539
- Step4 (TBD) - NativeAOT: Trimming and extensions compatibility - implementation macios#18584
Estimated savings
-
Estimated savings in app sizes by applying optimizations for NativeAOT from
Step1
toStep4
.NET MAUI ios app Mono-p6 NAOT-p6 Step1 Step2 Step3 Step4 SOD (Mb) 40,24 50,13 41,93 40,5 27,58 TBD .ipa (Mb) 14,68 16,59 13,43 12,85 10,23 TBD NOTE: Results for
StepN
mean that all the previous stepsStep1..N
have been implemented -
Estimated difference (%) in app sizes compared to
Mono-p6
by applying optimizations for NativeAOT fromStep1
toStep4
.NET MAUI ios app Mono-p6 NAOT-p6 Step1 Step2 Step3 Step4 diff SOD (%) NaN 24,56% 4,20% 0,64% -31,46% TBD diff .ipa (%) NaN 13,00% -8,53% -12,48% -30,32% TBD NOTE: Diffs in the table mean that if for example we implement
Step1
andStep2
, the .ipa size with NativeAOT will be12,48%
smaller compared to Mono
.NET MAUI Podcast app
Estimated savings
-
Preliminary data (only estimated for
Step3
improvements with NativeAOT):.NET MAUI ios app Mono-p6 Step3 diff (%) SOD (Mb) 62,67 43,59 -30,45% .ipa (Mb) 24,37 17,43 -28,47%
Preview 7
Apps were built and measured using: https://github.com/xamarin/xamarin-macios/tree/release/8.0.1xx-preview7 release. The results show that NativeAOT generates ~30%
smaller applications compared to Mono (as it has been estimated above).
.NET MAUI template app
MAUI ios app | Mono-p7 | NAOT-p7 | diff (%) |
---|---|---|---|
SOD (Mb) | 40,52 | 27,41 | -32,37% |
.ipa (Mb) | 14,82 | 10,14 | -31,56% |
.NET MAUI Podcast app
MAUI podcast app | Mono-p7 | NAOT-p7 | diff (%) |
---|---|---|---|
SOD (Mb) | 62,81 | 42,18 | -32,84% |
.ipa (Mb) | 24,46 | 16,85 | -31,10% |
Other findings
- Fix Infinite recursion when generated code wrongly dispatches explicit interface calls
- Objective-C interop and GC API support:
- Support static registrar with NativeAOT:
- Dynamic registrar with NativeAOT - [NOT A PROBLEM]
- We did not detect any need to support dynamic registrar with NativeAOT so far - especially because NativeAOT does not seem to be required for inner-dev loop experience. Nevertheless, bellow are listed findings when dynamic registrar is enabled for NativeAOT:
- When building the application with dynamic registrar, the application crashes when ObjC runtime tries to register
UIKit.UIGestureRecognizer+Callback`1
type while it is fetching its interface map againstFoundation.INSObjectProtocol
:
default 12:06:26.833235+0200 HelloMauiiOS *** Terminating app due to uncaught exception 'System.ArgumentException', reason: 'Interface not found. (System.ArgumentException) at Internal.Reflection.Execution.ExecutionEnvironmentImplementation.VerifyInterfaceIsImplemented(RuntimeTypeHandle, RuntimeTypeHandle) + 0x78 at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.GetInterfaceMap(Type) + 0xa8 at Registrar.SharedDynamic.PrepareInterfaceMethodMapping(Type) + 0x114 at Registrar.Registrar.RegisterTypeUnsafe(Type, List`1&) + 0x1fbc at Registrar.Registrar.RegisterType(Type, List`1&) + 0x44 at Registrar.DynamicRegistrar.Register(Type) + 0x18 at ObjCRuntime.Class.GetClassHandle(Type, Boolean, Boolean&) + 0x168 at Foundation.NSObject.AllocIfNeeded() + 0x40 at UIKit.UIPanGestureRecognizer..ctor(Action`1) + 0x40 at Microsoft.Maui.Controls.Platform.Compatibility.ShellFlyoutRenderer.Microsoft.Maui.Controls.Platform.Compatibility.IShellFlyoutRenderer.AttachFlyout(IShellContext context, UIViewController content) + 0xf8
GetInterfaceMap
does not seem to be supported with uninstantiated generic types in NativeAOT. Only the most mainstream cases seem to be supported which is being tracked here: Type.GetInterfaceMap doesn't work for all cases #89157
- When building the application with dynamic registrar, the application crashes when ObjC runtime tries to register
- We did not detect any need to support dynamic registrar with NativeAOT so far - especially because NativeAOT does not seem to be required for inner-dev loop experience. Nevertheless, bellow are listed findings when dynamic registrar is enabled for NativeAOT:
Metadata
Metadata
Assignees
Labels
Type
Projects
Status