I am moving a project from Ant to Gradle, but there's something I just can't figure out.
FACTS
After building a release APK (i.e., obfuscated), I noticed that the app was crashing badly. The error can be summed up by this:
java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
A debug (i.e., non obfuscated) APK works just fine, so I guessed it had to do with my ProGuard/DexGuard configuration.
I tried to keep the class reference by adding the following statement:
-keep class com.mypackage.MyCustomView
and, as a result, the release APK works just fine. I then did some research and I tried this more specific ProGuard/DexGuard configuration:
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
which also works, and it is class-independent.
QUESTION
I wonder:
ANSWER
The answer from @Blundell was substantially correct. Turns out I was missing one line from the build.gradle
configuration:
android {
...
buildTypes {
debug {
...
}
release {
proguardFile getDefaultDexGuardFile('dexguard-release.pro') # <----- this line
proguardFile 'dexguard-project.txt'
}
}
}
It appears that line is actually mandatory, since it serves as a base set of rules for ProGuard/DexGuard. In fact, this is part of the dexguard-release.pro
file:
-keepclassmembers !abstract class !com.google.ads.** extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclassmembers !abstract class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
}
I found the documentation a little bit too vague on this, I hope it can be redacted to clear any ambiguity it might have. All in all, my fault.
R8 is having a faster processing time than Proguard which reduces build time. R8 gives better output results than Proguard. R8 reduces the app size by 10 % whereas Proguard reduces app size by 8.5 %. The android app having a Gradle plugin above 3.4.
For example, the useProGuard setting has been deprecated a while ago - maybe that's what you saw and you're misremembering it.
– android developer. Jun 12, 2015 at 10:47. 1. minifyEnabled enables proguard which removes unused classes/code and shrinkResources removes unused resources (pngs, xmls, mostly introduced by libraries which you don't fully utilize).
minifyEnabled true. // Enables resource shrinking, which is performed by the. // Android Gradle plugin. shrinkResources true. // Includes the default ProGuard rules files that are packaged with.
Most likely Ant was using a different configuration file,
Also with Gradle you need to explicitly state you want to also use the Android proguard config file i.e. use multiple rules files like so:
proguardFile getDefaultProguardFile('proguard-android.txt')
proguardFile 'your/sepcific/folder/proguard.cfg'
(I remember Ant never used a SDK proguard file and it used to be recommended to copy all the config across).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With