Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions Documentation/docs-mobile/messages/xa1040.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,23 @@ ms.date: 02/24/2025
## Example messages

```
warning XA1040: The CoreCLR runtime on Android is an experimental feature and not yet suitable for production use. File issues at: https://github.com/dotnet/android/issues
warning XA1040: The NativeAOT runtime on Android is an experimental feature and not yet suitable for production use. File issues at: https://github.com/dotnet/android/issues
```

## Issue

MonoVM is the default, supported runtime for .NET for Android.
CoreCLR is the default, supported runtime for .NET for Android. Mono is also supported.

Other runtimes are currently experimental, such as:
You can opt into other runtimes via:

* CoreCLR, used via `$(UseMonoRuntime)=false`
* CoreCLR, default
* MonoVM, used via `$(UseMonoRuntime)=true`
* NativeAOT, used via `$(PublishAot)=true`

## Solution

To silence this warning, you can either:

* Use MonoVM by removing `$(UseMonoRuntime)=false` or
`$(PublishAot)=true` from your project file.
* Use CoreCLR by removing `$(PublishAot)=true` from your project file.

* Set `$(EnablePreviewFeatures)` to `true` in your project file.
10 changes: 5 additions & 5 deletions build-tools/automation/yaml-templates/stage-package-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ stages:
testName: Mono.Android.NET_Tests-Interpreter
project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)Interpreter.xml
extraBuildArgs: -p:TestsFlavor=Interpreter -p:UseInterpreter=True
extraBuildArgs: -p:TestsFlavor=Interpreter -p:UseInterpreter=True -p:UseMonoRuntime=true
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-Interpreter

Expand Down Expand Up @@ -154,7 +154,7 @@ stages:
testName: Mono.Android.NET_Tests-NoAot
project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)NoAot.xml
extraBuildArgs: -p:TestsFlavor=NoAot -p:RunAOTCompilation=false
extraBuildArgs: -p:TestsFlavor=NoAot -p:RunAOTCompilation=false -p:UseMonoRuntime=true
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-NoAot

Expand All @@ -164,7 +164,7 @@ stages:
testName: Mono.Android.NET_Tests-TrimModePartial
project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)TrimModePartial.xml
extraBuildArgs: -p:TestsFlavor=TrimModePartial -p:TrimMode=partial
extraBuildArgs: -p:TestsFlavor=TrimModePartial -p:TrimMode=partial -p:UseMonoRuntime=true
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-TrimModePartial

Expand All @@ -174,7 +174,7 @@ stages:
testName: Mono.Android.NET_Tests-AotLlvm
project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)AotLlvm.xml
extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLLVM=true -p:AndroidEnableProfiledAot=false
extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLLVM=true -p:AndroidEnableProfiledAot=false -p:UseMonoRuntime=true
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-AotLlvm

Expand All @@ -184,7 +184,7 @@ stages:
testName: Mono.Android.NET_Tests-IsAssignableFrom
project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)IsAssignableFrom.xml
extraBuildArgs: -p:TestsFlavor=IsAssignableFrom -p:IncludeCategories=Intune -p:_AndroidIsAssignableFromCheck=false
extraBuildArgs: -p:TestsFlavor=IsAssignableFrom -p:IncludeCategories=Intune -p:_AndroidIsAssignableFromCheck=false -p:UseMonoRuntime=true
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-IsAssignableFrom

Expand Down
2 changes: 1 addition & 1 deletion build-tools/scripts/TestApks.targets
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<PropertyGroup>
<!-- APK tests might run on 32-bit emulators -->
<RuntimeIdentifiers Condition=" '$(RuntimeIdentifier)' == '' and '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' != 'false' ">android-arm64;android-x86;android-x64;</RuntimeIdentifiers>
<RuntimeIdentifiers Condition=" '$(RuntimeIdentifier)' == '' and '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' == 'true' ">android-arm64;android-x86;android-x64;</RuntimeIdentifiers>
<TestAvdApiLevel Condition=" '$(TestAvdApiLevel)' == '' ">29</TestAvdApiLevel>
<TestAvdAbi Condition=" '$(TestAvdAbi)' == '' and '$(HostOS)' == 'Darwin' and '$(HostOSArchitecture)' == 'Arm64' ">arm64-v8a</TestAvdAbi>
<TestAvdAbi Condition=" '$(TestAvdAbi)' == '' ">x86_64</TestAvdAbi>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16
-->
<_GetChildProjectCopyToPublishDirectoryItems>false</_GetChildProjectCopyToPublishDirectoryItems>
<UseMonoRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' == '' ">false</UseMonoRuntime>
<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == '' ">true</UseMonoRuntime>
<_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' != 'true' ">NativeAOT</_AndroidRuntime>
<_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' != 'true' ">CoreCLR</_AndroidRuntime>
<_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">MonoVM</_AndroidRuntime>
<_AndroidRuntime Condition=" '$(PublishAot)' == 'true' ">NativeAOT</_AndroidRuntime>
<_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' == 'true' ">MonoVM</_AndroidRuntime>
<_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">CoreCLR</_AndroidRuntime>
<PublishAotUsingRuntimePack Condition=" '$(PublishAotUsingRuntimePack)' == '' and '$(_AndroidRuntime)' == 'NativeAOT' ">true</PublishAotUsingRuntimePack>

