diff --git a/eng/pipelines/arcade/setup-test-env.yml b/eng/pipelines/arcade/setup-test-env.yml
index 18c62294314b..b1e74bc2f611 100644
--- a/eng/pipelines/arcade/setup-test-env.yml
+++ b/eng/pipelines/arcade/setup-test-env.yml
@@ -11,6 +11,8 @@ steps:
fetchDepth: 1
clean: true
+- template: /eng/pipelines/common/enable-kvm.yml@self
+
- template: /eng/pipelines/common/provision.yml@self
parameters:
checkoutDirectory: '$(System.DefaultWorkingDirectory)'
diff --git a/eng/pipelines/ci.yml b/eng/pipelines/ci.yml
index ef9fd452abd8..58b1ba5dbb67 100644
--- a/eng/pipelines/ci.yml
+++ b/eng/pipelines/ci.yml
@@ -108,6 +108,13 @@ parameters:
- ImageOverride -equals ACES_VM_SharedPool_Tahoe
label: macOS
+- name: AndroidPoolLinux
+ type: object
+ default:
+ name: MAUI-DNCENG
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+
# Condition for MacOSPool comparison lanes (non-ARM64)
# Runs on: (non-PR on main/net*.0/release/*/inflight/*) OR (PR targeting net*.0/release/*/inflight/*)
@@ -277,12 +284,9 @@ stages:
# TODO: macOSTemplates and AOT template categories
- name: mac_runandroid_tests
${{ if eq(variables['Build.DefinitionName'], 'maui-pr') }}:
- pool:
- name: AcesShared
- demands:
- - ImageOverride -equals ACES_arm64_Sequoia_Xcode
+ pool: ${{ parameters.AndroidPoolLinux }}
${{ else }}:
- pool: ${{ parameters.MacOSPool.internal }}
+ pool: ${{ parameters.AndroidPoolLinux }}
timeout: 240
testCategory: RunOnAndroid
diff --git a/eng/pipelines/common/device-tests-steps.yml b/eng/pipelines/common/device-tests-steps.yml
index 8a59c42d73a5..46a7f09f147c 100644
--- a/eng/pipelines/common/device-tests-steps.yml
+++ b/eng/pipelines/common/device-tests-steps.yml
@@ -35,14 +35,8 @@ steps:
continueOnError: true
timeoutInMinutes: 60
-# Enable KVM for Android builds on Linux
- ${{ if and(ne(parameters.buildType, 'buildOnly'), eq(parameters.platform, 'android')) }}:
- - bash: |
- echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
- sudo udevadm control --reload-rules
- sudo udevadm trigger --name-match=kvm
- displayName: Enable KVM
- condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+ - template: enable-kvm.yml
# Provision the various SDKs that are needed
- template: provision.yml
diff --git a/eng/pipelines/common/enable-kvm.yml b/eng/pipelines/common/enable-kvm.yml
new file mode 100644
index 000000000000..9bb2050cc14c
--- /dev/null
+++ b/eng/pipelines/common/enable-kvm.yml
@@ -0,0 +1,8 @@
+# Enable KVM for Android tests on Linux
+steps:
+- bash: |
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
+ sudo udevadm control --reload-rules
+ sudo udevadm trigger --name-match=kvm
+ displayName: Enable KVM
+ condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
diff --git a/eng/pipelines/common/ui-tests-steps.yml b/eng/pipelines/common/ui-tests-steps.yml
index aad3e127a5d7..42461d1521f2 100644
--- a/eng/pipelines/common/ui-tests-steps.yml
+++ b/eng/pipelines/common/ui-tests-steps.yml
@@ -43,14 +43,8 @@ steps:
continueOnError: true
timeoutInMinutes: 60
-# Enable KVM for Android builds on Linux
- ${{ if and(ne(parameters.buildType, 'buildOnly'), eq(parameters.platform, 'android')) }}:
- - bash: |
- echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
- sudo udevadm control --reload-rules
- sudo udevadm trigger --name-match=kvm
- displayName: Enable KVM
- condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+ - template: enable-kvm.yml
- ${{ if eq(parameters.platform, 'catalyst')}}:
- bash: |
diff --git a/src/DotNet/DotNet.csproj b/src/DotNet/DotNet.csproj
index 5cab15a090ed..4e4e92feec35 100644
--- a/src/DotNet/DotNet.csproj
+++ b/src/DotNet/DotNet.csproj
@@ -78,7 +78,9 @@
<_WorkloadSource Include="$(NugetArtifactsPath)" />
- <_LocalWorkloadIds Include="maui" />
+
+ <_LocalWorkloadIds Include="maui-android" Condition="$([MSBuild]::IsOSPlatform('linux'))" />
+ <_LocalWorkloadIds Include="maui" Condition="!$([MSBuild]::IsOSPlatform('linux'))" />
<_LocalWorkloadIds Include="tizen" Condition=" '$(IncludeTizenTargetFrameworks)' == 'true' " />
diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs
index 2e8027bcfdfd..a4115a3f182d 100644
--- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs
+++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/AndroidTemplateTests.cs
@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
using Microsoft.Maui.IntegrationTests.Android;
namespace Microsoft.Maui.IntegrationTests
@@ -94,6 +95,12 @@ public void RunOnAndroid(string id, string framework, string config, string? tri
Assert.True(DotnetInternal.New(id, projectDir, framework, output: _output),
$"Unable to create template {id}. Check test output for errors.");
+ // On Linux, only the maui-android workload is installed. Previous .NET
+ // templates may still include iOS/macOS TFMs causing NETSDK1178 errors
+ // during restore. Strip them so only Android remains.
+ if (TestEnvironment.IsLinux)
+ StripNonAndroidTfms(projectFile, framework);
+
var buildProps = BuildProps;
if (!string.IsNullOrEmpty(trimMode))
{
@@ -128,5 +135,20 @@ void AddInstrumentation(string projectDir)
"MainLauncher = true, Name = \"com.microsoft.mauitemplate.MainActivity\"");
}
+ static void StripNonAndroidTfms(string projectFile, string framework)
+ {
+ var content = File.ReadAllText(projectFile);
+ var androidTfm = $"{framework}-android";
+ // Remove conditional TargetFrameworks lines (iOS/macOS/Windows additions)
+ content = Regex.Replace(content,
+ @"\s*[^<]*",
+ "");
+ // Set the base TargetFrameworks to Android only
+ content = Regex.Replace(content,
+ @"[^<]*",
+ $"{androidTfm}");
+ File.WriteAllText(projectFile, content);
+ }
+
}
}