Description
Description
In .NET 6/7 timeframe, we were able to make a few .NET MAUI assemblies trimmable:
Essentials
Compatibility
The remaining assemblies (see #1962) were not able to easily become trimmable due to some of the dynamic features of .NET MAUI.
As we've shipped the NativeAOT experiment for iOS in .NET 8, this makes trimming even more important:
- NativeAOT has to trim all assemblies, it has to do static analysis on all managed code.
- NativeAOT basically ignores if an assembly declares itself
IsTrimmable=true
, and trims everything. - Linker warnings become extremely important: NativeAOT apps aren't guaranteed to work unless there are 0 trimmer warnings
Current Trimming Behavior
For .NET MAUI apps running on Mono (iOS, Android, Catalyst), we default to TrimMode=partial
. This is the same as the "SDK-only" trimming mode that we got from the Xamarin days.
Current behavior is:
- Assemblies marked with
IsTrimmable=true
are trimmed- BCL types are trimmed
- Android APIs are trimmed (
Mono.Android.dll
) - iOS APIs are trimmed (
Microsoft.iOS.dll
)
We also suppress most trimmer warnings in this mode, as the warnings shown for .NET MAUI, Android assemblies, etc. are not currently actionable.
Thus, most user code and third-party libraries are not trimmed at all. We get a reasonable small application, with a lot of IL removed, but not all that is possible.
.NET 6/7/8 apps can opt into "full trimming" with the likelihood of running into runtime crashes. Few customers (if any) are using this today.
.NET Ecosystem Concerns
There are many third-party .NET libraries on NuGet, etc. that are not implemented with "trimmability" in mind. Existing .NET MAUI applications are likely using these libraries.
How would we get large adoption of NativeAOT, if we don't get existing customers to opt into this setting? We need to find out what libraries are problematic so library authors can react.
Trimmability for Everyone
I propose as part of the "trimmable" effort for .NET MAUI, that we also adopt full trimming for all platforms running on Mono: this includes Android, iOS, MacCatalyst. Existing customers will also get the benefit of smaller app sizes.
If WindowsAppSDK (by luck?) also works without issue, we can include Windows platforms as well. This issue appears to have been solved, so it might work: microsoft/CsWinRT#373
Goal for .NET 9
Project templates (dotnet new maui
, android
, ios
, etc.) will opt into:
<TrimMode>full</TrimMode>
When in this mode, we should make sure all trimmer warnings are visible for users to react to. Project templates should show 0 warnings.
Greenfield apps will have an easier time adopting full trimming, as they can react individually as NuGet packages are added, etc. The setting can also be disabled by simply removing a line from the .csproj
.
Existing projects can also "opt into" full trimming, and find out if it works for them.
(Public) API Changes
Problematic MAUI APIs include:
Dynamic XAML
grid.LoadFromXaml("<Grid></Grid>");
Bindings
new Binding("Some.Complex.PropertyPath.WithIndexersToo[0]", source);
The idea is we'd leave these APIs intact. The behavior in each case would be something like:
- Mono, TrimMode=Full: trimmer warning at build time. API "might work" if appropriate types are preserved.
- NativeAOT: trimmer warning at build time (we could consider an error), throws at runtime
Usage Scenarios
Up to a 50% reduction in .NET MAUI app size?
@ivanpovazan has some examples here.
Most of the size improvements were merely from opting into full-trimming. NativeAOT may also make apps smaller, but trimming is the major win for app size.
Backward Compatibility
Existing .NET MAUI apps should not see a change in behavior.
Difficulty
High