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
31 changes: 31 additions & 0 deletions Documentation/docs-mobile/messages/xa1042.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: .NET for Android error XA1042
description: XA1042 error code
ms.date: 01/29/2026
---
# .NET for Android error XA1042

## Example messages

```
The 'AndroidHttpClientHandlerType' property is deprecated and not supported with NativeAOT. The property value 'System.Net.Http.SocketsHttpHandler, System.Net.Http' will be ignored, and the default handler 'Xamarin.Android.Net.AndroidMessageHandler' will be used. Remove the 'AndroidHttpClientHandlerType' property from your project file. To use a custom HTTP handler, pass it to the HttpClient constructor.
```

## Issue

The `AndroidHttpClientHandlerType` MSBuild property is not compatible with NativeAOT because type name resolution at runtime requires reflection, which cannot be safely used with ahead-of-time compilation.

When targeting NativeAOT, the default `Xamarin.Android.Net.AndroidMessageHandler` handler will always be used regardless of the `AndroidHttpClientHandlerType` property value.

## Solution

Remove the `AndroidHttpClientHandlerType` property from your project file.

If you need to use a custom HTTP message handler, pass it directly to the `HttpClient` constructor:

```csharp
var handler = new MyCustomHttpHandler();
var client = new HttpClient(handler);
```

This approach is compatible with all .NET for Android runtimes including NativeAOT, CoreCLR, and MonoVM.
29 changes: 29 additions & 0 deletions Documentation/docs-mobile/messages/xa1043.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: .NET for Android warning XA1043
description: XA1043 warning code
ms.date: 01/29/2026
---
# .NET for Android warning XA1043

## Example messages

```
The 'AndroidHttpClientHandlerType' property is deprecated and will be removed in a future version of .NET for Android. The property value 'System.Net.Http.SocketsHttpHandler, System.Net.Http' will be used, but the recommended approach is to remove the property and pass a custom HTTP handler to the HttpClient constructor if needed.
```

## Issue

The `AndroidHttpClientHandlerType` MSBuild property is deprecated because it relies on runtime type name resolution which is not compatible with trimming and ahead-of-time compilation. While the property still works for MonoVM and CoreCLR runtimes, it will be removed in a future version of .NET for Android.

## Solution

Remove the `AndroidHttpClientHandlerType` property from your project file.

If you need to use a custom HTTP message handler, pass it directly to the `HttpClient` constructor:

```csharp
var handler = new MyCustomHttpHandler();
var client = new HttpClient(handler);
```

This approach is compatible with all .NET for Android runtimes including NativeAOT, CoreCLR, and MonoVM, and works correctly with trimming and ahead-of-time compilation.
31 changes: 31 additions & 0 deletions Documentation/docs-mobile/messages/xa1044.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: .NET for Android warning XA1044
description: XA1044 warning code
ms.date: 01/29/2026
---
# .NET for Android warning XA1044

## Example messages

```
The 'XA_HTTP_CLIENT_HANDLER_TYPE' environment variable is deprecated and will be removed in a future version of .NET for Android. Remove the environment variable from your @(AndroidEnvironment) files. To use a custom HTTP handler, pass it to the HttpClient constructor.
```

## Issue

The `XA_HTTP_CLIENT_HANDLER_TYPE` environment variable is deprecated because it relies on runtime type name resolution which is not compatible with trimming and ahead-of-time compilation.

This warning is raised when the build system detects that an `@(AndroidEnvironment)` file contains the `XA_HTTP_CLIENT_HANDLER_TYPE` environment variable.

## Solution

Remove the `XA_HTTP_CLIENT_HANDLER_TYPE` environment variable from your `@(AndroidEnvironment)` files.

If you need to use a custom HTTP message handler, pass it directly to the `HttpClient` constructor:

```csharp
var handler = new MyCustomHttpHandler();
var client = new HttpClient(handler);
```

This approach is compatible with all .NET for Android runtimes including NativeAOT, CoreCLR, and MonoVM, and works correctly with trimming and ahead-of-time compilation.
11 changes: 11 additions & 0 deletions src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Java.Net;
using Java.Security;
using Javax.Net.Ssl;
using Microsoft.Android.Runtime;

