From c35c1d198c0ea0a0d56c67a1faf7e492c49c6cc0 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 6 Mar 2026 10:35:45 -0800 Subject: [PATCH 1/4] Add RunOnAndroid_MauiNativeAOT integration test Add a test that builds a NativeAOT-compiled MAUI app for Android, deploys it to an emulator, and verifies it launches successfully using XHarness. This mirrors the existing RunOniOS_MauiNativeAOT test for iOS and runs in the existing mac_runandroid_tests CI lane. --- .../AndroidTemplateTests.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs index a4115a3f182d..bfa8bde04114 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs @@ -122,6 +122,59 @@ public void RunOnAndroid(string id, string framework, string config, string? tri $"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors."); } + [Fact] + public void RunOnAndroid_MauiNativeAOT() + { + var id = "maui"; + var framework = DotNetCurrent; + var config = "Release"; + + SetTestIdentifier(id, framework, config, "NativeAOT"); + var projectDir = TestDirectory; + var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj"); + + Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), + $"Unable to create template {id}. Check test output for errors."); + + var buildProps = BuildProps; + + // NativeAOT build properties + buildProps.Add("PublishAot=true"); + buildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060 + buildProps.Add("_IsPublishing=true"); + buildProps.Add("IlcTreatWarningsAsErrors=false"); + buildProps.Add("TrimmerSingleWarn=false"); + + // Restrict to Android-only to avoid restoring NativeAOT packages for other platforms (e.g., iOS) + // which may not be available in the configured NuGet sources + buildProps.Add($"TargetFrameworks={framework}-android"); + + // Set Android NDK path if available (required for NativeAOT cross-compilation) + var ndkRoot = Environment.GetEnvironmentVariable("ANDROID_NDK_ROOT"); + if (!string.IsNullOrEmpty(ndkRoot)) + { + var ndkRootEscaped = ndkRoot.Replace("\"", "\\\"", StringComparison.Ordinal); + buildProps.Add($"AndroidNdkDirectory=\"{ndkRootEscaped}\""); + } + + // NativeAOT requires an explicit runtime identifier matching the emulator ABI + var runtimeIdentifier = _emulatorFixture.TestAvd.Abi == "arm64-v8a" ? "android-arm64" : "android-x64"; + + AddInstrumentation(projectDir); + + Assert.True(DotnetInternal.Build(projectFile, config, target: "Install", framework: $"{framework}-android", + properties: buildProps, runtimeIdentifier: runtimeIdentifier, output: _output), + $"Project {Path.GetFileName(projectFile)} failed to build and install. Check test output/attachments for errors."); + + // Write xh-results to the log directory for artifact collection + var xhResultsDir = Path.Combine(TestEnvironment.GetLogDirectory(), "xh-results", Path.GetFileName(projectDir)); + Directory.CreateDirectory(xhResultsDir); + + testPackage = $"com.companyname.{Path.GetFileName(projectDir).ToLowerInvariant()}"; + Assert.True(XHarness.RunAndroid(testPackage, xhResultsDir, -1, output: _output), + $"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors."); + } + void AddInstrumentation(string projectDir) { var androidDir = Path.Combine(projectDir, "Platforms", "Android"); From c5fd7dd82e14e4ee0f8a748ef863135c29a96d67 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 6 Mar 2026 15:14:25 -0800 Subject: [PATCH 2/4] Update src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs index bfa8bde04114..aafb20ba39df 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs @@ -143,7 +143,6 @@ public void RunOnAndroid_MauiNativeAOT() buildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060 buildProps.Add("_IsPublishing=true"); buildProps.Add("IlcTreatWarningsAsErrors=false"); - buildProps.Add("TrimmerSingleWarn=false"); // Restrict to Android-only to avoid restoring NativeAOT packages for other platforms (e.g., iOS) // which may not be available in the configured NuGet sources From 96bcaa30595341acea5cf5ee36b41fc9c2c189f9 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 15:43:14 -0700 Subject: [PATCH 3/4] Remove PublishAotUsingRuntimePack and _IsPublishing from Android NativeAOT test --- .../src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs index aafb20ba39df..42f03b80becd 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs @@ -140,8 +140,6 @@ public void RunOnAndroid_MauiNativeAOT() // NativeAOT build properties buildProps.Add("PublishAot=true"); - buildProps.Add("PublishAotUsingRuntimePack=true"); // TODO: This parameter will become obsolete https://github.com/dotnet/runtime/issues/87060 - buildProps.Add("_IsPublishing=true"); buildProps.Add("IlcTreatWarningsAsErrors=false"); // Restrict to Android-only to avoid restoring NativeAOT packages for other platforms (e.g., iOS) From ce0155ea09b1d2f5f60403e3c5f15fbf09f73463 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 7 Apr 2026 15:50:44 -0700 Subject: [PATCH 4/4] Reuse PrepareNativeAotBuildPropsAndroid shared helper and update PR description --- .../AOTTemplateTest.cs | 8 ++++---- .../AndroidTemplateTests.cs | 14 +------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs index 8ded0f18f133..9dc037afa74c 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AOTTemplateTest.cs @@ -44,7 +44,7 @@ public void PublishNativeAOT(string id, string framework, string runtimeIdentifi var extendedBuildProps = isWindowsFramework ? PrepareNativeAotBuildPropsWindows(runtimeIdentifier) : isAndroidPlatform - ? PrepareNativeAotBuildPropsAndroid() + ? PrepareNativeAotBuildPropsAndroid(BuildProps) : PrepareNativeAotBuildProps(); // Disable code signing for Apple platforms (no signing certificate available in CI) @@ -105,7 +105,7 @@ public void PublishNativeAOTRootAllMauiAssemblies(string id, string framework, s var extendedBuildProps = isWindowsFramework ? PrepareNativeAotBuildPropsWindows(runtimeIdentifier) : isAndroidPlatform - ? PrepareNativeAotBuildPropsAndroid() + ? PrepareNativeAotBuildPropsAndroid(BuildProps) : PrepareNativeAotBuildProps(); // Disable code signing for Apple platforms (no signing certificate available in CI) @@ -180,9 +180,9 @@ private List PrepareNativeAotBuildPropsWindows(string runtimeIdentifier) return extendedBuildProps; } - private List PrepareNativeAotBuildPropsAndroid() + internal static List PrepareNativeAotBuildPropsAndroid(List buildProps) { - var extendedBuildProps = new List(BuildProps) + var extendedBuildProps = new List(buildProps) { "PublishAot=true", "PublishAotUsingRuntimePack=true", diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs index 42f03b80becd..4b6eea0ba2d3 100644 --- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs +++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs @@ -136,24 +136,12 @@ public void RunOnAndroid_MauiNativeAOT() Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output), $"Unable to create template {id}. Check test output for errors."); - var buildProps = BuildProps; - - // NativeAOT build properties - buildProps.Add("PublishAot=true"); - buildProps.Add("IlcTreatWarningsAsErrors=false"); + var buildProps = AOTTemplateTest.PrepareNativeAotBuildPropsAndroid(BuildProps); // Restrict to Android-only to avoid restoring NativeAOT packages for other platforms (e.g., iOS) // which may not be available in the configured NuGet sources buildProps.Add($"TargetFrameworks={framework}-android"); - // Set Android NDK path if available (required for NativeAOT cross-compilation) - var ndkRoot = Environment.GetEnvironmentVariable("ANDROID_NDK_ROOT"); - if (!string.IsNullOrEmpty(ndkRoot)) - { - var ndkRootEscaped = ndkRoot.Replace("\"", "\\\"", StringComparison.Ordinal); - buildProps.Add($"AndroidNdkDirectory=\"{ndkRootEscaped}\""); - } - // NativeAOT requires an explicit runtime identifier matching the emulator ABI var runtimeIdentifier = _emulatorFixture.TestAvd.Abi == "arm64-v8a" ? "android-arm64" : "android-x64";