diff --git a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs index 290f45a70e6..bb029b7421a 100644 --- a/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs +++ b/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs @@ -4,9 +4,9 @@ using Mono.Cecil; using Mono.Linker; using Mono.Linker.Steps; -using Mono.Tuner; using Java.Interop.Tools.Cecil; using Xamarin.Android.Tasks; +using Profile = Microsoft.Android.Sdk.ILLink.Profile; namespace MonoDroid.Tuner { @@ -27,7 +27,14 @@ public override void Initialize (LinkContext context, MarkContext markContext) bool IsActiveFor (AssemblyDefinition assembly) { - return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); + if (Profile.IsSdkAssembly (assembly)) + return false; + if (Profile.IsProductAssembly (assembly)) + return false; + + return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || + assembly.MainModule.HasTypeReference ("Java.Lang.Object") || + assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); } public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClientHandlerType, Dictionary> customViewMap) @@ -47,14 +54,42 @@ public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClie } } - // Custom views in Android .xml files + // Continue if not an IJavaObject if (!type.ImplementsIJavaObject (cache)) continue; + + // Custom views in Android .xml files if (customViewMap.ContainsKey (type.FullName)) { Annotations.Mark (type); PreserveJavaObjectImplementation (type); + continue; + } + + // Types with Java.Interop.IJniNameProviderAttribute attributes + if (ShouldPreserveBasedOnAttributes (type)) { + Annotations.Mark (type); + PreserveJavaObjectImplementation (type); + continue; + } + } + } + + bool ShouldPreserveBasedOnAttributes (TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + + foreach (var attr in type.CustomAttributes) { + // Ignore Android.Runtime.RegisterAttribute + if (attr.AttributeType.FullName == "Android.Runtime.RegisterAttribute") { + continue; + } + if (attr.AttributeType.Implements ("Java.Interop.IJniNameProviderAttribute", cache)) { + return true; } } + + return false; } public void ProcessType (TypeDefinition type) 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 d91ed72976f..134697f8c27 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 @@ -598,6 +598,40 @@ public void PreserveIX509TrustManagerSubclasses ([Values(true, false)] bool hasS } } + [Test] + public void PreserveServices () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + TrimModeRelease = TrimMode.Full, + PackageReferences = { + new Package { Id = "Plugin.Firebase.CloudMessaging", Version = "3.0.0" }, + } + }; + proj.MainActivity = proj.DefaultMainActivity + .Replace ("//${FIELDS}", + """ + protected override void OnNewIntent (Android.Content.Intent? intent) + { + base.OnNewIntent (intent); + Plugin.Firebase.CloudMessaging.FirebaseCloudMessagingImplementation.OnNewIntent (intent); + } + """) + .Replace ("//${AFTER_ONCREATE}", "Plugin.Firebase.Core.Platforms.Android.CrossFirebase.Initialize (this);"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + + var assemblyPath = BuildTest.GetLinkedPath (b, isRelease: true, "Plugin.Firebase.CloudMessaging.dll"); + FileAssert.Exists (assemblyPath); + using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath); + var types = new [] { "Plugin.Firebase.CloudMessaging.Platforms.Android.MyFirebaseMessagingService" }; + foreach (var typeName in types) { + var td = assembly.MainModule.GetType (typeName); + Assert.IsNotNull (td, $"{typeName} should not have been linked out!"); + } + } + [Test] public void DoNotErrorOnPerArchJavaTypeDuplicates ([Values(true, false)] bool enableMarshalMethods) {