namespace Android.Runtime {

Expand Down Expand Up @@ -245,6 +246,16 @@ static void DetectCPUAndArchitecture (out ushort builtForCPU, out ushort running
// DO NOT REMOVE
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))]
static HttpMessageHandler GetHttpMessageHandler ()
{
if (!RuntimeFeature.XaHttpClientHandlerType) {
return new Xamarin.Android.Net.AndroidMessageHandler ();
}

return GetHttpMessageHandlerFromEnvironment ();
}

[RequiresUnreferencedCode ("The handler type specified in XA_HTTP_CLIENT_HANDLER_TYPE might be removed by the trimmer.")]
static HttpMessageHandler GetHttpMessageHandlerFromEnvironment ()
{
[UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Preserved by the MarkJavaObjects trimmer step.")]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
Expand Down
2 changes: 2 additions & 0 deletions src/Mono.Android/ILLink/ILLink.Substitutions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<type fullname="Microsoft.Android.Runtime.RuntimeFeature">
<method signature="System.Boolean get_ManagedTypeMap()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.ManagedTypeMap" featurevalue="false" value="false" />
<method signature="System.Boolean get_ManagedTypeMap()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.ManagedTypeMap" featurevalue="true" value="true" />
<method signature="System.Boolean get_XaHttpClientHandlerType()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.XaHttpClientHandlerType" featurevalue="false" value="false" />
<method signature="System.Boolean get_XaHttpClientHandlerType()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.XaHttpClientHandlerType" featurevalue="true" value="true" />
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ static class RuntimeFeature
const bool IsCoreClrRuntimeEnabledByDefault = false;
const bool IsAssignableFromCheckEnabledByDefault = true;
const bool StartupHookSupportEnabledByDefault = true;
const bool XaHttpClientHandlerTypeEnabledByDefault = false;

const string FeatureSwitchPrefix = "Microsoft.Android.Runtime.RuntimeFeature.";
const string StartupHookProviderSwitch = "System.StartupHookProvider.IsSupported";
Expand All @@ -34,4 +35,9 @@ static class RuntimeFeature
[FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))]
internal static bool StartupHookSupport { get; } =
AppContext.TryGetSwitch (StartupHookProviderSwitch, out bool isEnabled) ? isEnabled : StartupHookSupportEnabledByDefault;

[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (XaHttpClientHandlerType)}")]
[FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))]
internal static bool XaHttpClientHandlerType { get; } =
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (XaHttpClientHandlerType)}", out bool isEnabled) ? isEnabled : XaHttpClientHandlerTypeEnabledByDefault;
Comment on lines +39 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simonrozsival can we use the existing feature switch, and we don't need a new one?