<!-- Use $(AndroidMinimumSupportedApiLevel) for $(SupportedOSPlatformVersion) if unset -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ public void BuildAotApplicationWithSpecialCharactersInProject (string testName,
IsRelease = isRelease,
AotAssemblies = aot,
};
proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64");
using (var builder = CreateApkBuilder (Path.Combine (rootPath, proj.ProjectName))){
Assert.IsTrue (builder.Build (proj), "Build should have succeeded.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b
IsRelease = !debugBuild,
};

// Mono-only test
proj.SetRuntime (AndroidRuntime.MonoVM);
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidEnableProfiler", enableProfiler.ToString ());
proj.SetProperty (proj.ActiveConfigurationProperties, "UseInterpreter", useInterpreter.ToString ());

Expand All @@ -260,65 +262,64 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b
string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);

List<EnvironmentHelper.EnvironmentFile> envFiles = EnvironmentHelper.GatherEnvironmentFiles (objPath, String.Join (";", abis), true);
EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles);
var app_config = (EnvironmentHelper.ApplicationConfig_MonoVM)EnvironmentHelper.ReadApplicationConfig (envFiles, AndroidRuntime.MonoVM);
Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files");
Assert.IsTrue (app_config.mono_components_mask == expectedMask, "Expected Mono Components mask 0x{expectedMask:x}, got 0x{app_config.mono_components_mask:x}");
}
}

static object [] CheckAssemblyCountsSource = new object [] {
new object[] {
/*isRelease*/ false,
/*aot*/ false,
},
new object[] {
/*isRelease*/ true,
/*aot*/ false,
},
new object[] {
/*isRelease*/ true,
/*aot*/ true,
},
};

[Test]
[TestCaseSource (nameof (CheckAssemblyCountsSource))]
[NonParallelizable]
public void CheckAssemblyCounts (bool isRelease, bool aot)
public void CheckAssemblyCounts ([Values (true, false)] bool isRelease, [Values (true, false)] bool aot,
[Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime)
{
if (isRelease == false && aot == true) {
Assert.Ignore ("Not testing AOT with Debug builds");
return;
}

bool aotAssemblies = aot && runtime == AndroidRuntime.MonoVM;
var proj = new XamarinFormsAndroidApplicationProject {
IsRelease = isRelease,
EmbedAssembliesIntoApk = true,
AotAssemblies = aot,
AotAssemblies = aotAssemblies,
};
proj.SetRuntime (runtime);

var abis = new [] { "armeabi-v7a", "x86" };
proj.SetRuntimeIdentifiers (abis);
var targetArches = new [] { AndroidTargetArch.Arm64, AndroidTargetArch.X86_64 };
var abis = targetArches.Select (arch => MonoAndroidHelper.ArchToAbi (arch));

proj.SetRuntimeIdentifiers (targetArches);
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidUseAssemblyStore", "True");

using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);

List<EnvironmentHelper.EnvironmentFile> envFiles = EnvironmentHelper.GatherEnvironmentFiles (objPath, String.Join (";", abis), true);
EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles);
EnvironmentHelper.IApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles, runtime);
Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files");

