From 70f7f30284cf6821a0299e046e17688ce6d3bb44 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 30 Mar 2026 16:55:43 -0700 Subject: [PATCH 01/10] [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/10] [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/10] 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/10] 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/10] 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/10] 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/10] 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/10] 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 a92e39f58668a92878c841cdfbdef73e693dde8e Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 10:25:09 -0700 Subject: [PATCH 09/10] 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 1eec90905a9414fa49ed5eda50595ca72c215514 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 10:44:48 -0700 Subject: [PATCH 10/10] Update APK size reference baselines FixLegacyResourceDesignerStep now runs post-ILLink with preserve=all, keeping all designer properties instead of only those referenced by libraries. This increases the designer assembly from ~19KB to ~135KB in the XForms MonoVM test app (1% of total APK size). Other baselines updated for SDK changes from the main branch merge. --- ...ldReleaseArm64SimpleDotNet.CoreCLR.apkdesc | 20 ++-- ...ildReleaseArm64SimpleDotNet.MonoVM.apkdesc | 14 +-- ...ReleaseArm64SimpleDotNet.NativeAOT.apkdesc | 8 +- ...ldReleaseArm64XFormsDotNet.CoreCLR.apkdesc | 22 ++-- ...ildReleaseArm64XFormsDotNet.MonoVM.apkdesc | 100 +++++++++--------- ...ReleaseArm64XFormsDotNet.NativeAOT.apkdesc | 8 +- 6 files changed, 86 insertions(+), 86 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 ef8da6c5bd7..9c3e342a13d 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 @@ -5,25 +5,25 @@ "Size": 3036 }, "classes.dex": { - "Size": 397520 + "Size": 400044 }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 3091928 + "Size": 3115312 }, "lib/arm64-v8a/libclrjit.so": { - "Size": 3141224 + "Size": 3202072 }, "lib/arm64-v8a/libcoreclr.so": { - "Size": 5736320 + "Size": 5766640 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1375784 + "Size": 1365104 }, "lib/arm64-v8a/libmscordaccore.so": { - "Size": 2442416 + "Size": 2493552 }, "lib/arm64-v8a/libmscordbi.so": { - "Size": 1894280 + "Size": 1902744 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71936 @@ -32,13 +32,13 @@ "Size": 1281696 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 105664 + "Size": 107904 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 165536 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 20128 + "Size": 20520 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 @@ -74,5 +74,5 @@ "Size": 1904 } }, - "PackageSize": 9176858 + "PackageSize": 9258778 } \ No newline at end of file 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 81aafc33724..5b76d46097d 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": 18288 + "Size": 18696 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 88040 + "Size": 88048 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 118024 + "Size": 117928 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26544 + "Size": 26464 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24432 @@ -35,7 +35,7 @@ "Size": 21632 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 20032 + "Size": 20144 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 19176 @@ -44,7 +44,7 @@ "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1386512 + "Size": 1386072 }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 3124368 @@ -62,7 +62,7 @@ "Size": 165536 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19840 + "Size": 19792 }, "META-INF/BNDLTOOL.RSA": { "Size": 1221 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 ece794fa0da..f3a4ee3f174 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 @@ -5,13 +5,13 @@ "Size": 3124 }, "classes.dex": { - "Size": 24224 + "Size": 25400 }, "lib/arm64-v8a/libUnnamedProject.so": { - "Size": 4968680 + "Size": 5056848 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1211 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 1211 @@ -44,5 +44,5 @@ "Size": 1904 } }, - "PackageSize": 2094050 + "PackageSize": 2122722 } \ No newline at end of file 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 ba0b9bd02ed..2d96ae07999 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 @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9447644 + "Size": 9444112 }, "classes2.dex": { "Size": 156448 @@ -32,22 +32,22 @@ "Size": 2396 }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 14041376 + "Size": 14459432 }, "lib/arm64-v8a/libclrjit.so": { - "Size": 3141224 + "Size": 3202072 }, "lib/arm64-v8a/libcoreclr.so": { - "Size": 5736320 + "Size": 5766640 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1375784 + "Size": 1365104 }, "lib/arm64-v8a/libmscordaccore.so": { - "Size": 2442416 + "Size": 2493552 }, "lib/arm64-v8a/libmscordbi.so": { - "Size": 1894280 + "Size": 1902744 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71936 @@ -56,13 +56,13 @@ "Size": 1281696 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 105664 + "Size": 107904 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 165536 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 147200 + "Size": 147368 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -215,7 +215,7 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 90346 @@ -2285,5 +2285,5 @@ "Size": 812848 } }, - "PackageSize": 22766523 + "PackageSize": 23086011 } \ 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 fd8f2a40c19..054a451576a 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 @@ -5,7 +5,7 @@ "Size": 6652 }, "classes.dex": { - "Size": 9165600 + "Size": 9159624 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -29,139 +29,139 @@ "Size": 2396 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 19544 + "Size": 258400 }, "lib/arm64-v8a/lib_FormsViewGroup.dll.so": { "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96664 + "Size": 96656 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 541152 + "Size": 541880 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26328 + "Size": 26464 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { - "Size": 21464 + "Size": 21472 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23112 + "Size": 23120 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 34008 + "Size": 34024 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 25680 + "Size": 25688 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23872 + "Size": 23880 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 19624 + "Size": 19632 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 21352 + "Size": 21368 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 43664 + "Size": 43672 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24456 + "Size": 24464 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19488 + "Size": 19496 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24648 + "Size": 24656 }, "lib/arm64-v8a/lib_System.dll.so": { "Size": 19888 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19464 + "Size": 19472 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30080 + "Size": 30096 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50200 + "Size": 51040 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29608 + "Size": 29616 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 34672 + "Size": 34680 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 28304 + "Size": 28312 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 48136 + "Size": 48144 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 186032 + "Size": 186048 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 86736 + "Size": 86752 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 42376 + "Size": 42384 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21584 + "Size": 21592 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27040 + "Size": 27048 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 994736 + "Size": 997176 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 217984 + "Size": 217968 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 62344 + "Size": 62280 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 236832 + "Size": 237032 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35536 + "Size": 35544 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20360 + "Size": 20424 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21624 + "Size": 21632 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { "Size": 61504 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19392 + "Size": 19400 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { "Size": 20368 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21488 + "Size": 21496 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 82176 + "Size": 82088 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 191264 + "Size": 194000 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19280 + "Size": 19288 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19296 + "Size": 19304 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 22104 + "Size": 22216 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { "Size": 34960 @@ -221,10 +221,10 @@ "Size": 581000 }, "lib/arm64-v8a/lib_Xamarin.Forms.Platform.Android.dll.so": { - "Size": 390456 + "Size": 390544 }, "lib/arm64-v8a/lib_Xamarin.Forms.Platform.dll.so": { - "Size": 35848 + "Size": 35992 }, "lib/arm64-v8a/lib_Xamarin.Forms.Xaml.dll.so": { "Size": 80632 @@ -233,16 +233,16 @@ "Size": 84768 }, "lib/arm64-v8a/libarc.bin.so": { - "Size": 19112 + "Size": 19176 }, "lib/arm64-v8a/libmono-component-marshal-ilgen.so": { "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1386232 + "Size": 1386072 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3123608 + "Size": 3124368 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71936 @@ -251,13 +251,13 @@ "Size": 1281696 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 105664 + "Size": 107904 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 165536 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 350616 + "Size": 350576 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -2480,5 +2480,5 @@ "Size": 812848 } }, - "PackageSize": 11131965 + "PackageSize": 11287613 } \ 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 4ce53ff43f2..c86f1cb9523 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 @@ -5,7 +5,7 @@ "Size": 6740 }, "classes.dex": { - "Size": 9136980 + "Size": 9131612 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -29,7 +29,7 @@ "Size": 2396 }, "lib/arm64-v8a/libUnnamedProject.so": { - "Size": 21592848 + "Size": 22749272 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -182,7 +182,7 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1221 }, "META-INF/BNDLTOOL.SF": { "Size": 89178 @@ -2252,5 +2252,5 @@ "Size": 812848 } }, - "PackageSize": 12521545 + "PackageSize": 12808265 } \ No newline at end of file