Search code examples
androidproguardandroid-proguard

Android proguard doesn't obfuscate classes


I've build a release Android application with proguard, but after decompiling of APK I see that classes, which must be obfuscated, have normal sources. There's a part of my gradle build :

buildTypes {
    debug {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

And here's my proguard-rules.pro file:

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-keepattributes *Annotation*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-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);
}

-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

-assumenosideeffects class android.util.Log {
    public static *** e(...);
    public static *** w(...);
    public static *** wtf(...);
    public static *** d(...);
    public static *** v(...);
}

-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclassmembers class * {
    public void *ButtonClicked(android.view.View);
}

-dontwarn okio**
-dontwarn java.lang.invoke**
-dontwarn org.apache.commons.io**
-dontwarn org.codehaus**
-keep public class java.nio**
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-dontwarn android.support.v7.**
-keep class android.support.v7.** { *; }
-keep class net.sqlcipher.** { *; }

-keep class net.sqlcipher.database.** { *; }

-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-keep class com.google.gson.** { *; }
-keep class com.google.inject.* { *; }
-keep class org.apache.http.** { *; }
-keep class org.apache.james.mime4j.** { *; }
-keep class javax.inject.** { *; }
-keepclassmembernames interface * {
    @retrofit.http.* <methods>;
}

-keep class sun.misc.Unsafe { *; }
-keep public class !com.vidal.cardio.datas.MySQLCipherOpenHelper { *; }
-keep public class !com.vidal.cardio.datas.SCLcipherOpenHelper { *; }

Well, I've expected that MySQLCipherOpenHelper and SCLcipherOpenHelper will be obfuscated, but actually they don't. Maybe there's a mistake in proguard-rules.pro?


Solution

  • Keep rules will be analyzed and processed independently from each other, so if you write rules like this

    -keep public class !com.vidal.cardio.datas.MySQLCipherOpenHelper { *; }
    -keep public class !com.vidal.cardio.datas.SCLcipherOpenHelper { *; }
    

    ProGuard will do the following:

    • process the first rule to keep everything except MySQLCipherOpenHelper
    • process the second rule to keep everything except SCLcipherOpenHelper

    as you can see, with the first rule you also implicitly keep the second class, while with the second rule you keep the first one as well.

    In order to not keep both of them, you have to merge the rules like that:

    -keep public class !com.vidal.cardio.datas.MySQLCipherOpenHelper, 
                       !com.vidal.cardio.datas.SCLcipherOpenHelper { *; }