if (aot) {
if (aotAssemblies) {
foreach (var env in envFiles) {
StringAssert.Contains ("libaot-Mono.Android.dll.so", File.ReadAllText (env.Path));
}
}

string apk = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk");
var helper = new ArchiveAssemblyHelper (apk, useAssemblyStores: true);
uint numberOfAssembliesInApk = runtime switch {
AndroidRuntime.MonoVM => ((EnvironmentHelper.ApplicationConfig_MonoVM)app_config).number_of_assemblies_in_apk,
AndroidRuntime.CoreCLR => ((EnvironmentHelper.ApplicationConfig_CoreCLR)app_config).number_of_assemblies_in_apk,
_ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'")
};

foreach (string abi in abis) {
AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi);
foreach (AndroidTargetArch arch in targetArches) {
Assert.AreEqual (
app_config.number_of_assemblies_in_apk,
numberOfAssembliesInApk,
helper.GetNumberOfAssemblies (arch: arch),
$"Assembly count must be equal between ApplicationConfig and the archive contents for architecture {arch} (ABI: {abi})"
$"Assembly count must be equal between ApplicationConfig and the archive contents for architecture {arch} (ABI: {MonoAndroidHelper.ArchToAbi (arch)})"
);
}
}
Expand Down Expand Up @@ -355,6 +356,8 @@ public static string GetLinkedPath (ProjectBuilder builder, bool isRelease, stri
[TestCaseSource (nameof (RuntimeChecks))]
public void CheckWhichRuntimeIsIncluded (string supportedAbi, bool debugSymbols, bool? optimize, bool? embedAssemblies, string expectedRuntime) {
var proj = new XamarinAndroidApplicationProject ();
// MonoVM-only test
proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM);
proj.SetAndroidSupportedAbis (supportedAbi);
proj.SetProperty (proj.ActiveConfigurationProperties, "DebugSymbols", debugSymbols);
if (optimize.HasValue)
Expand Down Expand Up @@ -1300,7 +1303,6 @@ public void EnvironmentVariables (bool useInterpreter, string packageNamingPolic
proj.SetProperty ("AndroidPackageNamingPolicy", packageNamingPolicy);
if (!string.IsNullOrEmpty (diagnosticConfiguration))
proj.SetProperty ("DiagnosticConfiguration", diagnosticConfiguration);
proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86");
using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "build should have succeeded.");
var environment = b.Output.GetIntermediaryPath (Path.Combine ("__environment__.txt"));
Expand Down Expand Up @@ -1704,16 +1706,23 @@ public void CheckLintResourceFileReferencesAreFixed ()
}

[Test]
public void SimilarAndroidXAssemblyNames ([Values(true, false)] bool publishTrimmed)
[TestCase (true, AndroidRuntime.MonoVM)]
[TestCase (false, AndroidRuntime.MonoVM)]
[TestCase (true, AndroidRuntime.CoreCLR)]
[TestCase (false, AndroidRuntime.CoreCLR)]
// TODO: [TestCase (false, AndroidRuntime.NativeAOT)]
public void SimilarAndroidXAssemblyNames (bool publishTrimmed, AndroidRuntime runtime)
{
bool aotAssemblies = runtime == AndroidRuntime.MonoVM && publishTrimmed;
var proj = new XamarinAndroidApplicationProject {
IsRelease = true,
AotAssemblies = publishTrimmed,
AotAssemblies = aotAssemblies,
PackageReferences = {
new Package { Id = "Xamarin.AndroidX.CustomView", Version = "1.1.0.17" },
new Package { Id = "Xamarin.AndroidX.CustomView.PoolingContainer", Version = "1.0.0.4" },
}
};
proj.SetRuntime (runtime);
proj.SetProperty (KnownProperties.PublishTrimmed, publishTrimmed.ToString());
proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "AndroidX.CustomView.PoolingContainer.PoolingContainer.IsPoolingContainer (null);");
using var builder = CreateApkBuilder ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public void MarshalMethodsDefaultEnabledStatus (bool isRelease, bool marshalMeth
IsRelease = isRelease,
EnableMarshalMethods = marshalMethodsEnabled,
};
// MonoVM-only test
proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM);
proj.SetRuntimeIdentifiers (abis);
bool shouldMarshalMethodsBeEnabled = isRelease && marshalMethodsEnabled;

Expand All @@ -68,7 +70,7 @@ public void MarshalMethodsDefaultEnabledStatus (bool isRelease, bool marshalMeth
String.Join (";", supportedArches.Select (arch => MonoAndroidHelper.ArchToAbi (arch))),
true
);
EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles);
var app_config = (EnvironmentHelper.ApplicationConfig_MonoVM)EnvironmentHelper.ReadApplicationConfig (envFiles, Android.Tasks.AndroidRuntime.MonoVM);

Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files");
Assert.AreEqual (app_config.marshal_methods_enabled, shouldMarshalMethodsBeEnabled, $"Marshal methods enabled status should be '{shouldMarshalMethodsBeEnabled}', but it was '{app_config.marshal_methods_enabled}'");
Expand Down
Loading
Loading