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 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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);