From 7e4162e1a7d8759d3579576206cafc1213aa4fcd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:19:43 +0000 Subject: [PATCH 01/10] Initial plan From 908aa09a0e902ce275b87a99c0d7ae54a28f0a63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:44:08 +0000 Subject: [PATCH 02/10] Guard Mono AOT targets for MonoVM-only runtime, add XA1042 warning for Mono-specific properties used with non-MonoVM runtimes Agent-Logs-Url: https://github.com/dotnet/android/sessions/a5ac81b3-0cd5-4a8a-9394-531fa1466274 Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- Documentation/docs-mobile/messages/xa1042.md | 45 +++++++++++++++++++ .../targets/Microsoft.Android.Sdk.Aot.targets | 4 +- ...soft.Android.Sdk.DefaultProperties.targets | 5 +++ .../Properties/Resources.Designer.cs | 9 ++++ .../Properties/Resources.resx | 7 +++ .../Xamarin.Android.Build.Tests/AotTests.cs | 32 +++++++++++++ .../Xamarin.Android.Common.targets | 10 +++++ 7 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 Documentation/docs-mobile/messages/xa1042.md diff --git a/Documentation/docs-mobile/messages/xa1042.md b/Documentation/docs-mobile/messages/xa1042.md new file mode 100644 index 00000000000..f57c6e6cbd2 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa1042.md @@ -0,0 +1,45 @@ +--- +title: .NET for Android warning XA1042 +description: XA1042 warning code +ms.date: 04/02/2026 +f1_keywords: + - "XA1042" +--- + +# .NET for Android warning XA1042 + +## Example messages + +``` +warning XA1042: The MSBuild property 'RunAOTCompilation' is not compatible with the CoreCLR runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" +``` + +## Issue + +This warning indicates that a Mono-specific MSBuild property is set in +the project file, but the project is configured to use a non-Mono +runtime (such as CoreCLR or NativeAOT). The property will have no +effect with the current runtime and will be ignored. + +Properties that trigger this warning include: +- `RunAOTCompilation` — Mono AOT compilation; CoreCLR uses `PublishReadyToRun` instead. +- `EnableLLVM` — Enables LLVM for the Mono AOT compiler. + +## Solution + +Remove the Mono-specific property from your project file or +`Directory.Build.props`, or guard it with a runtime condition: + +```xml + + true + +``` + +For CoreCLR, use `PublishReadyToRun` instead of `RunAOTCompilation`: + +```xml + + true + +``` diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index d80be84d01c..3537c75fb4b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -21,7 +21,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). when $(MonoAOTCompilerTasksAssemblyPath) is blank: https://github.com/dotnet/runtime/blob/69711860262e44458bbe276393ea3eb9f7a2192a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L20-L25 --> - + @@ -39,7 +39,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index e9c75e1667d..fd8c19234f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -119,6 +119,11 @@ true true false + + <_AndroidXA1042_RunAOTCompilation Condition=" '$(RunAOTCompilation)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + <_AndroidXA1042_EnableLLVM Condition=" '$(EnableLLVM)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + false + false <_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true <_AndroidXA1030 Condition=" '$(RunAOTCompilation)' == 'true' and '$(PublishTrimmed)' == 'false' ">true $(RunAOTCompilation) diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index bc2d9a7d4d4..4b7c0de91fc 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -938,6 +938,15 @@ public static string XA1041 { } } + /// + /// Looks up a localized string similar to The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'". + /// + public static string XA1042 { + get { + return ResourceManager.GetString("XA1042", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in .NET for Android once .NET 6 is released.. /// diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index d1ee02dc051..6d6eb3546f6 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -1007,6 +1007,13 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS The following are literal names and should not be translated: .NET. {0} - The MSBuild property that has the incorrect value. {1} - The current value of the property + + + + The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" + The following are literal names and should not be translated: MSBuild, UseMonoRuntime. +{0} - The MSBuild property name (e.g. RunAOTCompilation, EnableLLVM). +{1} - The name of the .NET runtime (e.g. CoreCLR, NativeAOT). diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index 6a6b91aa900..09d36e7b02a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -492,5 +492,37 @@ public void CheckWhetherLibcAndLibmAreReferencedInAOTLibraries () } } + [Test] + public void RunAOTCompilationWithCoreClrWarnsAndSkipsMonoAot () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.CoreCLR); + proj.SetProperty ("RunAOTCompilation", "true"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("RunAOTCompilation", b.LastBuildOutput, "Build output should mention RunAOTCompilation"); + StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); + } + + [Test] + public void EnableLLVMWithCoreClrWarnsAndIsIgnored () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.CoreCLR); + proj.SetProperty ("EnableLLVM", "true"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("EnableLLVM", b.LastBuildOutput, "Build output should mention EnableLLVM"); + StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); + } + } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index c2527d1954e..e6a46aab923 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -550,6 +550,16 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. ResourceName="XA1030" Condition=" $(_AndroidXA1030) == 'true' " /> + + Date: Fri, 3 Apr 2026 21:30:02 +0000 Subject: [PATCH 03/10] Fix NDK requirement for NativeAOT: add PublishAot condition and dedicated test Agent-Logs-Url: https://github.com/dotnet/android/sessions/1e564b95-24aa-400d-b01f-f153bea868fd Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com> --- .../AndroidDependenciesTests.cs | 20 +++++++++++++++++++ .../Xamarin.Android.Common.targets | 1 + 2 files changed, 21 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index d150196d51c..9bd7e91eed3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -188,6 +188,26 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire } } + [Test] + public void NativeAotRequiresNdk () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.NativeAOT); + using (var builder = CreateApkBuilder ()) { + builder.Verbosity = LoggerVerbosity.Detailed; + builder.Target = "GetAndroidDependencies"; + Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); + IEnumerable taskOutput = builder.LastBuildOutput + .Select (x => x.Trim ()) + .SkipWhile (x => !x.StartsWith ("Task \"CalculateProjectDependencies\"", StringComparison.Ordinal)) + .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) + .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); + StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency for NativeAOT."); + } + } + [Test] public void GetDependencyWhenBuildToolsAreMissingTest ([Values] AndroidRuntime runtime) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index e6a46aab923..754086557d0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2856,6 +2856,7 @@ because xbuild doesn't support framework reference assemblies. <_ProjectAndroidManifest>$(ProjectDir)$(AndroidManifest) <_NdkRequired Condition="'$(EnableLLVM)' == 'True'">true + <_NdkRequired Condition="'$(PublishAot)' == 'true'">true <_NdkRequired Condition="'$(_NdkRequired)' == ''">false From 2c4b57d5858610912fc91b8a439a7685c460eb70 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 13 Apr 2026 11:11:04 -0500 Subject: [PATCH 04/10] Change NDK dependency identity from ndk-bundle to ndk The CalculateProjectDependencies task was emitting 'ndk-bundle' as the AndroidDependency item identity, but modern Android SDK uses side-by-side NDK installed under 'ndk/{version}'. The GoogleV2 manifest doesn't have a component with path 'ndk-bundle', causing InstallAndroidDependencies to fail with 'could not be resolved' warnings. Change the identity to 'ndk' so it matches the GoogleV2 manifest component and resolves correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/CalculateProjectDependencies.cs | 2 +- .../AndroidDependenciesTests.cs | 4 ++-- .../Tasks/GetDependenciesTests.cs | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index 764129c5574..1473f753a95 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,7 +82,7 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { - dependencies.Add (CreateAndroidDependency ("ndk-bundle", NdkVersion)); + dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { javaDependencies.Add (CreateAndroidDependency ("jdk", JdkVersion)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index 9bd7e91eed3..f4ae14e5e90 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -182,9 +182,9 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); if (ndkRequired) - StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency."); + StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency."); else - StringAssertEx.DoesNotContain ("ndk-bundle", taskOutput, "ndk-bundle should not be a dependency."); + StringAssertEx.DoesNotContain ("ndk", taskOutput, "ndk should not be a dependency."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index e466de20a98..4b55dea4fb7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -43,11 +43,11 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); if (ndkRequred) { - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contain a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contain a ndk version 12.1"); } else { - Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle"), - "Dependencies should not contain a ndk-bundle item"); + Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), + "Dependencies should not contain a ndk item"); } Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -80,8 +80,8 @@ public void ManifestFileDoesNotExist () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -121,8 +121,8 @@ public void ManifestFileExists () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk version 12.1"); Directory.Delete (path, recursive: true); } From 7145c4128f2d78e9ebc49f7187d663643e9bdca7 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 13 Apr 2026 14:53:07 -0500 Subject: [PATCH 05/10] Fix NDK dependency identity to use ndk/{version} format Use ndk/{version} (e.g. ndk/27.2.1247901) as the AndroidDependency identity, matching the pattern used by build-tools/{version} and cmdline-tools/{version}. This allows the GoogleV2 manifest to resolve the NDK component correctly. Also fix tests: - Skip GetDependencyNdkRequiredConditions for NativeAOT when ndkRequired=false, since NativeAOT always requires NDK via PublishAot=true - Update NativeAotRequiresNdk assertion from ndk-bundle to ndk/ - Use ndk/ prefix matching in StringAssertEx to avoid false positives Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/CalculateProjectDependencies.cs | 2 +- .../AndroidDependenciesTests.cs | 11 ++++++++--- .../Tasks/GetDependenciesTests.cs | 8 ++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index 1473f753a95..c9692cbf9ec 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,7 +82,7 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { - dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); + dependencies.Add (CreateAndroidDependency ($"ndk/{NdkVersion}", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { javaDependencies.Add (CreateAndroidDependency ("jdk", JdkVersion)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index f4ae14e5e90..a6d061f344f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -166,6 +166,11 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire Assert.Ignore ("NativeAOT doesn't support profiled AOT"); } + // NativeAOT always requires the NDK (PublishAot=true), so ndkRequired=false cases don't apply + if (runtime == AndroidRuntime.NativeAOT && !ndkRequired) { + Assert.Ignore ("NativeAOT always requires NDK via PublishAot=true"); + } + var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, }; @@ -182,9 +187,9 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); if (ndkRequired) - StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency."); + StringAssertEx.Contains ("ndk/", taskOutput, "ndk should be a dependency."); else - StringAssertEx.DoesNotContain ("ndk", taskOutput, "ndk should not be a dependency."); + StringAssertEx.DoesNotContain ("ndk/", taskOutput, "ndk should not be a dependency."); } } @@ -204,7 +209,7 @@ public void NativeAotRequiresNdk () .SkipWhile (x => !x.StartsWith ("Task \"CalculateProjectDependencies\"", StringComparison.Ordinal)) .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); - StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency for NativeAOT."); + StringAssertEx.Contains ("ndk/", taskOutput, "ndk should be a dependency for NativeAOT."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index 4b55dea4fb7..f62ce47e493 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -43,10 +43,10 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); if (ndkRequred) { - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contain a ndk version 12.1"); } else { - Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), + Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec.StartsWith ("ndk/")), "Dependencies should not contain a ndk item"); } Directory.Delete (Path.Combine (Root, path), recursive: true); @@ -80,7 +80,7 @@ public void ManifestFileDoesNotExist () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -121,7 +121,7 @@ public void ManifestFileExists () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); Directory.Delete (path, recursive: true); From 2b468ec4c95c24d927307afd6197f9da3c122f74 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 14 Apr 2026 11:17:21 -0500 Subject: [PATCH 06/10] Revert NDK identity to 'ndk' instead of 'ndk/{version}' The downstream InstallAndroidDependencies task (from android-platform-support) joins the identity and version with a semicolon separator to form the SDK manager path (e.g. ndk;27.2.12479018). Using ndk/{version} as the identity caused a malformed path like 'ndk;27.2.12479018/27.2.12479018' that couldn't be resolved. The correct identity is just 'ndk' with the version in metadata, which produces the expected 'ndk;27.2.12479018' component path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/CalculateProjectDependencies.cs | 2 +- .../AndroidDependenciesTests.cs | 6 +++--- .../Tasks/GetDependenciesTests.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index c9692cbf9ec..1473f753a95 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,7 +82,7 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { - dependencies.Add (CreateAndroidDependency ($"ndk/{NdkVersion}", NdkVersion)); + dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { javaDependencies.Add (CreateAndroidDependency ("jdk", JdkVersion)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index a6d061f344f..b8d09a390b7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -187,9 +187,9 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); if (ndkRequired) - StringAssertEx.Contains ("ndk/", taskOutput, "ndk should be a dependency."); + StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency."); else - StringAssertEx.DoesNotContain ("ndk/", taskOutput, "ndk should not be a dependency."); + StringAssertEx.DoesNotContain ("ndk", taskOutput, "ndk should not be a dependency."); } } @@ -209,7 +209,7 @@ public void NativeAotRequiresNdk () .SkipWhile (x => !x.StartsWith ("Task \"CalculateProjectDependencies\"", StringComparison.Ordinal)) .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); - StringAssertEx.Contains ("ndk/", taskOutput, "ndk should be a dependency for NativeAOT."); + StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency for NativeAOT."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index f62ce47e493..4b55dea4fb7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -43,10 +43,10 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); if (ndkRequred) { - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contain a ndk version 12.1"); } else { - Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec.StartsWith ("ndk/")), + Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), "Dependencies should not contain a ndk item"); } Directory.Delete (Path.Combine (Root, path), recursive: true); @@ -80,7 +80,7 @@ public void ManifestFileDoesNotExist () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -121,7 +121,7 @@ public void ManifestFileExists () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk/12.1" && x.GetMetadata ("Version") == "12.1"), + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); Directory.Delete (path, recursive: true); From fc75a9cf71c601bab793423aa2e565f600debf37 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 15 Apr 2026 11:42:58 -0500 Subject: [PATCH 07/10] Emit both ndk-bundle and ndk as AndroidDependency items The bundled Xamarin manifest uses 'ndk-bundle' as the component path, while the GoogleV2 manifest (once regenerated) will use 'ndk'. Emit both identities so the dependency resolves regardless of which manifest the downstream InstallAndroidDependencies task is configured to use. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/CalculateProjectDependencies.cs | 3 +++ .../Tasks/GetDependenciesTests.cs | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index 1473f753a95..b2d68196f63 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,6 +82,9 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { + // Emit both identities so the dependency resolves against either + // the legacy "ndk-bundle" manifest entries or the modern "ndk" entries. + dependencies.Add (CreateAndroidDependency ("ndk-bundle", NdkVersion)); dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index 4b55dea4fb7..73e12f78634 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -35,7 +35,7 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml")); Assert.IsTrue (task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (ndkRequred ? 4 : 3, task.Dependencies.Length); + Assert.AreEqual (ndkRequred ? 5 : 3, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), @@ -43,9 +43,13 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); if (ndkRequred) { + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contain a ndk-bundle version 12.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contain a ndk version 12.1"); } else { + Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle"), + "Dependencies should not contain a ndk-bundle item"); Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), "Dependencies should not contain a ndk item"); } @@ -73,13 +77,15 @@ public void ManifestFileDoesNotExist () task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml")); Assert.IsTrue (task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (4, task.Dependencies.Length); + Assert.AreEqual (5, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk-bundle version 12.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); @@ -114,13 +120,15 @@ public void ManifestFileExists () task.ManifestFile = new TaskItem (manifestFile); Assert.IsTrue(task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (4, task.Dependencies.Length); + Assert.AreEqual (5, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk-bundle version 12.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk version 12.1"); From 80af176efd6192406031d15ff8908007b721032c Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 15 Apr 2026 15:33:59 -0500 Subject: [PATCH 08/10] Revert NDK identity back to ndk-bundle The bundled manifests in android-platform-support still use ndk-bundle as the component path. Revert to the original identity and only add the NativeAOT-specific test changes: - Skip GetDependencyNdkRequiredConditions for NativeAOT when ndkRequired=false (PublishAot=true always requires NDK) - Add NativeAotRequiresNdk test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/CalculateProjectDependencies.cs | 3 --- .../AndroidDependenciesTests.cs | 6 +++--- .../Tasks/GetDependenciesTests.cs | 14 +++----------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index b2d68196f63..764129c5574 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,10 +82,7 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { - // Emit both identities so the dependency resolves against either - // the legacy "ndk-bundle" manifest entries or the modern "ndk" entries. dependencies.Add (CreateAndroidDependency ("ndk-bundle", NdkVersion)); - dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { javaDependencies.Add (CreateAndroidDependency ("jdk", JdkVersion)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index b8d09a390b7..e55609045ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -187,9 +187,9 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); if (ndkRequired) - StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency."); + StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency."); else - StringAssertEx.DoesNotContain ("ndk", taskOutput, "ndk should not be a dependency."); + StringAssertEx.DoesNotContain ("ndk-bundle", taskOutput, "ndk-bundle should not be a dependency."); } } @@ -209,7 +209,7 @@ public void NativeAotRequiresNdk () .SkipWhile (x => !x.StartsWith ("Task \"CalculateProjectDependencies\"", StringComparison.Ordinal)) .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); - StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency for NativeAOT."); + StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency for NativeAOT."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index 73e12f78634..e466de20a98 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -35,7 +35,7 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml")); Assert.IsTrue (task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (ndkRequred ? 5 : 3, task.Dependencies.Length); + Assert.AreEqual (ndkRequred ? 4 : 3, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), @@ -45,13 +45,9 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) if (ndkRequred) { Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contain a ndk-bundle version 12.1"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contain a ndk version 12.1"); } else { Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle"), "Dependencies should not contain a ndk-bundle item"); - Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), - "Dependencies should not contain a ndk item"); } Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -77,7 +73,7 @@ public void ManifestFileDoesNotExist () task.ManifestFile = new TaskItem (Path.Combine (path, "AndroidManifest.xml")); Assert.IsTrue (task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (5, task.Dependencies.Length); + Assert.AreEqual (4, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), @@ -86,8 +82,6 @@ public void ManifestFileDoesNotExist () "Dependencies should contains a platform-tools version 26.0.3"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk-bundle version 12.1"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -120,7 +114,7 @@ public void ManifestFileExists () task.ManifestFile = new TaskItem (manifestFile); Assert.IsTrue(task.Execute ()); Assert.IsNotNull (task.Dependencies); - Assert.AreEqual (5, task.Dependencies.Length); + Assert.AreEqual (4, task.Dependencies.Length); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "build-tools/26.0.1" && x.GetMetadata ("Version") == "26.0.1"), "Dependencies should contains a build-tools version 26.0.1"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platforms/android-26" && x.GetMetadata ("Version") == ""), @@ -129,8 +123,6 @@ public void ManifestFileExists () "Dependencies should contains a platform-tools version 26.0.3"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), "Dependencies should contains a ndk-bundle version 12.1"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk version 12.1"); Directory.Delete (path, recursive: true); } From 4f264644f93985883af57875ab72a265051cc353 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 15 Apr 2026 15:40:36 -0500 Subject: [PATCH 09/10] Skip InstallAndroidDependenciesTest for GoogleV2+NativeAOT The GoogleV2 manifest from Google does not have an ndk-bundle component, so the NDK dependency cannot be resolved for runtimes that require it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index e55609045ee..c98c394daed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -26,6 +26,12 @@ public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] str return; } + // The GoogleV2 manifest from Google doesn't have an ndk-bundle component, + // so the NDK dependency can't be resolved for runtimes that require it. + if (manifestType == "GoogleV2" && runtime == AndroidRuntime.NativeAOT) { + Assert.Ignore ("GoogleV2 manifest does not have an ndk-bundle component for NativeAOT"); + } + // Set to true when we are marking a new Android API level as stable, but it has not // been added to the Xamarin manifest yet. var xamarin_manifest_needs_updating = false; From 3e108ac081e041ea51386d04a7c6e071ce924ae6 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 17 Apr 2026 12:24:54 -0500 Subject: [PATCH 10/10] Renumber XA1042 to XA1044 to avoid conflict with main XA1042 was already taken on main for a different warning (missing android:name in ). Renumber our Mono-specific property warning to XA1044. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../docs-mobile/messages/{xa1042.md => xa1044.md} | 10 +++++----- .../Microsoft.Android.Sdk.DefaultProperties.targets | 8 ++++---- .../Properties/Resources.Designer.cs | 4 ++-- .../Properties/Resources.resx | 2 +- .../Tests/Xamarin.Android.Build.Tests/AotTests.cs | 4 ++-- .../Xamarin.Android.Common.targets | 12 ++++++------ 6 files changed, 20 insertions(+), 20 deletions(-) rename Documentation/docs-mobile/messages/{xa1042.md => xa1044.md} (86%) diff --git a/Documentation/docs-mobile/messages/xa1042.md b/Documentation/docs-mobile/messages/xa1044.md similarity index 86% rename from Documentation/docs-mobile/messages/xa1042.md rename to Documentation/docs-mobile/messages/xa1044.md index f57c6e6cbd2..331dd99594c 100644 --- a/Documentation/docs-mobile/messages/xa1042.md +++ b/Documentation/docs-mobile/messages/xa1044.md @@ -1,17 +1,17 @@ --- -title: .NET for Android warning XA1042 -description: XA1042 warning code +title: .NET for Android warning XA1044 +description: XA1044 warning code ms.date: 04/02/2026 f1_keywords: - - "XA1042" + - "XA1044" --- -# .NET for Android warning XA1042 +# .NET for Android warning XA1044 ## Example messages ``` -warning XA1042: The MSBuild property 'RunAOTCompilation' is not compatible with the CoreCLR runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" +warning XA1044: The MSBuild property 'RunAOTCompilation' is not compatible with the CoreCLR runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" ``` ## Issue diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index fd8c19234f1..22816880d1b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -120,10 +120,10 @@ true false - <_AndroidXA1042_RunAOTCompilation Condition=" '$(RunAOTCompilation)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true - <_AndroidXA1042_EnableLLVM Condition=" '$(EnableLLVM)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true - false - false + <_AndroidXA1044_RunAOTCompilation Condition=" '$(RunAOTCompilation)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + <_AndroidXA1044_EnableLLVM Condition=" '$(EnableLLVM)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + false + false <_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true <_AndroidXA1030 Condition=" '$(RunAOTCompilation)' == 'true' and '$(PublishTrimmed)' == 'false' ">true $(RunAOTCompilation) diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index e947f7ad6e6..03e8aa2ea48 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -959,9 +959,9 @@ public static string XA1043 { /// /// Looks up a localized string similar to The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'". /// - public static string XA1042 { + public static string XA1044 { get { - return ResourceManager.GetString("XA1042", resourceCulture); + return ResourceManager.GetString("XA1044", resourceCulture); } } diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index 038b1677127..bdfc38d26bc 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -1009,7 +1009,7 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS {1} - The current value of the property - + The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" The following are literal names and should not be translated: MSBuild, UseMonoRuntime. {0} - The MSBuild property name (e.g. RunAOTCompilation, EnableLLVM). diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index 09d36e7b02a..90f43cf6614 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -503,7 +503,7 @@ public void RunAOTCompilationWithCoreClrWarnsAndSkipsMonoAot () using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("warning XA1044", b.LastBuildOutput, "Build output should contain warning XA1044"); StringAssertEx.Contains ("RunAOTCompilation", b.LastBuildOutput, "Build output should mention RunAOTCompilation"); StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); } @@ -519,7 +519,7 @@ public void EnableLLVMWithCoreClrWarnsAndIsIgnored () using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("warning XA1044", b.LastBuildOutput, "Build output should contain warning XA1044"); StringAssertEx.Contains ("EnableLLVM", b.LastBuildOutput, "Build output should mention EnableLLVM"); StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index c2545eaf4f4..8a18a922bb1 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -549,15 +549,15 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. ResourceName="XA1030" Condition=" $(_AndroidXA1030) == 'true' " /> - -