I have a android library project with the following structure:
- com.domain
------------.internal //internal classes of the library
------------.thirdPartyLib //3rd party library package renamed
------------.library.publicclasses //All the public classes of the library
The idea is to configure progrard to:
- Don't remove any unused classes (since it is a library)
- Obfuscate and optimize everything (including class and methods names) except the classes under **publicclasses** that should keep their names and public elements unchanged
Currently my proguard config is:
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-keep,allowobfuscation class com.domain.** {*;}
-keep class com.domain.library.publicclasses.** {public *;}
-keep class com.domain.library.publicclasses.Foo {public protected *;}
The result of this config is:
- com.domain.library.publicclasses //All the public classes of the library
- a.a.a /// all the internal and thirdPartyLib classes
My problem is the a.a.a classes are colliding with other library obfuscated classes, so i'd like the final class structure too be
- com.domain.library
--------------------.publicclasses //All the public classes of the library
--------------------.a /// all the internal and thirdPartyLib classes
Keeping the obfuscated classes under my domain so it can't collide.
How can I achieve this?
Related
In order to configure proguard to keep all classes from a single package, say org.myorg.special, the following notation works:
-keep class !org.myorg.special { *; }
I would like to configure proguard to keep all classes except when they are from either of two packages, say org.myorg.special and org.myorg.another.
I have tried for instance
-keep class !(org.myorg.special,org.myorg.another) { *; }
but the above syntax is not supported by proguard.
What is the correct syntax?
-keep class ![org.myorg.special,org.myorg.another],org.** { *; }
I'm trying to keep proguard from renaming/optimizing classes which have a certain annotaion. There are quite a few examples out there and it should be straight forward but proguard isn't behaving as I would expect it to be.
Issue
Proguard v6.2.2 obfuscates classes annotated with #KeepClass although -whyareyoukeeping shows test.KeepMe is kept by a directive in the configuration.
I can reproduce the issue with a simple 3 file project.
Proguard config:
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 3
-allowaccessmodification
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-keep public class test.Entry {
public static void main(java.lang.String[]);
}
-keep #proguard.annotation.KeepClass public class * {
*;
}
-whyareyoukeeping class test.KeepMe
Class which should be kept:
import proguard.annotation.KeepClass;
#KeepClass
public class KeepMe
{
}
Proguard log:
Explaining why classes and class members are being kept...
Printing usage to [D:\Development\Projects\ProguardTest\build\usage.txt]...
test.KeepMe
is kept by a directive in the configuration.
Removing unused program classes and class elements...
Original number of program classes: 3
Final number of program classes: 2
And finally the files in the processed jar file:
- test
|- Entry.class
|- a.class (Obfuscated KeepMe class)
If however I explicitly list the class in the proguard configuration using
-keep class test.KeepMe{*;}
proguard reports the same log output but the class is untouched (as expected)
Am I missing something or is this a bug in proguard?
As it turns out the issue was actually related to a bug in proguard. After trying the latest beta it's working as expected.
I'm using the #VisibleForTesting annotation located in the Android Support Annotations library, and it looks like this:
#Retention(SOURCE)
public #interface VisibleForTesting {
}
As I understand it, ProGuard operates on the .class files and since this annotation isn't available at compile time due to its retention policy, all the annotated methods are stripped away. I'd like to run automated tests on my app and use the methods exposed for testing to verify that the ProGuard configuration doesn't break any use cases.
Is it possible to configure ProGuard to keep these elements somehow? So far I've tried:
-keep #android.support.annotation.VisibleForTesting class *
-keep class android.support.annotation.** {
#**.VisibleForTesting *;
}
-keep interface android.support.annotation.** {
#**.VisibleForTesting *;
}
And:
-keep interface android.support.annotation.VisibleForTesting
-keepclasseswithmembers class * {
#android.support.annotation.VisibleForTesting *;
}
-keepclassmembers class ** {
#android.support.annotation.VisibleForTesting *;
}
These two configurations do not work. If I annotate the methods with #Keep as well, and configure ProGuard to keep those methods, the methods are kept and the tests pass. However, by doing that I have to annotate all methods with two annotations.
Is it possible to hook into the annotation processor and override the retention policy for #VisibleForTesting? Or is that already too late in the build process?
Guava's #VisibleForTesting uses RetentionPolicy.CLASS, while Android Support Annotations Library uses RetentionPolicy.SOURCE. I'm considering posting a request to change the policy, but I suppose it's set to SOURCE for a reason, possibly due to performance and a very slightly increased file size?
Are there any options other than using two annotations (#VisibleForTesting and #Keep)?
Annotations with a RetentionPolicy == SOURCE are not present in .class files on which ProGuard is operating. Thus there is no way to use them in rules as they will never match.
Annotations with RetentionPolicy == CLASS should work fine. If needed, they can even be removed in release builds using ProGuard.
Below is the application.pro which is the configuration to obfuscate the spring related standalone application:
# This ProGuard configuration file illustrates how to process applications.
# Usage:
# java -jar proguard.jar #applications.pro
#
# Specify the input jars, output jars, and library jars.
-injars xyz.jar
-outjars xyz_out.jar
-libraryjars C:\Program Files\Java\jdk1.8.0_20\jre\lib\rt.jar
-libraryjars <LocationOfJar>/xyz.jar
#-libraryjars servlet.jar
#-libraryjars jai_core.jar
#...
# Save the obfuscation mapping to a file, so you can de-obfuscate any stack
# traces later on. Keep a fixed source file attribute and all line number
# tables to get line numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.
-printmapping out.map
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# Preserve all annotations.
-keepattributes *Annotation*
# You can print out the seeds that are matching the keep options below.
#-printseeds out.seeds
# Preserve all public applications.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your application doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Your application may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:
# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface
#Warnings to be removed. Otherwise maven plugin stops, but not dangerous
-keep public class com.sun.xml.internal.**
-keep public class com.sun.istack.internal.**
-keep public class org.codehaus.jackson.**
-keep public class org.springframework.**
-keep public class java.awt.**
-keep public class javax.security.**
-keep public class java.beans.**
-keep public class javax.xml.**
-keep public class java.util.**
-keep public class org.w3c.dom.**
-keep public class com.google.common.**
-keep public class org.apache.**
-keep public class org.xnio.**
-keep public class javax.xml.**
-keep public class java.time.**
-keep public class com.sun.corba.**
-keep public class org.hibernate.**
-keep public class antlr.**
-dontwarn com.sun.xml.internal.**
-dontwarn com.sun.istack.internal.**
-dontwarn org.codehaus.jackson.**
-dontwarn org.springframework.**
-dontwarn java.awt.**
-dontwarn javax.security.**
-dontwarn java.beans.**
-dontwarn javax.xml.**
-dontwarn java.util.**
-dontwarn org.w3c.dom.**
-dontwarn com.google.common.**
-dontwarn org.apache.**
-dontwarn org.xnio.**
-dontwarn javax.xml.**
-dontwarn java.time.**
-dontwarn com.sun.corba.**
-dontwarn org.hibernate.**
-dontwarn antlr.**
-dontskipnonpubliclibraryclasses
When I run:
java -jar proguard.jar #applications.pro
I get this below error:
Note: duplicate definition of library class
And output is not generated as given in the application.pro:
Note: there were 166 classes trying to access generic signatures using reflection.
You should consider keeping the signature attributes
(using '-keepattributes Signature').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 21 classes trying to access enclosing classes using reflection.
You should consider keeping the inner classes attributes
(using '-keepattributes InnerClasses').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 5 classes trying to access enclosing methods using reflection.
You should consider keeping the enclosing method attributes
(using '-keepattributes InnerClasses,EnclosingMethod').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 563 library classes explicitly being kept.
You don't need to keep library classes; they are already left unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#libraryclass)
Note: there were 55 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 4 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Note: there were 292 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Warning: there were 5329 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 117 instances of library classes depending on program classes.
You must avoid such dependencies, since the program classes will
be processed, while the library classes will remain unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)
Warning: there were 42 unresolved references to program class members.
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
Error: Please correct the above warnings first.
How to resolve this issue?
I'm setting up ProGuard for my Android project. My project also uses GSON.
I've researched ProGuard configurations for compatibility with GSON and Android and came across this example offered by google-gson https://code.google.com/p/google-gson/source/browse/trunk/examples/android-proguard-example/proguard.cfg.
ProGuard config copied below:
##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''
-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.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static <fields>;
}
# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * {
public protected *;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
##---------------End: proguard configuration common for all Android apps ----------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON #Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
##---------------End: proguard configuration for Gson ----------
Questions:
I see that this file has not been updated since 2011, is it still recommended for use? I ask because Android/GSON has changed quite a bit since then so I don't know how much of the above in unnecessary or incorrect.
If this is not recommended, is there a new recommended ProGuard configuration for GSON in Android?
I think most of those settings you have there are already included in the Android SDK by default.
So you can remove most of them, just leaving in the section devoted to GSON.
I am developing in Eclipse using Android SDK Tools 22.6.3 & whatever version of ProGuard ships with that.
Here's what I'm using for GSON 2.2.4 (as per their example):
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
# -keep class mypersonalclass.data.model.** { *; }
It looks exactly the same as what you have, except I don't need the line about the annotations.
You can see I've commented out some classes that I added myself. If you serialize/deserialize your own classes, you need to declare them here in place of the reference to mypersonalclass.data.model. This is really important, as you don't want ProGuard to obfuscate the field or class names that GSON uses for serialization.
I always leave those types of comments in there, so I know how to configure the next library or app.
The previous answer stopped working for me recently probably due to some changes in Android (R8 is used now instead of Proguard). The configuration I use now is as follows (source - GSON examples):
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON #Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in #JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
#com.google.gson.annotations.SerializedName <fields>;
}
##---------------End: proguard configuration for Gson ----------
I found out that classes whose fields are annotated by #SerializedName do not have to be explicitly listed unless they are inner classes.
In my case, I just used GSON for deserializing JSON to an Object. So it was enough to add the following line to proguard file.
-keep class your.data.object.modals.package.** { <fields>; }
In my case I added the above but still got an error until in my app level gradle I changed compile 'org.immutables:gson:2.4.6' to provided 'org.immutables:gson:2.4.6'. Maybe someone more enlightened can explain why but this solved my problem.
Using -keep is a bad practice and you should never do it .You almost never want to use -keep; if you do need a ProGuard rule, you usually want one of the more specific variants
-keepclassmembers - This protects only the members of the class from shrinking and obfuscation.
-keepnames - This allows shrinking for classes and members, but not obfuscation. That is, any unused code is going to get removed. But the code that is kept will keep its original names.
-keepclassmembernames - Unused classes are removed, the remaining classes are renamed, unused members of those classes are removed, but then the remaining members keep their original names.
For more information please read this
PS - this is what I did for Gson
-keepclassmembernames class rscom.pojo.** { <fields>; }