We'd duplicate it in this file like we did StartupHookProvider.IsSupported.

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<MonoAndroidAssetsPrefix Condition=" '$(MonoAndroidAssetsPrefix)' == '' ">Assets</MonoAndroidAssetsPrefix>
<AndroidResgenClass Condition=" '$(AndroidResgenClass)' == '' ">Resource</AndroidResgenClass>
<AndroidEnableSGenConcurrent Condition=" '$(AndroidEnableSGenConcurrent)' == '' ">true</AndroidEnableSGenConcurrent>
<AndroidHttpClientHandlerType Condition=" '$(AndroidHttpClientHandlerType)' == '' ">Xamarin.Android.Net.AndroidMessageHandler</AndroidHttpClientHandlerType>
<!-- AndroidHttpClientHandlerType is deprecated and should no longer be set. See XA1034 warning. -->
<AndroidGenerateResourceDesigner Condition=" '$(AndroidGenerateResourceDesigner)' == '' ">true</AndroidGenerateResourceDesigner>
<AndroidUseDesignerAssembly Condition=" '$(AndroidUseDesignerAssembly)' == '' ">true</AndroidUseDesignerAssembly>
<AndroidUseIntermediateDesignerFile Condition=" '$(AndroidUseDesignerAssembly)' == 'True' ">false</AndroidUseIntermediateDesignerFile>
Expand Down Expand Up @@ -133,7 +133,7 @@
<Http3Support Condition="'$(Http3Support)' == ''">false</Http3Support>
<InvariantGlobalization Condition="'$(InvariantGlobalization)' == ''">false</InvariantGlobalization>
<UseSizeOptimizedLinq Condition="'$(UseSizeOptimizedLinq)' == ''">true</UseSizeOptimizedLinq>
<UseNativeHttpHandler Condition=" $(AndroidHttpClientHandlerType.Contains ('System.Net.Http.SocketsHttpHandler')) And '$(UseNativeHttpHandler)' == '' ">false</UseNativeHttpHandler>
<UseNativeHttpHandler Condition=" '$(AndroidHttpClientHandlerType)' != '' And $(AndroidHttpClientHandlerType.Contains ('System.Net.Http.SocketsHttpHandler')) And '$(UseNativeHttpHandler)' == '' ">false</UseNativeHttpHandler>
<UseNativeHttpHandler Condition="'$(UseNativeHttpHandler)' == ''">true</UseNativeHttpHandler>
<BuiltInComInteropSupport Condition="'$(BuiltInComInteropSupport)' == ''">false</BuiltInComInteropSupport>
<JsonSerializerIsReflectionEnabledByDefault Condition="'$(JsonSerializerIsReflectionEnabledByDefault)' == '' and '$(TrimMode)' == 'partial'">true</JsonSerializerIsReflectionEnabledByDefault>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f
Value="$([MSBuild]::ValueOrDefault('$(_AndroidUseManagedTypeMap)', 'false'))"
Trim="true"
/>
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.XaHttpClientHandlerType"
Value="$([MSBuild]::ValueOrDefault('$(_AndroidUseXaHttpClientHandlerType)', 'false'))"
Trim="true"
/>
<RuntimeHostConfigurationOption Include="Microsoft.Android.Runtime.RuntimeFeature.IsAssignableFromCheck"
Condition="'$(_AndroidIsAssignableFromCheck)' != ''"
Value="$(_AndroidIsAssignableFromCheck)"
Expand Down
14 changes: 14 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,20 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS
{1} - The current value of the property
</comment>
</data>
<data name="XA1042" xml:space="preserve">
<value>The 'AndroidHttpClientHandlerType' property is deprecated and not supported with NativeAOT. The property value '{0}' will be ignored, and the default handler 'Xamarin.Android.Net.AndroidMessageHandler' will be used. Remove the 'AndroidHttpClientHandlerType' property from your project file. To use a custom HTTP handler, pass it to the HttpClient constructor.</value>
<comment>The following are literal names and should not be translated: 'AndroidHttpClientHandlerType', 'NativeAOT', 'Xamarin.Android.Net.AndroidMessageHandler', 'HttpClient'.
{0} - The value of the AndroidHttpClientHandlerType property.</comment>
</data>
<data name="XA1043" xml:space="preserve">
<value>The 'AndroidHttpClientHandlerType' property is deprecated and will be removed in a future version of .NET for Android. The property value '{0}' will be used, but the recommended approach is to remove the property and pass a custom HTTP handler to the HttpClient constructor if needed.</value>
<comment>The following are literal names and should not be translated: 'AndroidHttpClientHandlerType', 'HttpClient'.
{0} - The value of the AndroidHttpClientHandlerType property.</comment>
</data>
<data name="XA1044" xml:space="preserve">
<value>The 'XA_HTTP_CLIENT_HANDLER_TYPE' environment variable is deprecated and will be removed in a future version of .NET for Android. Remove the environment variable from your @(AndroidEnvironment) files. To use a custom HTTP handler, pass it to the HttpClient constructor.</value>
<comment>The following are literal names and should not be translated: 'XA_HTTP_CLIENT_HANDLER_TYPE', '@(AndroidEnvironment)', 'HttpClient'.</comment>
</data>
<data name="XA4241" xml:space="preserve">
<value>Java dependency '{0}' is not satisfied.</value>
<comment>The following are literal names and should not be translated: Java.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,11 @@ public void CheckConcurrentGC ()
}

