From 70f7f30284cf6821a0299e046e17688ce6d3bb44 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 30 Mar 2026 16:55:43 -0700 Subject: [PATCH 01/24] [illink] Move FixLegacyResourceDesignerStep to post-trim pipeline Migrate FixLegacyResourceDesignerStep out of the ILLink trimmer process and into PostTrimmingPipeline, continuing the work in #10842 to remove custom ILLink steps. The step now runs after ILLink via a thin wrapper (PostTrimmingFixLegacyResourceDesignerStep) that calls ProcessAssemblyDesigner() directly, matching the former ILLink behavior. - Remove all #if ILLINK conditionals from FixLegacyResourceDesignerStep, LinkDesignerBase, and BaseStep - Remove FixLegacyResourceDesignerStep and LinkDesignerBase from the ILLink project (no longer compiled as a trimmer step) - Add UseDesignerAssembly property to PostTrimmingPipeline task - Wire AndroidUseDesignerAssembly through targets to PostTrimmingPipeline - Remove _TrimmerCustomSteps entry for FixLegacyResourceDesignerStep --- .../Microsoft.Android.Sdk.ILLink.csproj | 2 -- .../Linker/External/Linker.Steps/BaseStep.cs | 4 --- .../FixLegacyResourceDesignerStep.cs | 19 +---------- .../MonoDroid.Tuner/LinkDesignerBase.cs | 20 ++--------- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 9 ++--- .../Tasks/PostTrimmingPipeline.cs | 33 +++++++++++++++++++ .../Xamarin.Android.Build.Tasks.csproj | 2 +- 7 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj index 26d2067d1fc..5a8cef363e4 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -17,8 +17,6 @@ - - diff --git a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs index c1aa1ded94a..a3a5bb11066 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/External/Linker.Steps/BaseStep.cs @@ -89,11 +89,7 @@ public virtual void LogMessage (string message) public virtual void LogError (int code, string message) { -#if ILLINK - Context.LogMessage (MessageContainer.CreateCustomErrorMessage (message, code, origin: new MessageOrigin ())); -#else // !ILLINK Context.LogError ($"XA{code}", message); -#endif // !ILLINK } } } diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs index 7606f022e7a..7028aea33e0 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FixLegacyResourceDesignerStep.cs @@ -14,18 +14,11 @@ using Mono.Linker.Steps; using Mono.Tuner; -#if ILLINK -using Resources = Microsoft.Android.Sdk.ILLink.Properties.Resources; -#else // !ILLINK using Resources = Xamarin.Android.Tasks.Properties.Resources; -#endif // ILLINK namespace MonoDroid.Tuner { - public class FixLegacyResourceDesignerStep : LinkDesignerBase -#if !ILLINK - , Xamarin.Android.Tasks.IAssemblyModifierPipelineStep -#endif // !ILLINK + public class FixLegacyResourceDesignerStep : LinkDesignerBase, Xamarin.Android.Tasks.IAssemblyModifierPipelineStep { internal const string DesignerAssemblyName = "_Microsoft.Android.Resource.Designer"; internal const string DesignerAssemblyNamespace = "_Microsoft.Android.Resource.Designer"; @@ -36,14 +29,6 @@ public class FixLegacyResourceDesignerStep : LinkDesignerBase Dictionary lookup; Dictionary lookupCaseInsensitive; - protected override void EndProcess () - { - if (designerAssembly != null) { - LogMessage ($" Setting Action on {designerAssembly.Name} to Link."); - Annotations.SetAction (designerAssembly, AssemblyAction.Link); - } - } - protected override void LoadDesigner () { if (designerLoaded) @@ -72,7 +57,6 @@ protected override void LoadDesigner () } } -#if !ILLINK public void ProcessAssembly (AssemblyDefinition assembly, Xamarin.Android.Tasks.StepContext context) { // Only run this step on non-main user Android assemblies @@ -81,7 +65,6 @@ public void ProcessAssembly (AssemblyDefinition assembly, Xamarin.Android.Tasks. context.IsAssemblyModified |= ProcessAssemblyDesigner (assembly); } -#endif // !ILLINK internal override bool ProcessAssemblyDesigner (AssemblyDefinition assembly) { diff --git a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs index 5f7f7fc1f74..6e50b10d7d7 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs +++ b/src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/LinkDesignerBase.cs @@ -4,16 +4,12 @@ using Mono.Linker; using Mono.Linker.Steps; using System; -using System.Linq; using Xamarin.Android.Tasks; using System.Collections.Generic; using System.Globalization; using Mono.Cecil.Cil; using System.Text.RegularExpressions; using Mono.Collections.Generic; -#if ILLINK -using Microsoft.Android.Sdk.ILLink; -#endif namespace MonoDroid.Tuner { @@ -21,26 +17,14 @@ public abstract class LinkDesignerBase : BaseStep { protected IMetadataResolver Cache => Context; - public -#if !ILLINK - override -#endif - void LogMessage (string message) + public override void LogMessage (string message) { Context.LogMessage (message); } - public -#if !ILLINK - override -#endif - void LogError (int code, string error) + public override void LogError (int code, string error) { -#if ILLINK - Context.LogMessage (MessageContainer.CreateCustomErrorMessage (error, code, origin: new MessageOrigin ())); -#else // !ILLINK Context.LogError ($"XA{code}", error); -#endif // !ILLINK } public virtual AssemblyDefinition Resolve (AssemblyNameReference name) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 9b8870a8295..da747461e70 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -198,12 +198,6 @@ <_TrimmerCustomSteps Include="$(_AndroidLinkerCustomStepAssembly)" Type="MonoDroid.Tuner.FixAbstractMethodsStep" /> - <_TrimmerCustomSteps - Condition=" '$(AndroidUseDesignerAssembly)' == 'true' " - Include="$(_AndroidLinkerCustomStepAssembly)" - BeforeStep="MarkStep" - Type="MonoDroid.Tuner.FixLegacyResourceDesignerStep" - /> <_TrimmerCustomSteps Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' " Include="$(_AndroidLinkerCustomStepAssembly)" @@ -248,7 +242,8 @@ Assemblies="@(_PostTrimmingAssembly)" AddKeepAlives="$(AndroidAddKeepAlives)" AndroidLinkResources="$(AndroidLinkResources)" - Deterministic="$(Deterministic)" /> + Deterministic="$(Deterministic)" + UseDesignerAssembly="$(AndroidUseDesignerAssembly)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index 56fb01b6485..645b4fe4489 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -6,6 +6,7 @@ using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Mono.Cecil; +using Mono.Linker; using MonoDroid.Tuner; namespace Xamarin.Android.Tasks; @@ -34,6 +35,8 @@ public class PostTrimmingPipeline : AndroidTask public bool Deterministic { get; set; } + public bool UseDesignerAssembly { get; set; } + public override bool RunTask () { using var resolver = new DirectoryAssemblyResolver ( @@ -70,6 +73,15 @@ public override bool RunTask () }, (msg) => Log.LogDebugMessage (msg))); } + if (UseDesignerAssembly) { + // Create an MSBuildLinkContext so FixLegacyResourceDesignerStep can resolve assemblies + // and log messages. The resolver is owned by the outer 'using' block, so we intentionally + // do not dispose this context (LinkContext.Dispose would double-dispose the resolver). + var linkContext = new MSBuildLinkContext (resolver, Log); + var fixLegacyStep = new FixLegacyResourceDesignerStep (); + fixLegacyStep.Initialize (linkContext); + steps.Add (new PostTrimmingFixLegacyResourceDesignerStep (fixLegacyStep)); + } if (AndroidLinkResources) { var allAssemblies = new List (Assemblies.Length); foreach (var item in Assemblies) { @@ -96,3 +108,24 @@ public override bool RunTask () return !Log.HasLoggedErrors; } } + +/// +/// Thin wrapper around for the post-trimming pipeline. +/// Calls directly, matching the +/// behavior of the former ILLink path which processed all assemblies without StepContext flag filtering. +/// Assemblies without a resource designer are skipped internally by ProcessAssemblyDesigner. +/// +class PostTrimmingFixLegacyResourceDesignerStep : IAssemblyModifierPipelineStep +{ + readonly FixLegacyResourceDesignerStep _inner; + + public PostTrimmingFixLegacyResourceDesignerStep (FixLegacyResourceDesignerStep inner) + { + _inner = inner; + } + + public void ProcessAssembly (AssemblyDefinition assembly, StepContext context) + { + context.IsAssemblyModified |= _inner.ProcessAssemblyDesigner (assembly); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index a0ed0a47ead..843e4879257 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -45,7 +45,7 @@ - + From 77de75d8945d558a96f0aad77a47244abe3920e1 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 1 Apr 2026 16:18:54 -0700 Subject: [PATCH 02/24] [targets] Fix NativeAOT designer assembly trimming In NativeAOT builds, _AddResourceDesignerToPublishFiles ran after _ComputeManagedAssemblyToLink, so the designer assembly was not in ManagedAssemblyToLink. ILLink skipped the designer assembly entirely and did not rewrite its netstandard references. Fix by adding _AddResourceDesignerToPublishFiles to _PrepareLinking's DependsOnTargets, so the designer is passed to ILLink. --- .../targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index da747461e70..3d9d9713433 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -160,7 +160,7 @@ + DependsOnTargets="GetReferenceAssemblyPaths;_CreatePropertiesCache;_AddResourceDesignerToPublishFiles"> true <_ExtraTrimmerArgs Condition=" '$(_EnableSerializationDiscovery)' != 'false' ">--enable-serialization-discovery $(_ExtraTrimmerArgs) From f0059fd75f820eedb792e67e0376b35c90421b46 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 2 Apr 2026 09:48:30 -0700 Subject: [PATCH 03/24] Fix merge conflict: remove FixAbstractMethodsStep from ILLink csproj FixAbstractMethodsStep was moved from ILLink to the post-trim pipeline on main (7ae24aab1). The merge conflict resolution incorrectly kept the Compile include, but the file now uses types not available in the ILLink project (IAssemblyModifierPipelineStep, StepContext, Properties.Resources). --- .../Microsoft.Android.Sdk.ILLink.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj index 5a8cef363e4..6c4368fd7d2 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -16,7 +16,6 @@ - From 64d4ed1f29be377559c1d4e9c5771e40d7a6a7d2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 2 Apr 2026 15:21:08 -0700 Subject: [PATCH 04/24] Root designer assembly to prevent ILLink from trimming resource properties FixLegacyResourceDesignerStep now runs in PostTrimmingPipeline (after ILLink) instead of as an ILLink custom step. Previously, the step ran before MarkStep and rewrote library assemblies to reference designer properties, which caused MarkStep to preserve them. Now that the rewriting happens after ILLink, we must root the designer assembly so all resource properties survive trimming. Add TrimmerRootAssembly for the designer in _AddResourceDesignerToPublishFiles. This keeps IsTrimmable=true (action=link) so ILLink still rewrites the netstandard assembly reference, but roots all types so nothing is trimmed. An alternative approach would be to run FixLegacyResourceDesignerStep before ILLink instead of after. That would allow ILLink to trim unused resource properties from the designer (since the rewritten references would already be in place for MarkStep), but it would also process resource references in assemblies that ILLink may later remove entirely. --- .../Android/Xamarin.Android.Resource.Designer.targets | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index 5c154d9e05c..a8a666ab598 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -226,6 +226,10 @@ Copyright (C) 2016 Xamarin. All rights reserved. In additon we MUST set the `PostprocessAssembly` metadata to `true` so that the file is processed by the ILLink step. If we do not do this then the reference to `netstandard.dll` is not replaced with `System.Private.CoreLib` and the app crashes. + + We also add a TrimmerRootAssembly entry to prevent ILLink from trimming the designer's + resource properties. FixLegacyResourceDesignerStep now runs after ILLink and needs + all properties to be present when rewriting library assemblies. --> true true + + From 924649e83b7f0759734a8443def7453c065186dc Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 2 Apr 2026 17:07:16 -0700 Subject: [PATCH 05/24] Use TrimmerRootDescriptor instead of TrimmerRootAssembly for designer assembly TrimmerRootAssembly (-a flag) makes the designer an entry point, which causes ILLink to retain netstandard.dll as a dependency, leaking it into the APK (+19KB). TrimmerRootDescriptor (-x flag) preserves all designer types/members without making it an entry point, avoiding the regression. --- .../Xamarin.Android.Resource.Designer.targets | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index a8a666ab598..d847c57568a 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -227,14 +227,24 @@ Copyright (C) 2016 Xamarin. All rights reserved. is processed by the ILLink step. If we do not do this then the reference to `netstandard.dll` is not replaced with `System.Private.CoreLib` and the app crashes. - We also add a TrimmerRootAssembly entry to prevent ILLink from trimming the designer's - resource properties. FixLegacyResourceDesignerStep now runs after ILLink and needs - all properties to be present when rewriting library assemblies. + We use a TrimmerRootDescriptor (not TrimmerRootAssembly) to prevent ILLink from + trimming the designer's resource properties. FixLegacyResourceDesignerStep runs + after ILLink and needs all properties present when rewriting library assemblies. + A descriptor (-x) preserves types without making the assembly an entry point, + which avoids pulling netstandard.dll into the output. --> + + <_DesignerLinkerDescriptor>$(IntermediateOutputPath)_Microsoft.Android.Resource.Designer.xml + + $(_DesignerAssemblyName).dll @@ -242,9 +252,11 @@ Copyright (C) 2016 Xamarin. All rights reserved. true true - - + + + From 8be3817205b840b703ff331a70e063bd0d0dc26c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 3 Apr 2026 09:34:23 -0700 Subject: [PATCH 06/24] Update SkiaSharp test to expect XA8000 instead of IL8000 for release builds FixLegacyResourceDesignerStep now runs in PostTrimmingPipeline (MSBuild task) instead of inside ILLink, so the error code is always XA8000 regardless of build configuration. --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 04e52ee9839..3edda4515c9 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1423,7 +1423,7 @@ private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) // TODO: fix for NativeAOT if (!addResource && runtime != AndroidRuntime.NativeAOT) { Assert.IsFalse (b.Build (app, doNotCleanupOnUpdate: true), $"Build of {app.ProjectName} should have failed."); - Assert.IsTrue (b.LastBuildOutput.ContainsText (isRelease ? "IL8000" : "XA8000")); + Assert.IsTrue (b.LastBuildOutput.ContainsText ("XA8000")); Assert.IsTrue (b.LastBuildOutput.ContainsText ("@styleable/SKCanvasView"), "Expected '@styleable/SKCanvasView' in build output."); Assert.IsTrue (b.LastBuildOutput.ContainsText ("@styleable/SKCanvasView_ignorePixelScaling"), "Expected '@styleable/SKCanvasView_ignorePixelScaling' in build output."); return; From 83a8f64c91f795a6c385e68c9b48cccb2083ee6a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 6 Apr 2026 11:23:56 -0700 Subject: [PATCH 07/24] Fix incremental build: use WriteOnlyWhenDifferent for linker descriptor WriteLinesToFile was regenerating the TrimmerRootDescriptor XML on every build, changing its timestamp and causing ILLink to re-run on incremental builds. Adding WriteOnlyWhenDifferent preserves the timestamp when the content hasn't changed. --- .../Xamarin/Android/Xamarin.Android.Resource.Designer.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index d847c57568a..f9ff732238f 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -243,6 +243,7 @@ Copyright (C) 2016 Xamarin. All rights reserved. From 6e870ef4cc111ef30b0582e2eb02779e0d87ba49 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 6 Apr 2026 11:24:16 -0700 Subject: [PATCH 08/24] Add TODO to simplify TrimmerRootDescriptor once dotnet/runtime#126518 is fixed --- .../Android/Xamarin.Android.Resource.Designer.targets | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index f9ff732238f..7105bf0286c 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -232,6 +232,10 @@ Copyright (C) 2016 Xamarin. All rights reserved. after ILLink and needs all properties present when rewriting library assemblies. A descriptor (-x) preserves types without making the assembly an entry point, which avoids pulling netstandard.dll into the output. + See https://github.com/dotnet/runtime/issues/126518 + + TODO: Once dotnet/runtime#126518 is fixed and flows to dotnet/android, + simplify this to use TrimmerRootAssembly instead of the XML descriptor. --> + assembly an entry point, which would pull netstandard.dll into the output. + See https://github.com/dotnet/runtime/issues/126518 --> From 4c4c091f753555c04e352f4b56399f448fc0cabc Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 10:38:45 -0700 Subject: [PATCH 09/24] Move FixLegacyResourceDesignerStep to run before ILLink trimming Run FixLegacyResourceDesignerStep *before* ILLink instead of after it, so the trimmer sees the rewritten IL (call instructions to designer property getters) and can freely trim unused designer types. This removes the need to root the entire designer assembly via a TrimmerRootDescriptor during trimming, eliminating the APK size regression. --- .../Xamarin.Android.Resource.Designer.targets | 28 ++------- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 22 ++++++- .../Tasks/PostTrimmingPipeline.cs | 33 ---------- .../Tasks/PreTrimmingFixLegacyDesigner.cs | 61 +++++++++++++++++++ 4 files changed, 85 insertions(+), 59 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index 7105bf0286c..e19d986acda 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -227,29 +227,15 @@ Copyright (C) 2016 Xamarin. All rights reserved. is processed by the ILLink step. If we do not do this then the reference to `netstandard.dll` is not replaced with `System.Private.CoreLib` and the app crashes. - We use a TrimmerRootDescriptor (not TrimmerRootAssembly) to prevent ILLink from - trimming the designer's resource properties. FixLegacyResourceDesignerStep runs - after ILLink and needs all properties present when rewriting library assemblies. - A descriptor (-x) preserves types without making the assembly an entry point, - which avoids pulling netstandard.dll into the output. - See https://github.com/dotnet/runtime/issues/126518 - - TODO: Once dotnet/runtime#126518 is fixed and flows to dotnet/android, - simplify this to use TrimmerRootAssembly instead of the XML descriptor. + No TrimmerRootDescriptor is needed: PreTrimmingFixLegacyDesigner rewrites library + assemblies *before* ILLink, replacing designer field loads with calls to the designer + assembly's property getters. ILLink then naturally preserves only the referenced + properties through its mark step, allowing everything else to be trimmed. --> - - <_DesignerLinkerDescriptor>$(IntermediateOutputPath)_Microsoft.Android.Resource.Designer.xml - - $(_DesignerAssemblyName).dll @@ -257,12 +243,6 @@ Copyright (C) 2016 Xamarin. All rights reserved. true true - - - diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 0c2a2b21f28..7cbc906441f 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -8,6 +8,7 @@ + <_RemoveRegisterFlag>$(MonoAndroidIntermediateAssemblyDir)shrunk\shrunk.flag @@ -216,6 +217,24 @@ + + + + <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> + + + + + Deterministic="$(Deterministic)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index df2f1d48b53..fa3c3385737 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -6,7 +6,6 @@ using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Mono.Cecil; -using Mono.Linker; using MonoDroid.Tuner; namespace Xamarin.Android.Tasks; @@ -35,8 +34,6 @@ public class PostTrimmingPipeline : AndroidTask public bool Deterministic { get; set; } - public bool UseDesignerAssembly { get; set; } - public override bool RunTask () { using var resolver = new DirectoryAssemblyResolver ( @@ -103,15 +100,6 @@ public override bool RunTask () }, (msg) => Log.LogDebugMessage (msg))); } - if (UseDesignerAssembly) { - // Create an MSBuildLinkContext so FixLegacyResourceDesignerStep can resolve assemblies - // and log messages. The resolver is owned by the outer 'using' block, so we intentionally - // do not dispose this context (LinkContext.Dispose would double-dispose the resolver). - var linkContext = new MSBuildLinkContext (resolver, Log); - var fixLegacyStep = new FixLegacyResourceDesignerStep (); - fixLegacyStep.Initialize (linkContext); - steps.Add (new PostTrimmingFixLegacyResourceDesignerStep (fixLegacyStep)); - } foreach (var (item, assembly) in loadedAssemblies) { var context = new StepContext (item, item); @@ -130,24 +118,3 @@ public override bool RunTask () return !Log.HasLoggedErrors; } } - -/// -/// Thin wrapper around for the post-trimming pipeline. -/// Calls directly, matching the -/// behavior of the former ILLink path which processed all assemblies without StepContext flag filtering. -/// Assemblies without a resource designer are skipped internally by ProcessAssemblyDesigner. -/// -class PostTrimmingFixLegacyResourceDesignerStep : IAssemblyModifierPipelineStep -{ - readonly FixLegacyResourceDesignerStep _inner; - - public PostTrimmingFixLegacyResourceDesignerStep (FixLegacyResourceDesignerStep inner) - { - _inner = inner; - } - - public void ProcessAssembly (AssemblyDefinition assembly, StepContext context) - { - context.IsAssemblyModified |= _inner.ProcessAssemblyDesigner (assembly); - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs new file mode 100644 index 00000000000..a1de7d23132 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs @@ -0,0 +1,61 @@ +#nullable enable + +using System.Collections.Generic; +using System.IO; +using Java.Interop.Tools.Cecil; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Mono.Cecil; +using MonoDroid.Tuner; + +namespace Xamarin.Android.Tasks; + +/// +/// Runs on assemblies that are about to be +/// trimmed by ILLink. This rewrites library assemblies so their resource field accesses +/// (ldsfld) become calls to the designer assembly's property getters. +/// +/// Running this *before* ILLink means the trimmer sees the rewritten IL and can freely +/// trim unused designer types/fields. This avoids the need to root the entire designer +/// assembly during trimming (which causes an APK size regression). +/// +public class PreTrimmingFixLegacyDesigner : AndroidTask +{ + public override string TaskPrefix => "PTD"; + + [Required] + public ITaskItem [] Assemblies { get; set; } = []; + + public bool Deterministic { get; set; } + + public override bool RunTask () + { + using var resolver = new DirectoryAssemblyResolver ( + this.CreateTaskLogger (), loadDebugSymbols: true, + loadReaderParameters: new ReaderParameters { ReadWrite = true }); + + foreach (var assembly in Assemblies) { + var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? ""); + if (!resolver.SearchDirectories.Contains (dir)) { + resolver.SearchDirectories.Add (dir); + } + } + + var linkContext = new MSBuildLinkContext (resolver, Log); + var fixLegacyStep = new FixLegacyResourceDesignerStep (); + fixLegacyStep.Initialize (linkContext); + + foreach (var item in Assemblies) { + var assembly = resolver.GetAssembly (item.ItemSpec); + if (fixLegacyStep.ProcessAssemblyDesigner (assembly)) { + Log.LogDebugMessage ($" Writing modified assembly: {item.ItemSpec}"); + assembly.Write (new WriterParameters { + WriteSymbols = assembly.MainModule.HasSymbols, + DeterministicMvid = Deterministic, + }); + } + } + + return !Log.HasLoggedErrors; + } +} From 5e3ba1fca05fa582db9990abac5748ac75f2b50b Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 10:25:09 -0700 Subject: [PATCH 10/24] Fix SkiaSharp NativeAOT test to expect XA8000 build failure FixLegacyResourceDesignerStep now runs in PostTrimmingPipeline for all runtimes including NativeAOT, so the missing @styleable/SKCanvasView resources correctly produce XA8000 errors. Remove the NativeAOT exclusion from the addResource=False path. --- tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 3edda4515c9..8a8194f3cfe 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -1420,8 +1420,7 @@ private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) using (var b = CreateApkBuilder (Path.Combine ("temp", TestName, app.ProjectName))) { b.BuildLogFile = "build1.log"; b.ThrowOnBuildFailure = false; - // TODO: fix for NativeAOT - if (!addResource && runtime != AndroidRuntime.NativeAOT) { + if (!addResource) { Assert.IsFalse (b.Build (app, doNotCleanupOnUpdate: true), $"Build of {app.ProjectName} should have failed."); Assert.IsTrue (b.LastBuildOutput.ContainsText ("XA8000")); Assert.IsTrue (b.LastBuildOutput.ContainsText ("@styleable/SKCanvasView"), "Expected '@styleable/SKCanvasView' in build output."); From 432b1b2f9526b53dca4bec5ab36ca99cf2b8b88d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 12:45:17 -0700 Subject: [PATCH 11/24] Filter framework/main assemblies in PreTrimmingFixLegacyDesigner for efficiency --- .../Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 1 + .../Tasks/PreTrimmingFixLegacyDesigner.cs | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 7cbc906441f..85b80ea4061 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -232,6 +232,7 @@ diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs index a1de7d23132..9c49fc6274b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs @@ -1,6 +1,5 @@ #nullable enable -using System.Collections.Generic; using System.IO; using Java.Interop.Tools.Cecil; using Microsoft.Android.Build.Tasks; @@ -26,6 +25,9 @@ public class PreTrimmingFixLegacyDesigner : AndroidTask [Required] public ITaskItem [] Assemblies { get; set; } = []; + [Required] + public string TargetName { get; set; } = ""; + public bool Deterministic { get; set; } public override bool RunTask () @@ -46,6 +48,15 @@ public override bool RunTask () fixLegacyStep.Initialize (linkContext); foreach (var item in Assemblies) { + // Match the filtering in FixLegacyResourceDesignerStep.ProcessAssembly: + // skip the main assembly and framework/BCL assemblies. + if (Path.GetFileNameWithoutExtension (item.ItemSpec) == TargetName) { + continue; + } + if (MonoAndroidHelper.IsFrameworkAssembly (item)) { + continue; + } + var assembly = resolver.GetAssembly (item.ItemSpec); if (fixLegacyStep.ProcessAssemblyDesigner (assembly)) { Log.LogDebugMessage ($" Writing modified assembly: {item.ItemSpec}"); From 7b7261187275f662e4eeb3db28d22fcd0b551fe6 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 10 Apr 2026 10:18:11 -0700 Subject: [PATCH 12/24] Filter pre/post trimming assemblies by PostprocessAssembly metadata Both _PreTrimmingFixLegacyDesigner and _PostTrimmingPipeline were including all .dll files from ResolvedFileToPublish, which includes satellite resource assemblies (.resources.dll) from the shared NuGet package cache. These tasks open assemblies with ReadWrite access via DirectoryAssemblyResolver, causing IOException when parallel multi-RID builds contend for locks on the same cached files. Filter both targets to only process items where PostprocessAssembly metadata is 'true', which excludes satellite assemblies that ILLink does not process. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 1d9bbd590b7..2cce752fd5e 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -235,7 +235,7 @@ BeforeTargets="ILLink" Condition=" '$(PublishTrimmed)' == 'true' and '$(AndroidUseDesignerAssembly)' == 'True' "> - <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " /> + <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' and '%(ResolvedFileToPublish.PostprocessAssembly)' == 'true' " /> Date: Fri, 10 Apr 2026 15:25:59 -0700 Subject: [PATCH 13/24] Open assemblies read-only in PreTrimmingFixLegacyDesigner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The resolver was using ReadWrite=true, which acquires exclusive file locks on every assembly it loads — including the shared _Microsoft.Android.Resource.Designer.dll that is loaded implicitly via Resolve() during FixLegacyResourceDesignerStep.LoadDesigner(). The designer DLL is built once in the outer build at a shared obj/ path, but this task runs in each inner per-RID build. Parallel RID builds contend for exclusive locks on the shared file, causing IOException. Since the task only reads the designer assembly (never writes it), drop ReadWrite=true so all assemblies are opened in shared read mode. Library assemblies that get modified are written back using an explicit output path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/PreTrimmingFixLegacyDesigner.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs index 9c49fc6274b..5b0a896dda3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs @@ -33,8 +33,7 @@ public class PreTrimmingFixLegacyDesigner : AndroidTask public override bool RunTask () { using var resolver = new DirectoryAssemblyResolver ( - this.CreateTaskLogger (), loadDebugSymbols: true, - loadReaderParameters: new ReaderParameters { ReadWrite = true }); + this.CreateTaskLogger (), loadDebugSymbols: true); foreach (var assembly in Assemblies) { var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? ""); @@ -60,7 +59,7 @@ public override bool RunTask () var assembly = resolver.GetAssembly (item.ItemSpec); if (fixLegacyStep.ProcessAssemblyDesigner (assembly)) { Log.LogDebugMessage ($" Writing modified assembly: {item.ItemSpec}"); - assembly.Write (new WriterParameters { + assembly.Write (item.ItemSpec, new WriterParameters { WriteSymbols = assembly.MainModule.HasSymbols, DeterministicMvid = Deterministic, }); From 642052259a224d91c23eb0b6015f298eb7d9759c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 13 Apr 2026 11:03:02 -0700 Subject: [PATCH 14/24] Use InMemory=true to avoid file locking in PreTrimmingFixLegacyDesigner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The resolver was using memory-mapped files (the default), which holds file mappings open for the lifetime of the resolver. When the task writes modified assemblies back to disk, Cecil also tries to open the .pdb for writing, but the memory-mapped section is still active — causing IOException on both Linux and Windows. Using InMemory=true reads assemblies fully into memory without holding any file handles, so writing back to the same path works without conflicts. This also avoids exclusive locks on the shared designer assembly during parallel multi-RID builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/PreTrimmingFixLegacyDesigner.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs index 5b0a896dda3..2213ab9a515 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PreTrimmingFixLegacyDesigner.cs @@ -33,7 +33,8 @@ public class PreTrimmingFixLegacyDesigner : AndroidTask public override bool RunTask () { using var resolver = new DirectoryAssemblyResolver ( - this.CreateTaskLogger (), loadDebugSymbols: true); + this.CreateTaskLogger (), loadDebugSymbols: true, + loadReaderParameters: new ReaderParameters { InMemory = true }); foreach (var assembly in Assemblies) { var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? ""); From 3629ccf0fc8a9ec6843d2a28211f78a095e027fe Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 13 Apr 2026 11:57:00 -0700 Subject: [PATCH 15/24] Write modified assemblies to intermediate directory instead of in-place PreTrimmingFixLegacyDesigner was writing modified assemblies back to their original paths, which for NuGet package assemblies means mutating files in the shared NuGet cache. This can corrupt other builds using the same packages and causes file locking issues with memory-mapped reads. Write modified assemblies to an intermediate directory (obj//prelink/) and update ResolvedFileToPublish to point to the new copies so ILLink picks them up. The original files in the NuGet cache remain untouched. Also removes InMemory=true and ReadWrite=true from the resolver since we no longer write to any file the resolver has open. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 14 ++++++++- .../Tasks/PreTrimmingFixLegacyDesigner.cs | 30 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 2cce752fd5e..e694c57ce29 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -230,6 +230,9 @@ designer assembly's property getters, and clears the per-library designer classes. Because the rewritten IL no longer references the old designer fields, ILLink can freely trim unused designer types without needing a root descriptor. + + Modified assemblies are written to an intermediate directory (not in-place) to + avoid mutating files in the shared NuGet cache or shared intermediate output paths. --> + OutputDirectory="$(IntermediateOutputPath)prelink" + Deterministic="$(Deterministic)"> + + + + + <_PreTrimmingOriginalAssembly Include="@(_PreTrimmingModifiedAssembly->'%(OriginalPath)')" /> + + + rather than in-place, +/// to avoid mutating files in the shared NuGet cache or shared intermediate output paths. /// public class PreTrimmingFixLegacyDesigner : AndroidTask { @@ -28,13 +33,20 @@ public class PreTrimmingFixLegacyDesigner : AndroidTask [Required] public string TargetName { get; set; } = ""; + [Required] + public string OutputDirectory { get; set; } = ""; + public bool Deterministic { get; set; } + [Output] + public ITaskItem []? ModifiedAssemblies { get; set; } + public override bool RunTask () { + Directory.CreateDirectory (OutputDirectory); + using var resolver = new DirectoryAssemblyResolver ( - this.CreateTaskLogger (), loadDebugSymbols: true, - loadReaderParameters: new ReaderParameters { InMemory = true }); + this.CreateTaskLogger (), loadDebugSymbols: true); foreach (var assembly in Assemblies) { var dir = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec) ?? ""); @@ -47,6 +59,8 @@ public override bool RunTask () var fixLegacyStep = new FixLegacyResourceDesignerStep (); fixLegacyStep.Initialize (linkContext); + var modified = new List (); + foreach (var item in Assemblies) { // Match the filtering in FixLegacyResourceDesignerStep.ProcessAssembly: // skip the main assembly and framework/BCL assemblies. @@ -59,14 +73,22 @@ public override bool RunTask () var assembly = resolver.GetAssembly (item.ItemSpec); if (fixLegacyStep.ProcessAssemblyDesigner (assembly)) { - Log.LogDebugMessage ($" Writing modified assembly: {item.ItemSpec}"); - assembly.Write (item.ItemSpec, new WriterParameters { + var outputPath = Path.Combine (OutputDirectory, Path.GetFileName (item.ItemSpec)); + Log.LogDebugMessage ($" Writing modified assembly: {outputPath}"); + assembly.Write (outputPath, new WriterParameters { WriteSymbols = assembly.MainModule.HasSymbols, DeterministicMvid = Deterministic, }); + + var outputItem = new TaskItem (outputPath); + item.CopyMetadataTo (outputItem); + outputItem.SetMetadata ("OriginalPath", item.ItemSpec); + modified.Add (outputItem); } } + ModifiedAssemblies = modified.ToArray (); + return !Log.HasLoggedErrors; } } From db7071529459cca9a9bfa0f2b5570e76b2b14c23 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 13 Apr 2026 12:29:12 -0700 Subject: [PATCH 16/24] Add FileWrites for incremental clean support The prelink output files must be added to @(FileWrites) so IncrementalClean doesn't delete them between builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index e694c57ce29..39f6d60a15b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -252,6 +252,7 @@ <_PreTrimmingOriginalAssembly Include="@(_PreTrimmingModifiedAssembly->'%(OriginalPath)')" /> + From 77e20ff2b76ef115d4082cd58514f17f5da4125a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 13 Apr 2026 12:37:16 -0700 Subject: [PATCH 17/24] Add Inputs/Outputs for incremental build support Split into two targets: _PreTrimmingFixLegacyDesigner does the work with Inputs/Outputs and a stamp file, _PreTrimmingFixLegacyDesignerUpdateItems always runs to swap ResolvedFileToPublish entries with the prelink copies. The swap target uses an Exists() check and MSBuild item transforms to match prelink outputs to their original ResolvedFileToPublish items, preserving all metadata while changing the path. This works whether the main target ran or was skipped as up-to-date. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 39f6d60a15b..ea2a8d33354 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -236,7 +236,9 @@ --> + Condition=" '$(PublishTrimmed)' == 'true' and '$(AndroidUseDesignerAssembly)' == 'True' " + Inputs="@(ResolvedFileToPublish->'%(FullPath)')" + Outputs="$(_AndroidStampDirectory)_PreTrimmingFixLegacyDesigner.stamp"> <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' and '%(ResolvedFileToPublish.PostprocessAssembly)' == 'true' " /> @@ -247,15 +249,29 @@ Deterministic="$(Deterministic)"> - + - <_PreTrimmingOriginalAssembly Include="@(_PreTrimmingModifiedAssembly->'%(OriginalPath)')" /> - - + + + + <_PreTrimmingSwappableItem Include="@(ResolvedFileToPublish)" + Condition=" '%(Extension)' == '.dll' and Exists('$(IntermediateOutputPath)prelink/%(Filename)%(Extension)') " /> + + + + + Date: Mon, 13 Apr 2026 15:18:44 -0700 Subject: [PATCH 18/24] Scope Inputs to PostprocessAssembly assemblies only Split _PreTrimmingAssembly collection into a separate dependency target so the filtered item group is available for the Inputs attribute. This avoids re-running the task when unrelated ResolvedFileToPublish items change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index ea2a8d33354..2223e078b22 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -234,14 +234,20 @@ Modified assemblies are written to an intermediate directory (not in-place) to avoid mutating files in the shared NuGet cache or shared intermediate output paths. --> + + + <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' and '%(ResolvedFileToPublish.PostprocessAssembly)' == 'true' " /> + + + - - <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' and '%(ResolvedFileToPublish.PostprocessAssembly)' == 'true' " /> - Date: Tue, 14 Apr 2026 14:27:46 -0700 Subject: [PATCH 19/24] Fix target ordering: run pre-trimming before ILLink dependency chain The pre-trimming targets were using BeforeTargets=ILLink, which runs after ILLink's DependsOnTargets chain has already executed. This meant _ComputeManagedAssemblyToLink had already snapshotted ManagedAssemblyToLink with the original paths before our ResolvedFileToPublish swap happened. ILLink's Remove then didn't match our prelink/ paths, leaving duplicate assemblies in ResolvedFileToPublish and causing CrossGen/R2R failures: 'Multiple input files matching same simple name'. Switch to AfterTargets=ComputeResolvedFilesToPublishList so the pre-trimming and RFTP swap happen before _ComputeManagedAssemblyToLink runs. Add DependsOnTargets=_ComputeAssembliesToPostprocessOnPublish to ensure PostprocessAssembly metadata is set before we filter assemblies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 946114aac06..4aff146e88a 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -235,7 +235,8 @@ avoid mutating files in the shared NuGet cache or shared intermediate output paths. --> <_PreTrimmingAssembly Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' and '%(ResolvedFileToPublish.PostprocessAssembly)' == 'true' " /> @@ -243,7 +244,7 @@ From 8e45623772d2efb6490d7440ea1b974de8844b56 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 15 Apr 2026 10:11:14 -0700 Subject: [PATCH 20/24] Remove designer rooting and post-trimming FixLegacyResourceDesigner PreTrimmingFixLegacyDesigner rewrites library assemblies before ILLink, so ILLink naturally preserves only the designer properties that are actually referenced. The TrimmerRootDescriptor that preserved all designer types is no longer needed and was preventing trimming gains. Also remove FixLegacyResourceDesignerStep from PostTrimmingPipeline since it now runs pre-trimming only. Remove the UseDesignerAssembly property and PostTrimmingFixLegacyResourceDesignerStep wrapper class. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Xamarin.Android.Resource.Designer.targets | 15 -------- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 3 +- .../Tasks/PostTrimmingPipeline.cs | 36 +------------------ 3 files changed, 2 insertions(+), 52 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets index 1a6bc1166a8..e19d986acda 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Resource.Designer.targets @@ -236,15 +236,6 @@ Copyright (C) 2016 Xamarin. All rights reserved. Condition=" '$(AndroidUseDesignerAssembly)' == 'True' " AfterTargets="ComputeResolvedFilesToPublishList" DependsOnTargets="_SetupDesignerProperties"> - - <_DesignerLinkerDescriptor>$(IntermediateOutputPath)_Microsoft.Android.Resource.Designer.xml - - $(_DesignerAssemblyName).dll @@ -252,12 +243,6 @@ Copyright (C) 2016 Xamarin. All rights reserved. true true - - - diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 4aff146e88a..87610716732 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -304,8 +304,7 @@ Assemblies="@(_PostTrimmingAssembly)" AddKeepAlives="$(AndroidAddKeepAlives)" AndroidLinkResources="$(AndroidLinkResources)" - Deterministic="$(Deterministic)" - UseDesignerAssembly="$(AndroidUseDesignerAssembly)" /> + Deterministic="$(Deterministic)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index 9af2b1b6419..e8604280201 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -6,8 +6,6 @@ using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Mono.Cecil; -using Mono.Linker; -using MonoDroid.Tuner; namespace Xamarin.Android.Tasks; @@ -17,7 +15,7 @@ namespace Xamarin.Android.Tasks; /// This opens each assembly once (via DirectoryAssemblyResolver with ReadWrite) and /// runs all registered steps on it, then writes modified assemblies in-place. Currently /// runs CheckForObsoletePreserveAttributeStep, StripEmbeddedLibrariesStep and -/// (optionally) AddKeepAlivesStep and FixLegacyResourceDesignerStep. +/// (optionally) AddKeepAlivesStep. /// /// Runs in the inner build after ILLink but before ReadyToRun/crossgen2 compilation, /// so that R2R images are generated from the already-modified assemblies. @@ -35,8 +33,6 @@ public class PostTrimmingPipeline : AndroidTask public bool Deterministic { get; set; } - public bool UseDesignerAssembly { get; set; } - public override bool RunTask () { using var resolver = new DirectoryAssemblyResolver ( @@ -103,15 +99,6 @@ public override bool RunTask () }, (msg) => Log.LogDebugMessage (msg))); } - if (UseDesignerAssembly) { - // Create an MSBuildLinkContext so FixLegacyResourceDesignerStep can resolve assemblies - // and log messages. The resolver is owned by the outer 'using' block, so we intentionally - // do not dispose this context (LinkContext.Dispose would double-dispose the resolver). - var linkContext = new MSBuildLinkContext (resolver, Log); - var fixLegacyStep = new FixLegacyResourceDesignerStep (); - fixLegacyStep.Initialize (linkContext); - steps.Add (new PostTrimmingFixLegacyResourceDesignerStep (fixLegacyStep)); - } foreach (var (item, assembly) in loadedAssemblies) { var context = new StepContext (item, item); @@ -130,24 +117,3 @@ public override bool RunTask () return !Log.HasLoggedErrors; } } - -/// -/// Thin wrapper around for the post-trimming pipeline. -/// Calls directly, matching the -/// behavior of the former ILLink path which processed all assemblies without StepContext flag filtering. -/// Assemblies without a resource designer are skipped internally by ProcessAssemblyDesigner. -/// -class PostTrimmingFixLegacyResourceDesignerStep : IAssemblyModifierPipelineStep -{ - readonly FixLegacyResourceDesignerStep _inner; - - public PostTrimmingFixLegacyResourceDesignerStep (FixLegacyResourceDesignerStep inner) - { - _inner = inner; - } - - public void ProcessAssembly (AssemblyDefinition assembly, StepContext context) - { - context.IsAssemblyModified |= _inner.ProcessAssemblyDesigner (assembly); - } -} From 1b8748b2ac4d91a1fba33a8690b03fb73d1fc3d9 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 15 Apr 2026 11:17:03 -0700 Subject: [PATCH 21/24] Restore MonoDroid.Tuner using directive in PostTrimmingPipeline The other pipeline steps (CheckForObsoletePreserveAttributeStep, StripEmbeddedLibrariesStep, etc.) still need this namespace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs index e8604280201..fa3c3385737 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs @@ -6,6 +6,7 @@ using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Mono.Cecil; +using MonoDroid.Tuner; namespace Xamarin.Android.Tasks; From 122e9a4a30c55965ff6c15fa8dccbede22f7f687 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 15 Apr 2026 16:14:46 -0700 Subject: [PATCH 22/24] Update apkdiff baselines for improved designer trimming Removing the TrimmerRootDescriptor allows ILLink to trim unused designer types, reducing APK size. Update all BuildReleaseArm64 baselines using the UpdateApkSizeReference script approach. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...ldReleaseArm64SimpleDotNet.CoreCLR.apkdesc | 4 +- ...ildReleaseArm64SimpleDotNet.MonoVM.apkdesc | 12 +- ...ReleaseArm64SimpleDotNet.NativeAOT.apkdesc | 2 +- ...ldReleaseArm64XFormsDotNet.CoreCLR.apkdesc | 223 +---------------- ...ildReleaseArm64XFormsDotNet.MonoVM.apkdesc | 235 +----------------- ...ReleaseArm64XFormsDotNet.NativeAOT.apkdesc | 221 +--------------- 6 files changed, 29 insertions(+), 668 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc index 9c3e342a13d..e5d57c1c6ce 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc @@ -8,7 +8,7 @@ "Size": 400044 }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 3115312 + "Size": 3114872 }, "lib/arm64-v8a/libclrjit.so": { "Size": 3202072 @@ -17,7 +17,7 @@ "Size": 5766640 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1365104 + "Size": 1365360 }, "lib/arm64-v8a/libmscordaccore.so": { "Size": 2493552 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc index 5b76d46097d..762aec77296 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc @@ -8,16 +8,16 @@ "Size": 22388 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18696 + "Size": 18288 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 88048 + "Size": 88144 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 117928 + "Size": 117984 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26464 + "Size": 26472 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24432 @@ -35,7 +35,7 @@ "Size": 21632 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 20144 + "Size": 20152 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 19176 @@ -44,7 +44,7 @@ "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1386072 + "Size": 1386328 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3124368 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc index f3a4ee3f174..ec1aa177d43 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc @@ -8,7 +8,7 @@ "Size": 25400 }, "lib/arm64-v8a/libUnnamedProject.so": { - "Size": 5056848 + "Size": 5055552 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc index 2d96ae07999..86f2e82b4f7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc @@ -10,29 +10,8 @@ "classes2.dex": { "Size": 156448 }, - "kotlin/annotation/annotation.kotlin_builtins": { - "Size": 928 - }, - "kotlin/collections/collections.kotlin_builtins": { - "Size": 3685 - }, - "kotlin/coroutines/coroutines.kotlin_builtins": { - "Size": 200 - }, - "kotlin/internal/internal.kotlin_builtins": { - "Size": 646 - }, - "kotlin/kotlin.kotlin_builtins": { - "Size": 18640 - }, - "kotlin/ranges/ranges.kotlin_builtins": { - "Size": 3399 - }, - "kotlin/reflect/reflect.kotlin_builtins": { - "Size": 2396 - }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 14459432 + "Size": 14078272 }, "lib/arm64-v8a/libclrjit.so": { "Size": 3202072 @@ -41,7 +20,7 @@ "Size": 5766640 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1365104 + "Size": 1365360 }, "lib/arm64-v8a/libmscordaccore.so": { "Size": 2493552 @@ -64,206 +43,14 @@ "lib/arm64-v8a/libxamarin-app.so": { "Size": 147368 }, - "META-INF/androidx.activity_activity.version": { - "Size": 6 - }, - "META-INF/androidx.annotation_annotation-experimental.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat-resources.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat.version": { - "Size": 6 - }, - "META-INF/androidx.arch.core_core-runtime.version": { - "Size": 67 - }, - "META-INF/androidx.asynclayoutinflater_asynclayoutinflater.version": { - "Size": 6 - }, - "META-INF/androidx.browser_browser.version": { - "Size": 60 - }, - "META-INF/androidx.cardview_cardview.version": { - "Size": 6 - }, - "META-INF/androidx.coordinatorlayout_coordinatorlayout.version": { - "Size": 6 - }, - "META-INF/androidx.core_core-ktx.version": { - "Size": 6 - }, - "META-INF/androidx.core_core.version": { - "Size": 7 - }, - "META-INF/androidx.cursoradapter_cursoradapter.version": { - "Size": 6 - }, - "META-INF/androidx.customview_customview.version": { - "Size": 6 - }, - "META-INF/androidx.documentfile_documentfile.version": { - "Size": 6 - }, - "META-INF/androidx.drawerlayout_drawerlayout.version": { - "Size": 6 - }, - "META-INF/androidx.dynamicanimation_dynamicanimation.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2-views-helper.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2.version": { - "Size": 6 - }, - "META-INF/androidx.fragment_fragment.version": { - "Size": 6 - }, - "META-INF/androidx.interpolator_interpolator.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-ui.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-utils.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-v4.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-process.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-runtime.version": { - "Size": 72 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel-savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel.version": { - "Size": 6 - }, - "META-INF/androidx.loader_loader.version": { - "Size": 6 - }, - "META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version": { - "Size": 6 - }, - "META-INF/androidx.media_media.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-common.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-ui.version": { - "Size": 6 - }, - "META-INF/androidx.preference_preference.version": { - "Size": 6 - }, - "META-INF/androidx.print_print.version": { - "Size": 6 - }, - "META-INF/androidx.profileinstaller_profileinstaller.version": { - "Size": 6 - }, - "META-INF/androidx.recyclerview_recyclerview.version": { - "Size": 6 - }, - "META-INF/androidx.savedstate_savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.slidingpanelayout_slidingpanelayout.version": { - "Size": 6 - }, - "META-INF/androidx.startup_startup-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.swiperefreshlayout_swiperefreshlayout.version": { - "Size": 6 - }, - "META-INF/androidx.tracing_tracing.version": { - "Size": 6 - }, - "META-INF/androidx.transition_transition.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable.version": { - "Size": 6 - }, - "META-INF/androidx.versionedparcelable_versionedparcelable.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager_viewpager.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager2_viewpager2.version": { - "Size": 6 - }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 90346 - }, - "META-INF/com.android.tools/proguard/coroutines.pro": { - "Size": 1345 - }, - "META-INF/com.android.tools/r8-from-1.6.0/coroutines.pro": { - "Size": 899 - }, - "META-INF/com.android.tools/r8-upto-3.0.0/coroutines.pro": { - "Size": 558 - }, - "META-INF/com.android.tools/r8/coroutines.pro": { - "Size": 1190 - }, - "META-INF/com.google.android.material_material.version": { - "Size": 6 - }, - "META-INF/kotlin-project-structure-metadata.json": { - "Size": 552 - }, - "META-INF/kotlinx_coroutines_android.version": { - "Size": 5 - }, - "META-INF/kotlinx_coroutines_core.version": { - "Size": 5 + "Size": 81667 }, "META-INF/MANIFEST.MF": { - "Size": 90219 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { - "Size": 96 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.xml": { - "Size": 2226 - }, - "META-INF/proguard/androidx-annotations.pro": { - "Size": 433 - }, - "META-INF/proguard/coroutines.pro": { - "Size": 1363 - }, - "META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler": { - "Size": 54 - }, - "META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory": { - "Size": 52 + "Size": 81540 }, "res/anim-v21/design_bottom_sheet_slide_in.xml": { "Size": 616 @@ -2285,5 +2072,5 @@ "Size": 812848 } }, - "PackageSize": 23086011 + "PackageSize": 22833433 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc index 054a451576a..abb82fa25e9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc @@ -7,41 +7,20 @@ "classes.dex": { "Size": 9159624 }, - "kotlin/annotation/annotation.kotlin_builtins": { - "Size": 928 - }, - "kotlin/collections/collections.kotlin_builtins": { - "Size": 3685 - }, - "kotlin/coroutines/coroutines.kotlin_builtins": { - "Size": 200 - }, - "kotlin/internal/internal.kotlin_builtins": { - "Size": 646 - }, - "kotlin/kotlin.kotlin_builtins": { - "Size": 18640 - }, - "kotlin/ranges/ranges.kotlin_builtins": { - "Size": 3399 - }, - "kotlin/reflect/reflect.kotlin_builtins": { - "Size": 2396 - }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 258400 + "Size": 19544 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96656 + "Size": 96696 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 541880 + "Size": 541912 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26464 + "Size": 26472 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21472 @@ -77,7 +56,7 @@ "Size": 24656 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19888 + "Size": 19848 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { "Size": 19472 @@ -161,7 +140,7 @@ "Size": 19304 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 22216 + "Size": 22224 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { "Size": 34960 @@ -221,7 +200,7 @@ "Size": 581000 }, "lib/arm64-v8a/lib_Xamarin.Forms.Platform.Android.dll.so": { - "Size": 390544 + "Size": 390392 }, "lib/arm64-v8a/lib_Xamarin.Forms.Platform.dll.so": { "Size": 35992 @@ -239,7 +218,7 @@ "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1386072 + "Size": 1386328 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3124368 @@ -259,206 +238,14 @@ "lib/arm64-v8a/libxamarin-app.so": { "Size": 350576 }, - "META-INF/androidx.activity_activity.version": { - "Size": 6 - }, - "META-INF/androidx.annotation_annotation-experimental.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat-resources.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat.version": { - "Size": 6 - }, - "META-INF/androidx.arch.core_core-runtime.version": { - "Size": 67 - }, - "META-INF/androidx.asynclayoutinflater_asynclayoutinflater.version": { - "Size": 6 - }, - "META-INF/androidx.browser_browser.version": { - "Size": 60 - }, - "META-INF/androidx.cardview_cardview.version": { - "Size": 6 - }, - "META-INF/androidx.coordinatorlayout_coordinatorlayout.version": { - "Size": 6 - }, - "META-INF/androidx.core_core-ktx.version": { - "Size": 6 - }, - "META-INF/androidx.core_core.version": { - "Size": 7 - }, - "META-INF/androidx.cursoradapter_cursoradapter.version": { - "Size": 6 - }, - "META-INF/androidx.customview_customview.version": { - "Size": 6 - }, - "META-INF/androidx.documentfile_documentfile.version": { - "Size": 6 - }, - "META-INF/androidx.drawerlayout_drawerlayout.version": { - "Size": 6 - }, - "META-INF/androidx.dynamicanimation_dynamicanimation.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2-views-helper.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2.version": { - "Size": 6 - }, - "META-INF/androidx.fragment_fragment.version": { - "Size": 6 - }, - "META-INF/androidx.interpolator_interpolator.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-ui.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-utils.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-v4.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-process.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-runtime.version": { - "Size": 72 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel-savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel.version": { - "Size": 6 - }, - "META-INF/androidx.loader_loader.version": { - "Size": 6 - }, - "META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version": { - "Size": 6 - }, - "META-INF/androidx.media_media.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-common.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-ui.version": { - "Size": 6 - }, - "META-INF/androidx.preference_preference.version": { - "Size": 6 - }, - "META-INF/androidx.print_print.version": { - "Size": 6 - }, - "META-INF/androidx.profileinstaller_profileinstaller.version": { - "Size": 6 - }, - "META-INF/androidx.recyclerview_recyclerview.version": { - "Size": 6 - }, - "META-INF/androidx.savedstate_savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.slidingpanelayout_slidingpanelayout.version": { - "Size": 6 - }, - "META-INF/androidx.startup_startup-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.swiperefreshlayout_swiperefreshlayout.version": { - "Size": 6 - }, - "META-INF/androidx.tracing_tracing.version": { - "Size": 6 - }, - "META-INF/androidx.transition_transition.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable.version": { - "Size": 6 - }, - "META-INF/androidx.versionedparcelable_versionedparcelable.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager_viewpager.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager2_viewpager2.version": { - "Size": 6 - }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 98319 - }, - "META-INF/com.android.tools/proguard/coroutines.pro": { - "Size": 1345 - }, - "META-INF/com.android.tools/r8-from-1.6.0/coroutines.pro": { - "Size": 899 - }, - "META-INF/com.android.tools/r8-upto-3.0.0/coroutines.pro": { - "Size": 558 - }, - "META-INF/com.android.tools/r8/coroutines.pro": { - "Size": 1190 - }, - "META-INF/com.google.android.material_material.version": { - "Size": 6 - }, - "META-INF/kotlin-project-structure-metadata.json": { - "Size": 552 - }, - "META-INF/kotlinx_coroutines_android.version": { - "Size": 5 - }, - "META-INF/kotlinx_coroutines_core.version": { - "Size": 5 + "Size": 89640 }, "META-INF/MANIFEST.MF": { - "Size": 98192 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { - "Size": 96 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.xml": { - "Size": 2226 - }, - "META-INF/proguard/androidx-annotations.pro": { - "Size": 433 - }, - "META-INF/proguard/coroutines.pro": { - "Size": 1363 - }, - "META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler": { - "Size": 54 - }, - "META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory": { - "Size": 52 + "Size": 89513 }, "res/anim-v21/design_bottom_sheet_slide_in.xml": { "Size": 616 @@ -2480,5 +2267,5 @@ "Size": 812848 } }, - "PackageSize": 11287613 + "PackageSize": 11108763 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.NativeAOT.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.NativeAOT.apkdesc index c86f1cb9523..d5ed381a144 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.NativeAOT.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.NativeAOT.apkdesc @@ -7,230 +7,17 @@ "classes.dex": { "Size": 9131612 }, - "kotlin/annotation/annotation.kotlin_builtins": { - "Size": 928 - }, - "kotlin/collections/collections.kotlin_builtins": { - "Size": 3685 - }, - "kotlin/coroutines/coroutines.kotlin_builtins": { - "Size": 200 - }, - "kotlin/internal/internal.kotlin_builtins": { - "Size": 646 - }, - "kotlin/kotlin.kotlin_builtins": { - "Size": 18640 - }, - "kotlin/ranges/ranges.kotlin_builtins": { - "Size": 3399 - }, - "kotlin/reflect/reflect.kotlin_builtins": { - "Size": 2396 - }, "lib/arm64-v8a/libUnnamedProject.so": { - "Size": 22749272 - }, - "META-INF/androidx.activity_activity.version": { - "Size": 6 - }, - "META-INF/androidx.annotation_annotation-experimental.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat-resources.version": { - "Size": 6 - }, - "META-INF/androidx.appcompat_appcompat.version": { - "Size": 6 - }, - "META-INF/androidx.arch.core_core-runtime.version": { - "Size": 67 - }, - "META-INF/androidx.asynclayoutinflater_asynclayoutinflater.version": { - "Size": 6 - }, - "META-INF/androidx.browser_browser.version": { - "Size": 60 - }, - "META-INF/androidx.cardview_cardview.version": { - "Size": 6 - }, - "META-INF/androidx.coordinatorlayout_coordinatorlayout.version": { - "Size": 6 - }, - "META-INF/androidx.core_core-ktx.version": { - "Size": 6 - }, - "META-INF/androidx.core_core.version": { - "Size": 7 - }, - "META-INF/androidx.cursoradapter_cursoradapter.version": { - "Size": 6 - }, - "META-INF/androidx.customview_customview.version": { - "Size": 6 - }, - "META-INF/androidx.documentfile_documentfile.version": { - "Size": 6 - }, - "META-INF/androidx.drawerlayout_drawerlayout.version": { - "Size": 6 - }, - "META-INF/androidx.dynamicanimation_dynamicanimation.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2-views-helper.version": { - "Size": 6 - }, - "META-INF/androidx.emoji2_emoji2.version": { - "Size": 6 - }, - "META-INF/androidx.fragment_fragment.version": { - "Size": 6 - }, - "META-INF/androidx.interpolator_interpolator.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-ui.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-core-utils.version": { - "Size": 6 - }, - "META-INF/androidx.legacy_legacy-support-v4.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-livedata.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-process.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-runtime.version": { - "Size": 72 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel-savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.lifecycle_lifecycle-viewmodel.version": { - "Size": 6 - }, - "META-INF/androidx.loader_loader.version": { - "Size": 6 - }, - "META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version": { - "Size": 6 - }, - "META-INF/androidx.media_media.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-common.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.navigation_navigation-ui.version": { - "Size": 6 - }, - "META-INF/androidx.preference_preference.version": { - "Size": 6 - }, - "META-INF/androidx.print_print.version": { - "Size": 6 - }, - "META-INF/androidx.profileinstaller_profileinstaller.version": { - "Size": 6 - }, - "META-INF/androidx.recyclerview_recyclerview.version": { - "Size": 6 - }, - "META-INF/androidx.savedstate_savedstate.version": { - "Size": 6 - }, - "META-INF/androidx.slidingpanelayout_slidingpanelayout.version": { - "Size": 6 - }, - "META-INF/androidx.startup_startup-runtime.version": { - "Size": 6 - }, - "META-INF/androidx.swiperefreshlayout_swiperefreshlayout.version": { - "Size": 6 - }, - "META-INF/androidx.tracing_tracing.version": { - "Size": 6 - }, - "META-INF/androidx.transition_transition.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { - "Size": 6 - }, - "META-INF/androidx.vectordrawable_vectordrawable.version": { - "Size": 6 - }, - "META-INF/androidx.versionedparcelable_versionedparcelable.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager_viewpager.version": { - "Size": 6 - }, - "META-INF/androidx.viewpager2_viewpager2.version": { - "Size": 6 + "Size": 21483352 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 }, "META-INF/BNDLTOOL.SF": { - "Size": 89178 - }, - "META-INF/com.android.tools/proguard/coroutines.pro": { - "Size": 1345 - }, - "META-INF/com.android.tools/r8-from-1.6.0/coroutines.pro": { - "Size": 899 - }, - "META-INF/com.android.tools/r8-upto-3.0.0/coroutines.pro": { - "Size": 558 - }, - "META-INF/com.android.tools/r8/coroutines.pro": { - "Size": 1190 - }, - "META-INF/com.google.android.material_material.version": { - "Size": 6 - }, - "META-INF/kotlin-project-structure-metadata.json": { - "Size": 552 - }, - "META-INF/kotlinx_coroutines_android.version": { - "Size": 5 - }, - "META-INF/kotlinx_coroutines_core.version": { - "Size": 5 + "Size": 80499 }, "META-INF/MANIFEST.MF": { - "Size": 89051 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { - "Size": 96 - }, - "META-INF/maven/com.google.guava/listenablefuture/pom.xml": { - "Size": 2226 - }, - "META-INF/proguard/androidx-annotations.pro": { - "Size": 433 - }, - "META-INF/proguard/coroutines.pro": { - "Size": 1363 - }, - "META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler": { - "Size": 54 - }, - "META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory": { - "Size": 52 + "Size": 80372 }, "res/anim-v21/design_bottom_sheet_slide_in.xml": { "Size": 616 @@ -2252,5 +2039,5 @@ "Size": 812848 } }, - "PackageSize": 12808265 + "PackageSize": 12461479 } \ No newline at end of file From b28ccdf6589964aabfb5989c42cba638600534b0 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 16 Apr 2026 12:29:17 -0700 Subject: [PATCH 23/24] Fix NativeAOT pre-trimming ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _AndroidRunNativeCompile hooks AfterTargets=ComputeResolvedFilesToPublishList and is imported before our pre-trimming targets (via Sdk.targets vs Sdk.After.targets). MSBuild runs AfterTargets hooks in definition order, so _AndroidRunNativeCompile ran first, pulling in NativeCompile → ILLink before our pre-trimming step had a chance to run. Add _PreTrimmingFixLegacyDesignerUpdateItems as a DependsOnTargets of _AndroidRunNativeCompile so the pre-trimming and RFTP swap happens before NativeCompile triggers ILLink. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../targets/Microsoft.Android.Sdk.NativeAOT.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index ddf8348d9e9..14eb57c1134 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -267,7 +267,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. --> + DependsOnTargets="_PreTrimmingFixLegacyDesignerUpdateItems;NativeCompile" /> From ac02d09a29b6492b0e1a01b48f5fcb3efa561a6c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 16 Apr 2026 12:36:02 -0700 Subject: [PATCH 24/24] Create stamp directory and update NativeAOT apkdiff baselines The stamp directory may not exist when the pre-trimming target runs early in the NativeAOT build pipeline. Add MakeDir to ensure it exists. Update apkdiff baselines for NativeAOT variants now that pre-trimming runs before ILLink in NativeAOT builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...crosoft.Android.Sdk.TypeMap.LlvmIr.targets | 1 + ...ldReleaseArm64SimpleDotNet.CoreCLR.apkdesc | 14 +- ...ildReleaseArm64SimpleDotNet.MonoVM.apkdesc | 18 +- ...ReleaseArm64SimpleDotNet.NativeAOT.apkdesc | 4 +- ...ldReleaseArm64XFormsDotNet.CoreCLR.apkdesc | 231 ++++++++++++++- ...ildReleaseArm64XFormsDotNet.MonoVM.apkdesc | 271 ++++++++++++++++-- ...ReleaseArm64XFormsDotNet.NativeAOT.apkdesc | 221 +++++++++++++- 7 files changed, 700 insertions(+), 60 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets index 87610716732..4b1cb9fcab0 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets @@ -249,6 +249,7 @@ Condition=" '$(PublishTrimmed)' == 'true' and '$(AndroidUseDesignerAssembly)' == 'True' " Inputs="@(_PreTrimmingAssembly)" Outputs="$(_AndroidStampDirectory)_PreTrimmingFixLegacyDesigner.stamp"> +