diff --git a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg index 5d5c9affde5..e3feb7e92a1 100644 --- a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg +++ b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg @@ -14,15 +14,15 @@ -keep class opentk_1_0.GameViewBase { *; (...); } -keep class com.xamarin.java_interop.ManagedPeer { *; (...); } --keep class android.runtime.** { (***); } --keep class assembly_mono_android.android.runtime.** { (***); } +-keep class android.runtime.** { (...); } +-keep class assembly_mono_android.android.runtime.** { (...); } # hash for android.runtime and assembly_mono_android.android.runtime. -keep class md52ce486a14f4bcd95899665e9d932190b.** { *; (...); } -keepclassmembers class md52ce486a14f4bcd95899665e9d932190b.** { *; (...); } # Android's template misses fluent setters... -keepclassmembers class * extends android.view.View { - *** set*(***); + *** set*(...); } # also misses those inflated custom layout stuff from xml... diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index f59607fe6cd..4aa8b2cdc5e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -774,10 +774,15 @@ public void BuildProguardEnabledProject ([Values (true, false)] bool isRelease, Assert.IsTrue (StringAssertEx.ContainsText (File.ReadAllLines (proguardProjectPrimary), "-keep class md52d9cf6333b8e95e8683a477bc589eda5.MainActivity"), "`md52d9cf6333b8e95e8683a477bc589eda5.MainActivity` should exist in `proguard_project_primary.cfg`!"); } - var className = "Lmono/MonoRuntimeProvider;"; var dexFile = b.Output.GetIntermediaryPath (Path.Combine ("android", "bin", "classes.dex")); FileAssert.Exists (dexFile); - Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, b.AndroidSdkDirectory), $"`{dexFile}` should include `{className}`!"); + var classes = new [] { + "Lmono/MonoRuntimeProvider;", + "Landroid/runtime/UncaughtExceptionHandler;", + }; + foreach (var className in classes) { + Assert.IsTrue (DexUtils.ContainsClassWithMethod (className, "", "()V", dexFile, b.AndroidSdkDirectory), $"`{dexFile}` should include `{className}`!"); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/DexUtils.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/DexUtils.cs index f1dbe6ded7f..96b0fb2a57b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/DexUtils.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Utilities/DexUtils.cs @@ -9,10 +9,60 @@ namespace Xamarin.ProjectTools { public static class DexUtils { + /* + Example dexdump output: + + Class #12 - + Class descriptor : 'Landroid/runtime/UncaughtExceptionHandler;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'Ljava/lang/Object;' + Interfaces - + #0 : 'Ljava/lang/Thread$UncaughtExceptionHandler;' + #1 : 'Lmono/android/IGCUserPeer;' + Static fields - + #0 : (in Landroid/runtime/UncaughtExceptionHandler;) + name : '__md_methods' + type : 'Ljava/lang/String;' + access : 0x0019 (PUBLIC STATIC FINAL) + Instance fields - + #0 : (in Landroid/runtime/UncaughtExceptionHandler;) + name : 'refList' + type : 'Ljava/util/ArrayList;' + access : 0x0002 (PRIVATE) + Direct methods - + #0 : (in Landroid/runtime/UncaughtExceptionHandler;) + name : '' + type : '()V' + access : 0x10008 (STATIC CONSTRUCTOR) + code - + registers : 3 + ins : 0 + outs : 3 + insns size : 10 16-bit code units + catches : (none) + positions : + 0x0002 line=16 + locals : + #1 : (in Landroid/runtime/UncaughtExceptionHandler;) + name : '' + type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 4 + ins : 1 + outs : 4 + insns size : 22 16-bit code units + catches : (none) + positions : + 0x0000 line=22 + 0x0003 line=23 + 0x0010 line=24 + locals : + 0x0000 - 0x0016 reg=3 this Landroid/runtime/UncaughtExceptionHandler; + */ + /// /// Runs the dexdump command to see if a class exists in a dex file - /// dexdump returns data of the form: - /// Class descriptor : 'Landroid/app/ActivityTracker;' /// /// A Java class name of the form 'Landroid/app/ActivityTracker;' public static bool ContainsClass (string className, string dexFile, string androidSdkDirectory) @@ -22,13 +72,45 @@ public static bool ContainsClass (string className, string dexFile, string andro if (e.Data != null && e.Data.Contains ("Class descriptor") && e.Data.Contains (className)) containsClass = true; }; + DexDump (handler, dexFile, androidSdkDirectory); + return containsClass; + } - var androidSdk = new AndroidSdkInfo ((l, m) => { - Console.WriteLine ($"{l}: {m}"); - if (l == TraceLevel.Error) { - throw new Exception (m); + /// + /// Runs the dexdump command to see if a class exists in a dex file *and* has a public constructor + /// + /// A Java class name of the form 'Landroid/app/ActivityTracker;' + /// A Java method name of the form 'foo' + /// A Java method signature of the form '()V' + public static bool ContainsClassWithMethod (string className, string method, string type, string dexFile, string androidSdkDirectory) + { + bool inClass = false; + bool hasName = false; + bool hasType = false; + DataReceivedEventHandler handler = (s, e) => { + if (e.Data != null) { + if (e.Data.Contains ("Class descriptor")) { + inClass = e.Data.Contains (className); + hasName = false; + } else if (inClass && e.Data.Contains ("name") && e.Data.Contains (method)) { + hasName = true; + } else if (hasName && e.Data.Contains ("type") && e.Data.Contains (type)) { + hasType = true; } - }, androidSdkDirectory); + } + }; + DexDump (handler, dexFile, androidSdkDirectory); + return hasType; + } + + static void DexDump (DataReceivedEventHandler handler, string dexFile, string androidSdkDirectory) + { + var androidSdk = new AndroidSdkInfo ((l, m) => { + Console.WriteLine ($"{l}: {m}"); + if (l == TraceLevel.Error) { + throw new Exception (m); + } + }, androidSdkDirectory); var buildToolsPath = androidSdk.GetBuildToolsPaths ().FirstOrDefault (); if (string.IsNullOrEmpty (buildToolsPath)) { throw new Exception ($"Unable to find build-tools in `{androidSdkDirectory}`!"); @@ -53,8 +135,6 @@ public static bool ContainsClass (string className, string dexFile, string andro p.BeginOutputReadLine (); p.WaitForExit (); } - - return containsClass; } } }