[Test]
public void CheckForInvalidHttpClientHandlerType ([Values] AndroidRuntime runtime)
public void CheckForInvalidHttpClientHandlerType ()
{
// Test with MonoVM only since NativeAOT will fail with XA1042 before reaching XA1031
const bool isRelease = true;
var runtime = AndroidRuntime.MonoVM;
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
return;
}
Expand All @@ -177,13 +179,38 @@ public void CheckForInvalidHttpClientHandlerType ([Values] AndroidRuntime runtim
proj.SetProperty ("AndroidHttpClientHandlerType", "Android.App.Application");
Assert.IsFalse (b.Build (proj), "Build should not have succeeded.");
Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, "XA1031"), "Output should contain XA1031");
// Also expect deprecation warning
Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, "XA1043"), "Output should contain XA1043 deprecation warning");
}
}

[Test]
public void CheckHttpClientHandlerType ([Values] AndroidRuntime runtime)
public void CheckHttpClientHandlerType_NativeAOT_Error ()
{
bool isRelease = runtime == AndroidRuntime.NativeAOT;
// NativeAOT should fail with an error when AndroidHttpClientHandlerType is set
const bool isRelease = true;
var runtime = AndroidRuntime.NativeAOT;
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
return;
}
var proj = new XamarinAndroidApplicationProject () {
IsRelease = isRelease,
};
proj.SetRuntime (runtime);
using (var b = CreateApkBuilder ()) {
b.ThrowOnBuildFailure = false;
proj.SetProperty ("AndroidHttpClientHandlerType", "Xamarin.Android.Net.AndroidMessageHandler");
Assert.IsFalse (b.Build (proj), "Build should not have succeeded for NativeAOT with AndroidHttpClientHandlerType set.");
Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, "XA1042"), "Output should contain XA1042");
}
}

[Test]
[TestCase (AndroidRuntime.MonoVM)]
[TestCase (AndroidRuntime.CoreCLR)]
public void CheckHttpClientHandlerType_DeprecationWarning (AndroidRuntime runtime)
{
bool isRelease = false;
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
return;
}
Expand All @@ -197,7 +224,6 @@ public void CheckHttpClientHandlerType ([Values] AndroidRuntime runtime)
string supportedAbis = runtime switch {
AndroidRuntime.MonoVM => "armeabi-v7a;arm64-v8a",
AndroidRuntime.CoreCLR => "arm64-v8a;x86_64",
AndroidRuntime.NativeAOT => "arm64-v8a;x86_64",
_ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'")
};
proj.SetRuntime (runtime);
Expand All @@ -208,30 +234,25 @@ public void CheckHttpClientHandlerType ([Values] AndroidRuntime runtime)
using (var b = CreateApkBuilder ()) {
proj.SetProperty ("AndroidHttpClientHandlerType", expectedDefaultValue);
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
// Expect deprecation warning XA1043
Assert.IsTrue (StringAssertEx.ContainsText (b.LastBuildOutput, "XA1043"), "Output should contain XA1043 deprecation warning");

var intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);

List<EnvironmentHelper.EnvironmentFile>? envFiles = null;
Dictionary<string, string> envvars;

if (runtime == AndroidRuntime.NativeAOT) {
envvars = EnvironmentHelper.ReadNativeAotEnvironmentVariables (intermediateOutputDir);
} else {
envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, runtime);
envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime);
}
envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, runtime);
envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime);

Assert.IsTrue (envvars.ContainsKey (httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'.");
Assert.AreEqual (expectedDefaultValue, envvars[httpClientHandlerVarName]);

proj.SetProperty ("AndroidHttpClientHandlerType", expectedUpdatedValue);
Assert.IsTrue (b.Build (proj), "Second build should have succeeded.");

if (runtime == AndroidRuntime.NativeAOT) {
envvars = EnvironmentHelper.ReadNativeAotEnvironmentVariables (intermediateOutputDir);
} else {
envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, runtime);
envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime);
}
envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, runtime);
envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime);

Assert.IsTrue (envvars.ContainsKey (httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'.");
Assert.AreEqual (expectedUpdatedValue, envvars[httpClientHandlerVarName]);
Expand Down
Loading
Loading