diff --git a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
index 329ee6aa67a..17bbb17d273 100644
--- a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
+++ b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
@@ -336,9 +336,7 @@ static IWebProxy GetDefaultProxy ()
[DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))]
static object GetHttpMessageHandler ()
{
- // FIXME: https://github.com/xamarin/xamarin-android/issues/8797
- // Note that this is a problem for custom $(AndroidHttpClientHandlerType) or $XA_HTTP_CLIENT_HANDLER_TYPE
- [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "DynamicDependency should preserve AndroidMessageHandler.")]
+ [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Rooted by the MSBuild task.")]
[return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
static Type TypeGetType (string typeName) =>
Type.GetType (typeName, throwOnError: false);
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
index 05c6c56639f..775370ac8d4 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets
@@ -81,7 +81,8 @@ _ResolveAssemblies MSBuild target.
-
+
<_RIDs Include="$(RuntimeIdentifier)" Condition=" '$(RuntimeIdentifiers)' == '' " />
<_RIDs Include="$(RuntimeIdentifiers)" Condition=" '$(RuntimeIdentifiers)' != '' " />
@@ -96,6 +97,7 @@ _ResolveAssemblies MSBuild target.
;_OuterIntermediateAssembly=@(IntermediateAssembly)
;_OuterOutputPath=$(OutputPath)
;_OuterIntermediateOutputPath=$(IntermediateOutputPath)
+ ;_AndroidGeneratedRootDescriptor=$(_AndroidGeneratedRootDescriptor)
<_AndroidBuildRuntimeIdentifiersInParallel Condition=" '$(_AndroidBuildRuntimeIdentifiersInParallel)' == '' ">true
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
index df4dab646d8..429386f977d 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets
@@ -55,6 +55,7 @@ properties that determine build ordering.
_SetLatestTargetFrameworkVersion;
_GetLibraryImports;
_RemoveRegisterAttribute;
+ _GenerateILLinkXml;
_ResolveAssemblies;
_ResolveSatellitePaths;
_CreatePackageWorkspace;
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets
index d9478aed722..36dd8c3f985 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets
@@ -9,6 +9,8 @@ This file contains the .NET 5-specific targets to customize ILLink
+
+
+
+
+
+
+
+
+ <_AndroidGeneratedRootDescriptor>$(IntermediateOutputPath)net-android-trimmer.xml
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateILLinkXml.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateILLinkXml.cs
new file mode 100644
index 00000000000..263a85833c7
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateILLinkXml.cs
@@ -0,0 +1,70 @@
+using System.Xml.Linq;
+using Microsoft.Android.Build.Tasks;
+using Microsoft.Build.Framework;
+
+namespace Xamarin.Android.Tasks;
+
+public class GenerateILLinkXml : AndroidTask
+{
+ public override string TaskPrefix => "GILX";
+
+ [Required]
+ public string AndroidHttpClientHandlerType { get; set; }
+
+ [Required]
+ public string CustomViewMapFile { get; set; }
+
+ [Required]
+ public string OutputFile { get; set; }
+
+ public override bool RunTask ()
+ {
+ string assemblyName, typeName;
+
+ var index = AndroidHttpClientHandlerType.IndexOf (',');
+ if (index != -1) {
+ typeName = AndroidHttpClientHandlerType.Substring (0, index).Trim ();
+ assemblyName = AndroidHttpClientHandlerType.Substring (index + 1).Trim ();
+ } else {
+ typeName = AndroidHttpClientHandlerType;
+ assemblyName = "Mono.Android";
+ }
+
+ // public parameterless constructors
+ // example: https://github.com/dotnet/runtime/blob/039d2ecb46687e89337d6d629c295687cfe226be/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
+ var ctor = new XElement ("method", new XAttribute("signature", "System.Void .ctor()"));
+
+ XElement linker;
+ var doc = new XDocument (
+ linker = new XElement ("linker",
+ new XElement ("assembly",
+ new XAttribute ("fullname", assemblyName),
+ new XElement ("type", new XAttribute ("fullname", typeName), ctor)
+ )
+ )
+ );
+
+ var customViewMap = MonoAndroidHelper.LoadCustomViewMapFile (BuildEngine4, CustomViewMapFile);
+ foreach (var pair in customViewMap) {
+ index = pair.Key.IndexOf (',');
+ if (index == -1)
+ continue;
+
+ typeName = pair.Key.Substring (0, index).Trim ();
+ assemblyName = pair.Key.Substring (index + 1).Trim ();
+
+ linker.Add (new XElement ("assembly",
+ new XAttribute ("fullname", assemblyName),
+ new XElement ("type", new XAttribute ("fullname", typeName), ctor)
+ ));
+ }
+
+ if (doc.SaveIfChanged (OutputFile)) {
+ Log.LogDebugMessage ($"Saving {OutputFile}");
+ } else {
+ Log.LogDebugMessage ($"{OutputFile} is unchanged. Skipping.");
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
index 86f2a319cc0..5aebe1b4a6f 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs
@@ -156,14 +156,45 @@ static AssemblyDefinition CreateFauxMonoAndroidAssembly ()
return assm;
}
- private void PreserveCustomHttpClientHandler (string handlerType, string handlerAssembly, string testProjectName, string assemblyPath)
+ private void PreserveCustomHttpClientHandler (
+ string handlerType,
+ string handlerAssembly,
+ string testProjectName,
+ string assemblyPath,
+ TrimMode trimMode)
{
- var proj = new XamarinAndroidApplicationProject () { IsRelease = true };
+ testProjectName += trimMode.ToString ();
+
+ var class_library = new XamarinAndroidLibraryProject {
+ IsRelease = true,
+ ProjectName = "MyClassLibrary",
+ Sources = {
+ new BuildItem.Source ("MyCustomHandler.cs") {
+ TextContent = () => """
+ class MyCustomHandler : System.Net.Http.HttpMessageHandler
+ {
+ protected override Task SendAsync (HttpRequestMessage request, CancellationToken cancellationToken) =>
+ throw new NotImplementedException ();
+ }
+ """
+ }
+ }
+ };
+ using (var libBuilder = CreateDllBuilder ($"{testProjectName}/{class_library.ProjectName}")) {
+ Assert.IsTrue (libBuilder.Build (class_library), $"Build for {class_library.ProjectName} should have succeeded.");
+ }
+
+ var proj = new XamarinAndroidApplicationProject {
+ ProjectName = "MyApp",
+ IsRelease = true,
+ TrimModeRelease = trimMode
+ };
+ proj.AddReference (class_library);
proj.AddReferences ("System.Net.Http");
string handlerTypeFullName = string.IsNullOrEmpty(handlerAssembly) ? handlerType : handlerType + ", " + handlerAssembly;
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidHttpClientHandlerType", handlerTypeFullName);
proj.MainActivity = proj.DefaultMainActivity.Replace ("base.OnCreate (bundle);", "base.OnCreate (bundle);\nvar client = new System.Net.Http.HttpClient ();");
- using (var b = CreateApkBuilder (testProjectName)) {
+ using (var b = CreateApkBuilder ($"{testProjectName}/{proj.ProjectName}")) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
using (var assembly = AssemblyDefinition.ReadAssembly (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, assemblyPath))) {
@@ -173,12 +204,14 @@ private void PreserveCustomHttpClientHandler (string handlerType, string handler
}
[Test]
- public void PreserveCustomHttpClientHandlers ()
+ public void PreserveCustomHttpClientHandlers ([Values (TrimMode.Partial, TrimMode.Full)] TrimMode trimMode)
{
PreserveCustomHttpClientHandler ("Xamarin.Android.Net.AndroidMessageHandler", "",
- "temp/PreserveAndroidMessageHandler", "android-arm64/linked/Mono.Android.dll");
+ "temp/PreserveAndroidMessageHandler", "android-arm64/linked/Mono.Android.dll", trimMode);
PreserveCustomHttpClientHandler ("System.Net.Http.SocketsHttpHandler", "System.Net.Http",
- "temp/PreserveSocketsHttpHandler", "android-arm64/linked/System.Net.Http.dll");
+ "temp/PreserveSocketsHttpHandler", "android-arm64/linked/System.Net.Http.dll", trimMode);
+ PreserveCustomHttpClientHandler ("MyCustomHandler", "MyClassLibrary",
+ "temp/MyCustomHandler", "android-arm64/linked/MyClassLibrary.dll", trimMode);
}
[Test]
diff --git a/tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs b/tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs
index ec2ab5bdc1d..9ffd36a7328 100644
--- a/tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs
+++ b/tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs
@@ -1,11 +1,9 @@
-using System.Diagnostics.CodeAnalysis;
-using Android.App;
+using Android.App;
using Android.Content;
using Android.Util;
using Android.Views;
using Android.Widget;
using NUnit.Framework;
-using Mono.Android_Test.Library;
namespace Xamarin.Android.RuntimeTests
{
@@ -14,7 +12,6 @@ public class CustomWidgetTests
{
// https://bugzilla.xamarin.com/show_bug.cgi?id=23880
[Test]
- [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (CustomTextView))]
public void UpperCaseCustomWidget_ShouldNotThrowInflateException ()
{
Assert.DoesNotThrow (() => {
@@ -24,7 +21,6 @@ public void UpperCaseCustomWidget_ShouldNotThrowInflateException ()
}
[Test]
- [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (CustomTextView))]
public void LowerCaseCustomWidget_ShouldNotThrowInflateException ()
{
Assert.DoesNotThrow (() => {
@@ -34,7 +30,6 @@ public void LowerCaseCustomWidget_ShouldNotThrowInflateException ()
}
[Test]
- [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (CustomTextView))]
public void UpperAndLowerCaseCustomWidget_FromLibrary_ShouldNotThrowInflateException ()
{
Assert.DoesNotThrow (() => {