| You can find some sample configuration files in the `examples` directory |
| of the ProGuard distribution. |
| |
| ## Processing different types of applications {: #applicationtypes} |
| |
| ### A typical application {: #application} |
| |
| To shrink, optimize, and obfuscate a simple Java application, you |
| typically create a configuration file like `myconfig.pro`, which you can |
| then use with |
| |
| bin/proguard @myconfig.pro |
| |
| The configuration file specifies the input, the output, and the entry |
| points of the application: |
| |
| -injars myapplication.jar |
| -outjars myapplication_out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -printmapping myapplication.map |
| |
| -keep public class com.example.MyMain { |
| public static void main(java.lang.String[]); |
| } |
| |
| Note the use of the `<java.home>` system property. ProGuard automatically |
| replaces it when parsing the file. In this example, the library jar is the |
| base Java runtime module, minus some unwanted files. For Java 8 or older, the |
| Java runtime jar would be `<java.home>/lib/rt.jar` instead. You may need |
| additional modules or jars if your application depends on them. |
| |
| The [`-keep`](usage.md#keep) option specifies the entry point of the |
| application that has to be preserved. The access modifiers `public` and |
| `static` are not really required in this case, since we know a priori that the |
| specified class and method have the proper access flags. It just looks more |
| familiar this way. |
| |
| Note that all type names are fully specified: `com.example.MyMain` and |
| `java.lang.String[]`. |
| |
| We're writing out an obfuscation mapping file with |
| [`-printmapping`](usage.md#printmapping), for de-obfuscating any stack traces |
| later on, or for incremental obfuscation of extensions. |
| |
| We can further improve the results with a few additional options: |
| |
| -optimizationpasses 3 |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| |
| These options are not required; they just shave off some extra bytes from the |
| output jar, by performing up to 3 optimization passes, and by aggressively |
| obfuscating class members and [package names](#repackaging). |
| |
| In general, you might need a few additional options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### A typical applet {: #applet} |
| |
| These options shrink, optimize, and obfuscate the applet |
| `com.example.MyApplet`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| -keep public class com.example.MyApplet |
| |
| The typical applet methods will be preserved automatically, since |
| `com.example.MyApplet` is an extension of the `Applet` class in the library |
| `rt.jar`. |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### A typical midlet {: #midlet} |
| |
| These options shrink, optimize, obfuscate, and preverify the midlet |
| `com.example.MyMIDlet`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| -microedition |
| |
| -keep public class com.example.MyMIDlet |
| |
| Note how we're now targeting the Java Micro Edition run-time environment of |
| `midpapi20.jar` and `cldcapi11.jar`, instead of the Java Standard Edition |
| run-time environment `rt.jar`. You can target other JME environments by |
| picking the appropriate jars. |
| |
| The typical midlet methods will be preserved automatically, since |
| `com.example.MyMIDlet` is an extension of the `MIDlet` class in the library |
| `midpapi20.jar`. |
| |
| The [`-microedition`](usage.md#microedition) option makes sure the class files |
| are preverified for Java Micro Edition, producing compact `StackMap` |
| attributes. It is no longer necessary to run an external preverifier. |
| |
| Be careful if you do use the external `preverify` tool on a platform with a |
| case-insensitive filing system, such as Windows. Because this tool unpacks |
| your processed jars, you should then use ProGuard's |
| [`-dontusemixedcaseclassnames`](usage.md#dontusemixedcaseclassnames) option. |
| |
| If applicable, you should add options for processing [native methods](#native) |
| and [resource files](#resourcefiles). |
| |
| Note that you will still have to adapt the midlet jar size in the |
| corresponding jad file; ProGuard doesn't do that for you. |
| |
| ### A typical Java Card applet {: #jcapplet} |
| |
| These options shrink, optimize, and obfuscate the Java Card applet |
| `com.example.MyApplet`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/javacard2.2.2/lib/api.jar |
| -dontwarn java.lang.Class |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| |
| -keep public class com.example.MyApplet |
| |
| The configuration is very similar to the configuration for midlets, except |
| that it now targets the Java Card run-time environment. This environment |
| doesn't have java.lang.Class, so we're telling ProGuard not to worry about it. |
| |
| ### A typical xlet {: #xlet} |
| |
| These options shrink, optimize, and obfuscate the xlet `com.example.MyXlet`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/jtv1.1/javatv.jar |
| -libraryjars /usr/local/java/cdc1.1/lib/cdc.jar |
| -libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| |
| -keep public class com.example.MyXlet |
| |
| The configuration is very similar to the configuration for midlets, except |
| that it now targets the CDC run-time environment with the Java TV API. |
| |
| ### A simple Android activity {: #simpleandroid} |
| |
| These options shrink, optimize, and obfuscate the single Android activity |
| `com.example.MyActivity`: |
| |
| -injars bin/classes |
| -outjars bin/classes-processed.jar |
| -libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar |
| |
| -android |
| -dontpreverify |
| -repackageclasses '' |
| -allowaccessmodification |
| -optimizations !code/simplification/arithmetic |
| |
| -keep public class com.example.MyActivity |
| |
| We're targeting the Android run-time and keeping the activity as an entry |
| point. |
| |
| Preverification is irrelevant for the dex compiler and the Dalvik VM, so we |
| can switch it off with the [`-dontpreverify`](usage.md#dontpreverify) option. |
| |
| The [`-optimizations`](usage.md#optimizations) option disables some arithmetic |
| simplifications that Dalvik 1.0 and 1.5 can't handle. Note that the Dalvik VM |
| also can't handle [aggressive overloading](usage.md#overloadaggressively) (of |
| static fields). |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### A complete Android application {: #android} |
| |
| !!! note "" |
| {: .icon} The standard build processes of the |
| Android SDK (with Ant, Gradle, Android Studio, and Eclipse) already |
| integrate ProGuard with all the proper settings. You only need to enable |
| ProGuard by uncommenting the line "`proguard.config=.....`" in the file |
| `project.properties` of your Ant project, or by adapting the |
| `build.gradle` file of your Gradle project. You then *don't* need any of |
| the configuration below. |
| |
| Notes: |
| |
| - In case of problems, you may want to check if the configuration files that |
| are listed on this line (`proguard-project.txt`,...) contain the necessary |
| settings for your application. |
| - Android SDK revision 20 and higher have a different configuration file for |
| enabling optimization: |
| `${sdk.dir}/tools/proguard/proguard-android-optimize.txt` instead of the |
| default `${sdk.dir}/tools/proguard/proguard-android.txt`. |
| - The build processes are already setting the necessary program jars, library |
| jars, and output jars for you — don't specify them again. |
| - If you get warnings about missing referenced classes: it's all too common |
| that libraries refer to missing classes. See ["Warning: can't find |
| referenced class"](troubleshooting.md#unresolvedclass) in the |
| Troubleshooting section. |
| |
| For more information, you can consult the official [Developer |
| Guide](http://developer.android.com/guide/developing/tools/proguard.html) in |
| the Android SDK. |
| |
| If you're constructing a build process *from scratch*: these options |
| shrink, optimize, and obfuscate all public activities, services, |
| broadcast receivers, and content providers from the compiled classes and |
| external libraries: |
| |
| -injars bin/classes |
| -injars bin/resources.ap_ |
| -injars libs |
| -outjars bin/application.apk |
| -libraryjars /usr/local/android-sdk/platforms/android-28/android.jar |
| |
| -android |
| -dontpreverify |
| -repackageclasses '' |
| -allowaccessmodification |
| -optimizations !code/simplification/arithmetic |
| -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 * extends android.content.Context { |
| public void *(android.view.View); |
| public void *(android.view.MenuItem); |
| } |
| |
| -keepclassmembers class * implements android.os.Parcelable { |
| static ** CREATOR; |
| } |
| |
| -keepclassmembers class **.R$* { |
| public static <fields>; |
| } |
| |
| -keepclassmembers class * { |
| @android.webkit.JavascriptInterface <methods>; |
| } |
| |
| Most importantly, we're keeping all fundamental classes that may be referenced |
| by the `AndroidManifest.xml` file of the application. If your manifest file |
| contains other classes and methods, you may have to specify those as well. |
| |
| We're keeping annotations, since they might be used by custom `RemoteViews` |
| and by various frameworks. |
| |
| We're keeping any custom `View` extensions and other classes with typical |
| constructors, since they might be referenced from XML layout files. |
| |
| We're also keeping possible `onClick` handlers in custom `Context` extensions, |
| since they might be referenced from XML layout files. |
| |
| We're also keeping the required static fields in `Parcelable` implementations, |
| since they are accessed by introspection. |
| |
| We're keeping the static fields of referenced inner classes of auto-generated |
| `R` classes, just in case your code is accessing those fields by |
| introspection. Note that the compiler already inlines primitive fields, so |
| ProGuard can generally remove all these classes entirely anyway (because the |
| classes are not referenced and therefore not required). |
| |
| Finally, we're keeping annotated Javascript interface methods, so they can be |
| exported and accessed by their original names. Javascript interface methods |
| that are not annotated (in code targeted at Android versions older than 4.2) |
| still need to be preserved manually. |
| |
| If you're using additional Google APIs, you'll have to specify those as |
| well, for instance: |
| |
| -libraryjars /usr/local/java/android-sdk/extras/android/support/v4/android-support-v4.jar |
| -libraryjars /usr/local/java/android-sdk/add-ons/addon-google_apis-google-21/libs/maps.jar |
| |
| If you're using Google's optional License Verification Library, you can |
| obfuscate its code along with your own code. You do have to preserve its |
| `ILicensingService` interface for the library to work: |
| |
| -keep public interface com.android.vending.licensing.ILicensingService |
| |
| If you're using the Android Compatibility library, you should add the |
| following line, to let ProGuard know it's ok that the library references some |
| classes that are not available in all versions of the API: |
| |
| -dontwarn android.support.** |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), and [resource files](#resourcefiles). You may |
| also want to add options for producing [useful stack traces](#stacktrace) and |
| to [remove logging](#logging). You can find a complete sample configuration in |
| `examples/standalone/android.pro` in the ProGuard distribution. |
| |
| ### A typical library {: #library} |
| |
| These options shrink, optimize, and obfuscate an entire library, keeping |
| all public and protected classes and class members, native method names, |
| and serialization code. The processed version of the library can then |
| still be used as such, for developing code based on its public API. |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -printmapping out.map |
| |
| -keep public class * { |
| public protected *; |
| } |
| |
| -keepparameternames |
| -renamesourcefileattribute SourceFile |
| -keepattributes Exceptions,InnerClasses,Signature,Deprecated, |
| SourceFile,LineNumberTable,*Annotation*,EnclosingMethod |
| |
| -keepclasseswithmembernames,includedescriptorclasses class * { |
| native <methods>; |
| } |
| |
| -keepclassmembers,allowoptimization enum * { |
| public static **[] values(); |
| public static ** valueOf(java.lang.String); |
| } |
| |
| -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(); |
| } |
| |
| This configuration should preserve everything a developers ever wants to |
| access in the library. Only if there are any other non-public classes or |
| methods that are invoked dynamically, they should be specified using |
| additional [`-keep`](usage.md#keep) options. |
| |
| The "Exceptions" attribute has to be preserved, so the compiler knows |
| which exceptions methods may throw. |
| |
| The "InnerClasses" attribute (or more precisely, its source name part) has to |
| be preserved too, for any inner classes that can be referenced from outside |
| the library. The `javac` compiler would be unable to find the inner classes |
| otherwise. |
| |
| The "Signature" attribute is required to be able to access generic types when |
| compiling in JDK 5.0 and higher. |
| |
| The [`-keepparameternames`](usage.md#keepparameternames) option keeps the |
| parameter names in the "LocalVariableTable" and "LocalVariableTypeTable" |
| attributes of public library methods. Some IDEs can present these names to the |
| developers who use the library. |
| |
| Finally, we're keeping the "Deprecated" attribute and the attributes for |
| producing [useful stack traces](#stacktrace). |
| |
| We've also added some options for for processing [native methods](#native), |
| [enumerations](#enumerations), [serializable classes](#serializable), and |
| [annotations](#annotations), which are all discussed in their respective |
| examples. |
| |
| ### All possible applications in the input jars {: #applications} |
| |
| These options shrink, optimize, and obfuscate all public applications in |
| `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -printseeds |
| |
| -keepclasseswithmembers public class * { |
| public static void main(java.lang.String[]); |
| } |
| |
| Note the use of [`-keepclasseswithmembers`](usage.md#keepclasseswithmembers). |
| We don't want to preserve all classes, just all classes that have main |
| methods, _and_ those methods. |
| |
| The [`-printseeds`](usage.md#printseeds) option prints out which classes |
| exactly will be preserved, so we know for sure we're getting what we want. |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### All possible applets in the input jars {: #applets} |
| |
| These options shrink, optimize, and obfuscate all public applets in `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -libraryjars <java.home>/jmods/java.desktop.jmod(!**.jar;!module-info.class) |
| -printseeds |
| |
| -keep public class * extends java.applet.Applet |
| |
| We're simply keeping all classes that extend the `Applet` class. |
| |
| Again, the [`-printseeds`](usage.md#printseeds) option prints out which |
| applets exactly will be preserved. |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### All possible midlets in the input jars {: #midlets} |
| |
| These options shrink, optimize, obfuscate, and preverify all public midlets in |
| `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| -microedition |
| -printseeds |
| |
| -keep public class * extends javax.microedition.midlet.MIDlet |
| |
| We're simply keeping all classes that extend the `MIDlet` class. |
| |
| The [`-microedition`](usage.md#microedition) option makes sure the class files |
| are preverified for Java Micro Edition, producing compact `StackMap` |
| attributes. It is no longer necessary to run an external preverifier. |
| |
| Be careful if you do use the external `preverify` tool on a platform with a |
| case-insensitive filing system, such as Windows. Because this tool unpacks |
| your processed jars, you should then use ProGuard's |
| [`-dontusemixedcaseclassnames`](usage.md#dontusemixedcaseclassnames) option. |
| |
| The [`-printseeds`](usage.md#printseeds) option prints out which midlets |
| exactly will be preserved. |
| |
| If applicable, you should add options for processing [native methods](#native) |
| and [resource files](#resourcefiles). |
| |
| Note that you will still have to adapt the midlet jar size in the |
| corresponding jad file; ProGuard doesn't do that for you. |
| |
| ### All possible Java Card applets in the input jars {: #jcapplets} |
| |
| These options shrink, optimize, and obfuscate all public Java Card |
| applets in `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/javacard2.2.2/lib/api.jar |
| -dontwarn java.lang.Class |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| -printseeds |
| |
| -keep public class * implements javacard.framework.Applet |
| |
| We're simply keeping all classes that implement the `Applet` interface. |
| |
| The [`-printseeds`](usage.md#printseeds) option prints out which applets |
| exactly will be preserved. |
| |
| ### All possible xlets in the input jars {: #xlets} |
| |
| These options shrink, optimize, and obfuscate all public xlets in `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/jtv1.1/javatv.jar |
| -libraryjars /usr/local/java/cdc1.1/lib/cdc.jar |
| -libraryjars /usr/local/java/cdc1.1/lib/btclasses.zip |
| -overloadaggressively |
| -repackageclasses '' |
| -allowaccessmodification |
| -printseeds |
| |
| -keep public class * implements javax.tv.xlet.Xlet |
| |
| We're simply keeping all classes that implement the `Xlet` interface. |
| |
| The [`-printseeds`](usage.md#printseeds) option prints out which xlets exactly |
| will be preserved. |
| |
| ### All possible servlets in the input jars {: #servlets} |
| |
| These options shrink, optimize, and obfuscate all public servlets in `in.jar`: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/lib/rt.jar |
| -libraryjars /usr/local/java/servlet/servlet.jar |
| -printseeds |
| |
| -keep public class * implements javax.servlet.Servlet |
| |
| Keeping all servlets is very similar to keeping all applets. The servlet API |
| is not part of the standard run-time jar, so we're specifying it as a library. |
| Don't forget to use the right path name. |
| |
| We're then keeping all classes that implement the `Servlet` interface. We're |
| using the `implements` keyword because it looks more familiar in this context, |
| but it is equivalent to `extends`, as far as ProGuard is concerned. |
| |
| The [`-printseeds`](usage.md#printseeds) option prints out which |
| servlets exactly will be preserved. |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ### Scala applications with the Scala runtime {: #scala} |
| |
| These options shrink, optimize, and obfuscate all public Scala applications in |
| `in.jar`: |
| |
| -injars in.jar |
| -injars /usr/local/java/scala-2.9.1/lib/scala-library.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| -dontwarn scala.** |
| |
| -keepclasseswithmembers public class * { |
| public static void main(java.lang.String[]); |
| } |
| |
| -keep class * implements org.xml.sax.EntityResolver |
| |
| -keepclassmembers class * { |
| ** MODULE$; |
| } |
| |
| -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool { |
| long eventCount; |
| int workerCounts; |
| int runControl; |
| scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack; |
| scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack; |
| } |
| |
| -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinWorkerThread { |
| int base; |
| int sp; |
| int runState; |
| } |
| |
| -keepclassmembernames class scala.concurrent.forkjoin.ForkJoinTask { |
| int status; |
| } |
| |
| -keepclassmembernames class scala.concurrent.forkjoin.LinkedTransferQueue { |
| scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference head; |
| scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference tail; |
| scala.concurrent.forkjoin.LinkedTransferQueue$PaddedAtomicReference cleanMe; |
| } |
| |
| The configuration is essentially the same as for [processing |
| applications](#applications), because Scala is compiled to ordinary Java |
| bytecode. However, the example processes the Scala runtime library as well. |
| The processed jar can be an order of magnitude smaller and a few times faster |
| than the original code (for the Scala code examples, for instance). |
| |
| The [`-dontwarn`](usage.md#dontwarn) option tells ProGuard not to complain |
| about some artefacts in the Scala runtime, the way it is compiled by the |
| `scalac` compiler (at least in Scala 2.9.1 and older). Note that this option |
| should always be used with care. |
| |
| The additional [`-keep`](usage.md#keepoverview) options make sure that some |
| classes and some fields that are accessed by means of introspection are not |
| removed or renamed. |
| |
| If applicable, you should add options for processing [native |
| methods](#native), [callback methods](#callback), |
| [enumerations](#enumerations), [serializable classes](#serializable), [bean |
| classes](#beans), [annotations](#annotations), and [resource |
| files](#resourcefiles). |
| |
| ## Processing common code constructs {: #commonconstructs} |
| |
| ### Processing native methods {: #native} |
| |
| If your application, applet, servlet, library, etc., contains native methods, |
| you'll want to preserve their names and their classes' names, so they can |
| still be linked to the native library. The following additional option will |
| ensure that: |
| |
| -keepclasseswithmembernames,includedescriptorclasses class * { |
| native <methods>; |
| } |
| |
| Note the use of |
| [`-keepclasseswithmembernames`](usage.md#keepclasseswithmembernames). We don't |
| want to preserve all classes or all native methods; we just want to keep the |
| relevant names from being obfuscated. The modifier |
| [includedescriptorclasses](usage.md#includedescriptorclasses) additionally |
| makes sure that the return types and parameter types aren't renamed either, so |
| the entire signatures remain compatible with the native libraries. |
| |
| ProGuard doesn't look at your native code, so it won't automatically preserve |
| the classes or class members that are invoked by the native code. These are |
| entry points, which you'll have to specify explicitly. [Callback |
| methods](callback) are discussed below as a typical example. |
| |
| ### Processing callback methods {: #callback} |
| |
| If your application, applet, servlet, library, etc., contains callback |
| methods, which are called from external code (native code, scripts,...), |
| you'll want to preserve them, and probably their classes too. They are just |
| entry points to your code, much like, say, the main method of an application. |
| If they aren't preserved by other [`-keep`](usage.md#keep) options, something |
| like the following option will keep the callback class and method: |
| |
| -keep class com.example.MyCallbackClass { |
| void myCallbackMethod(java.lang.String); |
| } |
| |
| This will preserve the given class and method from being removed or renamed. |
| |
| ### Processing enumeration classes {: #enumerations} |
| |
| If your application, applet, servlet, library, etc., contains enumeration |
| classes, you'll have to preserve some special methods. Enumerations were |
| introduced in Java 5. The java compiler translates enumerations into classes |
| with a special structure. Notably, the classes contain implementations of some |
| static methods that the run-time environment accesses by introspection (Isn't |
| that just grand? Introspection is the self-modifying code of a new |
| generation). You have to specify these explicitly, to make sure they aren't |
| removed or obfuscated: |
| |
| -keepclassmembers,allowoptimization enum * { |
| public static **[] values(); |
| public static ** valueOf(java.lang.String); |
| } |
| |
| ### Processing serializable classes {: #serializable} |
| |
| More complex applications, applets, servlets, libraries, etc., may |
| contain classes that are serialized. Depending on the way in which they |
| are used, they may require special attention: |
| |
| - Often, serialization is simply a means of transporting data, without |
| long-term storage. Classes that are shrunk and obfuscated should then |
| continue to function fine with the following additional options: |
| |
| -keepclassmembers class * implements java.io.Serializable { |
| 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(); |
| } |
| |
| The [`-keepclassmembers`](usage.md#keepclassmembers) option makes sure |
| that any serialization methods are kept. By using this option instead of |
| the basic `-keep` option, we're not forcing preservation of *all* |
| serializable classes, just preservation of the listed members of classes |
| that are actually used. |
| |
| - Sometimes, the serialized data are stored, and read back later into newer |
| versions of the serializable classes. One then has to take care the classes |
| remain compatible with their unprocessed versions and with future processed |
| versions. In such cases, the relevant classes will most likely have |
| `serialVersionUID` fields. The following options should then be sufficient |
| to ensure compatibility over time: |
| |
| -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 void writeObject(java.io.ObjectOutputStream); |
| private void readObject(java.io.ObjectInputStream); |
| java.lang.Object writeReplace(); |
| java.lang.Object readResolve(); |
| } |
| |
| The `serialVersionUID` and `serialPersistentFields` lines makes sure those |
| fields are preserved, if they are present. The `<fields>` line preserves |
| all non-static, non-transient fields, with their original names. The |
| introspection of the serialization process and the de-serialization |
| process will then find consistent names. |
| |
| - Occasionally, the serialized data have to remain compatible, but the classes |
| involved lack `serialVersionUID` fields. I imagine the original code will |
| then be hard to maintain, since the serial version UID is then computed from |
| a list of features the serializable class. Changing the class ever so |
| slightly may change the computed serial version UID. The list of features is |
| specified in the section on [Stream Unique |
| Identifiers](http://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#a4100) |
| of Sun's [Java Object Serialization |
| Specification](http://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html). |
| The following directives should at least partially ensure compatibility with |
| the original classes: |
| |
| -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(); |
| } |
| |
| The new options force preservation of the elements involved in the UID |
| computation. In addition, the user will have to manually specify all |
| interfaces of the serializable classes (using something like "`-keep |
| interface MyInterface`"), since these names are also used when computing |
| the UID. A fast but sub-optimal alternative would be simply keeping all |
| interfaces with "`-keep interface *`". |
| |
| - In the rare event that you are serializing lambda expressions in Java 8 or |
| higher, you need to preserve some methods and adapt the hard-coded names of |
| the classes in which they occur: |
| |
| -keepclassmembers class * { |
| private static synthetic java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda); |
| } |
| |
| -keepclassmembernames class * { |
| private static synthetic *** lambda$*(...); |
| } |
| |
| -adaptclassstrings com.example.Test |
| |
| This should satisfy the reflection in the deserialization code of the Java |
| run-time. |
| |
| Note that the above options may preserve more classes and class members than |
| strictly necessary. For instance, a large number of classes may implement the |
| `Serialization` interface, yet only a small number may actually ever be |
| serialized. Knowing your application and tuning the configuration often |
| produces more compact results. |
| |
| ### Processing bean classes {: #beans} |
| |
| If your application, applet, servlet, library, etc., makes extensive use of |
| introspection on bean classes to find bean editor classes, or getter and |
| setter methods, then configuration may become painful. There's not much else |
| you can do than making sure the bean class names, or the getter and setter |
| names don't change. For instance: |
| |
| -keep public class com.example.MyBean { |
| public void setMyProperty(int); |
| public int getMyProperty(); |
| } |
| |
| -keep public class com.example.MyBeanEditor |
| |
| If there are too many elements to list explicitly, wildcards in class |
| names and method signatures might be helpful. This example preserves all |
| possible setters and getters in classes in the package `mybeans`: |
| |
| -keep class mybeans.** { |
| void set*(***); |
| void set*(int, ***); |
| |
| boolean is*(); |
| boolean is*(int); |
| |
| *** get*(); |
| *** get*(int); |
| } |
| |
| The '`***`' wildcard matches any type (primitive or non-primitive, array |
| or non-array). The methods with the '`int`' arguments matches properties |
| that are lists. |
| |
| ### Processing annotations {: #annotations} |
| |
| If your application, applet, servlet, library, etc., uses annotations, you may |
| want to preserve them in the processed output. Annotations are represented by |
| attributes that have no direct effect on the execution of the code. However, |
| their values can be retrieved through introspection, allowing developers to |
| adapt the execution behavior accordingly. By default, ProGuard treats |
| annotation attributes as optional, and removes them in the obfuscation step. |
| If they are required, you'll have to specify this explicitly: |
| |
| -keepattributes *Annotation* |
| |
| For brevity, we're specifying a wildcarded attribute name, which will match |
| `RuntimeVisibleAnnotations`, `RuntimeInvisibleAnnotations`, |
| `RuntimeVisibleParameterAnnotations`, `RuntimeInvisibleParameterAnnotations`, |
| and `AnnotationDefault`. Depending on the purpose of the processed code, you |
| could refine this selection, for instance not keeping the run-time invisible |
| annotations (which are only used at compile-time). |
| |
| Some code may make further use of introspection to figure out the enclosing |
| methods of anonymous inner classes. In that case, the corresponding attribute |
| has to be preserved as well: |
| |
| -keepattributes EnclosingMethod |
| |
| ### Processing database drivers {: #database} |
| |
| Database drivers are implementations of the `Driver` interface. Since they are |
| often created dynamically, you may want to preserve any implementations that |
| you are processing as entry points: |
| |
| -keep class * implements java.sql.Driver |
| |
| This option also gets rid of the note that ProGuard prints out about |
| `(java.sql.Driver)Class.forName` constructs, if you are instantiating a driver |
| in your code (without necessarily implementing any drivers yourself). |
| |
| ### Processing ComponentUI classes {: #componentui} |
| |
| Swing UI look and feels are implemented as extensions of the `ComponentUI` |
| class. For some reason, these have to contain a static method `createUI`, |
| which the Swing API invokes using introspection. You should therefore always |
| preserve the method as an entry point, for instance like this: |
| |
| -keep class * extends javax.swing.plaf.ComponentUI { |
| public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent); |
| } |
| |
| This option also keeps the classes themselves. |
| |
| ## Processing common libraries {: #commonlibraries} |
| |
| ### Processing RMI code {: #rmi} |
| |
| Reportedly, the easiest way to handle RMI code is to process the code with |
| ProGuard first and then invoke the `rmic` tool. If that is not possible, you |
| may want to try something like this: |
| |
| -keepattributes Exceptions |
| |
| -keep interface * extends java.rmi.Remote { |
| <methods>; |
| } |
| |
| -keep class * implements java.rmi.Remote { |
| <init>(java.rmi.activation.ActivationID, java.rmi.MarshalledObject); {: #activation} |
| } |
| |
| The first [`-keep`](usage.md#keep) option keeps all your Remote interfaces and |
| their methods. The second one keeps all the implementations, along with their |
| particular RMI constructors, if any. |
| |
| The `Exceptions` attribute has to be kept too, because the RMI handling code |
| performs introspection to check whether the method signatures are compatible. |
| |
| ### Optimizing Gson code {: #gson} |
| |
| ProGuard [optimizes Gson code](optimizations.md#gson), by detecting which |
| domain classes are serialized using the Gson library, and then replacing the |
| reflection-based implementation by more efficient hard-coded serialization. |
| |
| The GSON optimization is enabled by default and doesn't require any additional |
| configuration. If you've disabled optimization, the GSON library still relies |
| on reflection on the fields of the classes that it serializes. You then need |
| to preserve the parameterless constructor and the serialized fields from being |
| removed, optimized, or obfuscated. For example: |
| |
| -keepclassmembers class com.example.SerializedClass { |
| <fields>; |
| <init>(); |
| } |
| |
| While creating the configuration, you can specify the option |
| [`-addconfigurationdebugging`](usage.md#addconfigurationdebugging), to get |
| feedback on the necessary settings at run-time. |
| |
| Alternatively, you can make sure the fields are explicitly annotated with |
| `@SerializedName`, so the names of the fields can be obfuscated. You can |
| then keep all of them at the same time with: |
| |
| -keepclasseswithmembers,allowobfuscation,includedescriptorclasses class * { |
| @com.google.gson.annotations.SerializedName <fields>; |
| } |
| |
| -keepclassmembers enum * { |
| @com.google.gson.annotations.SerializedName <fields>; |
| } |
| |
| ### Processing dependency injection {: #injection} |
| |
| If your application is using JEE-style dependency injection, the application |
| container will automatically assign instances of resource classes to fields |
| and methods that are annotated with `@Resource`. The container applies |
| introspection, even accessing private class members directly. It typically |
| constructs a resource name based on the type name and the class member name. |
| We then have to avoid that such class members are removed or renamed: |
| |
| -keepclassmembers class * { |
| @javax.annotation.Resource *; |
| } |
| |
| The Spring framework has another similar annotation `@Autowired`: |
| |
| -keepclassmembers class * { |
| @org.springframework.beans.factory.annotation.Autowired *; |
| } |
| |
| ### Processing Dagger code {: #dagger} |
| |
| Your Android application may be using the Dagger library for its dependency |
| injection. |
| |
| **Dagger 1** relies heavily on reflection, so you may need some additional |
| configuration to make sure it continues to work. DexGuard's default |
| configuration already keeps some required classes: |
| |
| -keepclassmembers,allowobfuscation class * { |
| @dagger.** *; |
| } |
| |
| -keep class **$$ModuleAdapter |
| -keep class **$$InjectAdapter |
| -keep class **$$StaticInjection |
| |
| -if class **$$ModuleAdapter |
| -keep class <1> |
| |
| -if class **$$InjectAdapter |
| -keep class <1> |
| |
| -if class **$$StaticInjection |
| -keep class <1> |
| |
| -keepnames class dagger.Lazy |
| |
| That way, Dagger can combine the corresponding pairs of classes, based on |
| their names. |
| |
| Furthermore, if your code injects dependencies into some given classes with an |
| annotation like `@Module(injects = { SomeClass.class }, ...)`, you need to |
| preserve the specified names as well: |
| |
| -keep class com.example.SomeClass |
| |
| **Dagger 2** no longer relies on reflection. You don't need to preserve any |
| classes there. |
| |
| ### Processing Butterknife code {: #butterknife} |
| |
| If your Android application includes Butterknife to inject views, you also |
| need a few lines of configuration, since Butterknife relies on reflection to |
| tie together the code at runtime: |
| |
| -keep @interface butterknife.* |
| |
| -keepclasseswithmembers class * { |
| @butterknife.* <fields>; |
| } |
| |
| -keepclasseswithmembers class * { |
| @butterknife.* <methods>; |
| } |
| |
| -keepclasseswithmembers class * { |
| @butterknife.On* <methods>; |
| } |
| |
| -keep class **$$ViewInjector { |
| public static void inject(...); |
| public static void reset(...); |
| } |
| |
| -keep class **$$ViewBinder { |
| public static void bind(...); |
| public static void unbind(...); |
| } |
| |
| -if class **$$ViewBinder |
| -keep class <1> |
| |
| -keep class **_ViewBinding { |
| <init>(<1>, android.view.View); |
| } |
| |
| -if class **_ViewBinding |
| -keep class <1> |
| |
| These settings preserve the Butterknife annotations, the annotated fields and |
| methods, and the generated classes and methods that Butterknife accesses by |
| reflection. |
| |
| ## Further processing possibilities {: #furtherpossibilities} |
| |
| ### Processing resource files {: #resourcefiles} |
| |
| If your application, applet, servlet, library, etc., contains resource files, |
| it may be necessary to adapt their names and/or their contents when the |
| application is obfuscated. The following two options can achieve this |
| automatically: |
| |
| -adaptresourcefilenames **.properties,**.gif,**.jpg |
| -adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF |
| |
| The [`-adaptresourcefilenames`](usage.md#adaptresourcefilenames) option in |
| this case renames properties files and image files in the processed output, |
| based on the obfuscated names of their corresponding class files (if any). The |
| [`-adaptresourcefilecontents`](usage.md#adaptresourcefilecontents) option |
| looks for class names in properties files and in the manifest file, and |
| replaces these names by the obfuscated names (if any). You'll probably want to |
| adapt the filters to suit your application. |
| |
| ### Processing manifest files {: #manifestfiles} |
| |
| As illustrated in the previous section, manifest files can be treated like |
| ordinary resource files. ProGuard can adapt obfuscated class names in the |
| files, but it won't make any other changes. If you want anything else, you |
| should apply an external tool. For instance, if a manifest file contains |
| signing information, you should sign the jar again after it has been |
| processed. |
| |
| If you're merging several input jars into a single output jar, you'll have to |
| pick one, typically by specifying [filters](usage.md#filters): |
| |
| -injars in1.jar |
| -injars in2.jar(!META-INF/MANIFEST.MF) |
| -injars in3.jar(!META-INF/MANIFEST.MF) |
| -outjars out.jar |
| |
| The filters will let ProGuard copy the manifest file from the first jar and |
| ignore any manifest files in the second and third input jars. Note that |
| ProGuard will leave the order of the files in the jars unchanged; manifest |
| files are not necessarily put first. |
| |
| ### Producing useful obfuscated stack traces {: #stacktrace} |
| |
| These options let obfuscated applications or libraries produce stack traces |
| that can still be deciphered later on: |
| |
| -printmapping out.map |
| |
| -renamesourcefileattribute SourceFile |
| -keepattributes SourceFile,LineNumberTable |
| |
| We're keeping all source file attributes, but we're replacing their values by |
| the string "SourceFile". We could use any string. This string is already |
| present in all class files, so it doesn't take up any extra space. If you're |
| working with J++, you'll want to keep the "SourceDir" attribute as well. |
| |
| We're also keeping the line number tables of all methods. |
| |
| Whenever both of these attributes are present, the Java run-time environment |
| will include line number information when printing out exception stack traces. |
| |
| The information will only be useful if we can map the obfuscated names back to |
| their original names, so we're saving the mapping to a file `out.map`. The |
| information can then be used by the [ReTrace](retrace/index.html) tool to |
| restore the original stack trace. |
| |
| ### Obfuscating package names {: #repackaging} |
| |
| Package names can be obfuscated in various ways, with increasing levels of |
| obfuscation and compactness. For example, consider the following classes: |
| |
| mycompany.myapplication.MyMain |
| mycompany.myapplication.Foo |
| mycompany.myapplication.Bar |
| mycompany.myapplication.extra.FirstExtra |
| mycompany.myapplication.extra.SecondExtra |
| mycompany.util.FirstUtil |
| mycompany.util.SecondUtil |
| |
| Let's assume the class name `mycompany.myapplication.MyMain` is the main |
| application class that is kept by the configuration. All other class names can |
| be obfuscated. |
| |
| By default, packages that contain classes that can't be renamed aren't renamed |
| either, and the package hierarchy is preserved. This results in obfuscated |
| class names like these: |
| |
| mycompany.myapplication.MyMain |
| mycompany.myapplication.a |
| mycompany.myapplication.b |
| mycompany.myapplication.a.a |
| mycompany.myapplication.a.b |
| mycompany.a.a |
| mycompany.a.b |
| |
| The [`-flattenpackagehierarchy`](usage.md#flattenpackagehierarchy) option |
| obfuscates the package names further, by flattening the package hierarchy of |
| obfuscated packages: |
| |
| -flattenpackagehierarchy 'myobfuscated' |
| |
| The obfuscated class names then look as follows: |
| |
| mycompany.myapplication.MyMain |
| mycompany.myapplication.a |
| mycompany.myapplication.b |
| myobfuscated.a.a |
| myobfuscated.a.b |
| myobfuscated.b.a |
| myobfuscated.b.b |
| |
| Alternatively, the [`-repackageclasses`](usage.md#repackageclasses) option |
| obfuscates the entire packaging, by combining obfuscated classes into a single |
| package: |
| |
| -repackageclasses 'myobfuscated' |
| |
| The obfuscated class names then look as follows: |
| |
| mycompany.myapplication.MyMain |
| mycompany.myapplication.a |
| mycompany.myapplication.b |
| myobfuscated.a |
| myobfuscated.b |
| myobfuscated.c |
| myobfuscated.d |
| |
| Additionally specifying the |
| [`-allowaccessmodification`](usage.md#allowaccessmodification) option allows |
| access permissions of classes and class members to be broadened, opening up |
| the opportunity to repackage all obfuscated classes: |
| |
| -repackageclasses 'myobfuscated' |
| -allowaccessmodification |
| |
| The obfuscated class names then look as follows: |
| |
| mycompany.myapplication.MyMain |
| myobfuscated.a |
| myobfuscated.b |
| myobfuscated.c |
| myobfuscated.d |
| myobfuscated.e |
| myobfuscated.f |
| |
| The specified target package can always be the root package. For |
| instance: |
| |
| -repackageclasses '' |
| -allowaccessmodification |
| |
| The obfuscated class names are then the shortest possible names: |
| |
| mycompany.myapplication.MyMain |
| a |
| b |
| c |
| d |
| e |
| f |
| |
| Note that not all levels of obfuscation of package names may be acceptable for |
| all code. Notably, you may have to take into account that your application may |
| contain [resource files](#resourcefiles) that have to be adapted. |
| |
| ### Removing logging code {: #logging} |
| |
| You can let ProGuard remove logging code. The trick is to specify that the |
| logging methods don't have side-effects — even though they actually do, since |
| they write to the console or to a log file. ProGuard will take your word for |
| it and remove the invocations (in the optimization step) and if possible the |
| logging classes and methods themselves (in the shrinking step). |
| |
| For example, this configuration removes invocations of the Android |
| logging methods: |
| |
| -assumenosideeffects class android.util.Log { |
| public static boolean isLoggable(java.lang.String, int); |
| public static int v(...); |
| public static int i(...); |
| public static int w(...); |
| public static int d(...); |
| public static int e(...); |
| } |
| |
| The wildcards are a shortcut to match all versions of the methods. Be careful |
| not to use a `*` wildcard to match all methods, because it would also match |
| methods like `wait()`, higher up the hierarchy. Removing those invocations |
| will generally break your code. |
| |
| Note that you generally can't remove logging code that uses |
| `System.out.println`, since you would be removing all invocations of |
| `java.io.PrintStream#println`, which could break your application. You can |
| work around it by creating your own logging methods and let ProGuard remove |
| those. |
| |
| Logging statements often contain implicit calls that perform string |
| concatenation. They no longer serve a purpose after the logging calls have |
| been removed. You can let ProGuard clean up such constructs as well by |
| providing additional hints: |
| |
| -assumenoexternalsideeffects class java.lang.StringBuilder { |
| public java.lang.StringBuilder(); |
| public java.lang.StringBuilder(int); |
| public java.lang.StringBuilder(java.lang.String); |
| public java.lang.StringBuilder append(java.lang.Object); |
| public java.lang.StringBuilder append(java.lang.String); |
| public java.lang.StringBuilder append(java.lang.StringBuffer); |
| public java.lang.StringBuilder append(char[]); |
| public java.lang.StringBuilder append(char[], int, int); |
| public java.lang.StringBuilder append(boolean); |
| public java.lang.StringBuilder append(char); |
| public java.lang.StringBuilder append(int); |
| public java.lang.StringBuilder append(long); |
| public java.lang.StringBuilder append(float); |
| public java.lang.StringBuilder append(double); |
| public java.lang.String toString(); |
| } |
| |
| -assumenoexternalreturnvalues public final class java.lang.StringBuilder { |
| public java.lang.StringBuilder append(java.lang.Object); |
| public java.lang.StringBuilder append(java.lang.String); |
| public java.lang.StringBuilder append(java.lang.StringBuffer); |
| public java.lang.StringBuilder append(char[]); |
| public java.lang.StringBuilder append(char[], int, int); |
| public java.lang.StringBuilder append(boolean); |
| public java.lang.StringBuilder append(char); |
| public java.lang.StringBuilder append(int); |
| public java.lang.StringBuilder append(long); |
| public java.lang.StringBuilder append(float); |
| public java.lang.StringBuilder append(double); |
| } |
| |
| Be careful specifying your own assumptions, since they can easily break |
| your code. |
| |
| ### Optimizing for Android SDK versions {: #androidsdk} |
| |
| You can let ProGuard optimize the code for the range of Android versions that |
| you intend to support — the range between the minimum SDK version and the |
| maximum SDK version in your Android manifest. It then removes all code for SDK |
| versions that are not relevant, for example in the various Android support |
| libraries. |
| |
| For example, if the minimum SDK version in your Android manifest is 19, you |
| can optimize the code accordingly: |
| |
| -assumevalues class android.os.Build$VERSION { |
| int SDK_INT = 19..2147483647; |
| } |
| |
| You can also specify return values for methods. The "`=`" keyword and the |
| "`return`" keyword are equivalent. Be careful specifying assumptions, since |
| they can easily break your code. |
| |
| ### Restructuring the output archives {: #restructuring} |
| |
| In simple applications, all output classes and resources files are merged into |
| a single jar. For example: |
| |
| -injars classes |
| -injars in1.jar |
| -injars in2.jar |
| -injars in3.jar |
| -outjars out.jar |
| |
| This configuration merges the processed versions of the files in the `classes` |
| directory and the three jars into a single output jar `out.jar`. |
| |
| If you want to preserve the structure of your input jars (and/or apks, aars, |
| wars, ears, jmods, zips, or directories), you can specify an output directory |
| (or an apk, an aar, a war, an ear, a jmod, or a zip). For example: |
| |
| -injars in1.jar |
| -injars in2.jar |
| -injars in3.jar |
| -outjars out |
| |
| The input jars will then be reconstructed in the directory `out`, with their |
| original names. |
| |
| You can also combine archives into higher level archives. For example: |
| |
| -injars in1.jar |
| -injars in2.jar |
| -injars in3.jar |
| -outjars out.war |
| |
| The other way around, you can flatten the archives inside higher level |
| archives into simple archives: |
| |
| -injars in.war |
| -outjars out.jar |
| |
| This configuration puts the processed contents of all jars inside `in.war` |
| (plus any other contents of `in.war`) into `out.jar`. |
| |
| If you want to combine input jars (and/or apks, aars, wars, ears, jmods, zips, |
| or directories) into output jars (and/or apks, aars, wars, ears, jmods, zips, |
| or directories), you can group the [`-injars`](usage.md#injars) and |
| [`-outjars`](usage.md#outjars) options. For example: |
| |
| -injars base_in1.jar |
| -injars base_in2.jar |
| -injars base_in3.jar |
| -outjars base_out.jar |
| |
| -injars extra_in.jar |
| -outjars extra_out.jar |
| |
| This configuration puts the processed results of all `base_in*.jar` jars into |
| `base_out.jar`, and the processed results of the `extra_in.jar` into |
| `extra_out.jar`. Note that only the order of the options matters; the |
| additional whitespace is just for clarity. |
| |
| This grouping, archiving, and flattening can be arbitrarily complex. ProGuard |
| always tries to package output archives in a sensible way, reconstructing the |
| input entries as much as required. |
| |
| ### Filtering the input and the output {: #filtering} |
| |
| If you want even greater control, you can add [filters](usage.md#filters) to |
| the input and the output, filtering out apks, jars, aars, wars, ears, jmods, |
| zips, and/or ordinary files. For example, if you want to disregard certain |
| files from an input jar: |
| |
| -injars in.jar(!images/**) |
| -outjars out.jar |
| |
| This configuration removes any files in the `images` directory and its |
| subdirectories. |
| |
| Such filters can be convenient for avoiding warnings about duplicate files in |
| the output. For example, only keeping the manifest file from a first input |
| jar: |
| |
| -injars in1.jar |
| -injars in2.jar(!META-INF/MANIFEST.MF) |
| -injars in3.jar(!META-INF/MANIFEST.MF) |
| -outjars out.jar |
| |
| Another useful application is ignoring unwanted files from the runtime library |
| module: |
| |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| The filter makes ProGuard disregard redundant jars inside the module, and |
| module info classes that would only cause conflicts with duplicate names. |
| |
| It is also possible to filter the jars (and/or apks, aabs, aars, wars, ears, |
| jmods, zips) themselves, based on their names. For example: |
| |
| -injars in(**/acme_*.jar;) |
| -outjars out.jar |
| |
| Note the semi-colon in the filter; the filter in front of it applies to jar |
| names. In this case, only `acme_*.jar` jars are read from the directory `in` |
| and its subdirectories. Filters for war names, ear names, and zip names can be |
| prefixed with additional semi-colons. All types of filters can be combined. |
| They are orthogonal. |
| |
| On the other hand, you can also filter the output, in order to control what |
| content goes where. For example: |
| |
| -injars in.jar |
| -outjars code_out.jar(**.class) |
| -outjars resources_out.jar |
| |
| This configuration splits the processed output, sending `**.class` files to |
| `code_out.jar`, and all remaining files to `resources_out.jar`. |
| |
| Again, the filtering can be arbitrarily complex, especially when combined with |
| grouping input and output. |
| |
| ### Processing multiple applications at once {: #multiple} |
| |
| You can process several dependent or independent applications (or applets, |
| midlets,...) in one go, in order to save time and effort. ProGuard's input and |
| output handling offers various ways to keep the output nicely structured. |
| |
| The easiest way is to specify your input jars (and/or wars, ears, zips, and |
| directories) and a single output directory. ProGuard will then reconstruct the |
| input in this directory, using the original jar names. For example, showing |
| just the input and output options: |
| |
| -injars application1.jar |
| -injars application2.jar |
| -injars application3.jar |
| -outjars processed_applications |
| |
| After processing, the directory `processed_applications` will contain |
| processed versions of application jars, with their original names. |
| |
| ### Incremental obfuscation {: #incremental} |
| |
| After having [processed an application](#application), e.g. ProGuard itself, |
| you can still incrementally add other pieces of code that depend on it, e.g. |
| the ProGuard GUI: |
| |
| -injars proguardgui.jar |
| -outjars proguardgui_out.jar |
| -injars proguard.jar |
| -outjars proguard_out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -applymapping proguard.map |
| |
| -keep public class proguard.gui.ProGuardGUI { |
| public static void main(java.lang.String[]); |
| } |
| |
| We're reading both unprocessed jars as input. Their processed contents will go |
| to the respective output jars. The [`-applymapping`](usage.md#applymapping) |
| option then makes sure the ProGuard part of the code gets the previously |
| produced obfuscation mapping. The final application will consist of the |
| obfuscated ProGuard jar and the additional obfuscated GUI jar. |
| |
| The added code in this example is straightforward; it doesn't affect the |
| original code. The `proguard_out.jar` will be identical to the one produced in |
| the initial processing step. If you foresee adding more complex extensions to |
| your code, you should specify the options |
| [`-useuniqueclassmembernames`](usage.md#useuniqueclassmembernames), |
| [`-dontshrink`](usage.md#dontshrink), and |
| [`-dontoptimize`](usage.md#dontoptimize) *in the original processing step*. |
| These options ensure that the obfuscated base jar will always remain usable |
| without changes. You can then specify the base jar as a library jar: |
| |
| -injars proguardgui.jar |
| -outjars proguardgui_out.jar |
| -libraryjars proguard.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| -applymapping proguard.map |
| |
| -keep public class proguard.gui.ProGuardGUI { |
| public static void main(java.lang.String[]); |
| } |
| |
| ## Other uses {: #otheruses} |
| |
| ### Preverifying class files for Java Micro Edition {: #microedition} |
| |
| Even if you're not interested in shrinking, optimizing, and obfuscating your |
| midlets, as shown in the [midlets example](#midlets), you can still use |
| ProGuard to preverify the class files for Java Micro Edition. ProGuard |
| produces slightly more compact results than the traditional external |
| preverifier. |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/midpapi20.jar |
| -libraryjars /usr/local/java/wtk2.5.2/lib/cldcapi11.jar |
| |
| -dontshrink |
| -dontoptimize |
| -dontobfuscate |
| |
| -microedition |
| |
| We're not processing the input, just making sure the class files are |
| preverified by targeting them at Java Micro Edition with the |
| [`-microedition`](usage.md#microedition) option. Note that we don't need any |
| [`-keep`](usage.md#keep) options to specify entry points; all class files are |
| simply preverified. |
| |
| ### Upgrading old class files to Java 6 {: #upgrade} |
| |
| The following options upgrade class files to Java 6, by updating their |
| internal version numbers and preverifying them. The class files can then be |
| loaded more efficiently by the Java 6 Virtual Machine. |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| -dontshrink |
| -dontoptimize |
| -dontobfuscate |
| |
| -target 1.6 |
| |
| We're not processing the input, just retargeting the class files with the |
| [`-target`](usage.md#target) option. They will automatically be preverified |
| for Java 6 as a result. Note that we don't need any `-keep` options to specify |
| entry points; all class files are simply updated and preverified. |
| |
| ### Finding dead code {: #deadcode} |
| |
| These options list unused classes, fields, and methods in the application |
| `com.example.MyApplication`: |
| |
| -injars in.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| -dontoptimize |
| -dontobfuscate |
| -dontpreverify |
| -printusage |
| |
| -keep public class com.example.MyApplication { |
| public static void main(java.lang.String[]); |
| } |
| |
| We're not specifying an output jar, just printing out some results. We're |
| saving some processing time by skipping the other processing steps. |
| |
| The java compiler inlines primitive constants and String constants (`static |
| final` fields). ProGuard would therefore list such fields as not being used in |
| the class files that it analyzes, even if they *are* used in the source files. |
| We can add a [`-keepclassmembers`](usage.md#keepclassmembers) option that |
| keeps those fields a priori, in order to avoid having them listed: |
| |
| -keepclassmembers class * { |
| static final % *; |
| static final java.lang.String *; |
| } |
| |
| ### Printing out the internal structure of class files {: #structure} |
| |
| These options print out the internal structure of all class files in the |
| input jar: |
| |
| -injars in.jar |
| |
| -dontshrink |
| -dontoptimize |
| -dontobfuscate |
| -dontpreverify |
| |
| -dump |
| |
| Note how we don't need to specify the Java run-time jar, because we're not |
| processing the input jar at all. |
| |
| ### Using annotations to configure ProGuard {: #annotated} |
| |
| The traditional ProGuard configuration allows to keep a clean separation |
| between the code and the configuration for shrinking, optimization, and |
| obfuscation. However, it is also possible to define specific annotations, and |
| then annotate the code to configure the processing. |
| |
| You can find a set of such predefined annotations in `lib/annotations.jar` in |
| the ProGuard distribution. The corresponding ProGuard configuration (or |
| meta-configuration, if you prefer) is specified in |
| `annotations/annotations.pro`. With these files, you can start annotating your |
| code. For instance, a java source file `Application.java` can be annotated as |
| follows: |
| |
| @KeepApplication |
| public class Application { |
| .... |
| } |
| |
| The ProGuard configuration file for the application can then be simplified by |
| leveraging these annotations: |
| |
| -injars in.jar |
| -outjars out.jar |
| -libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class) |
| |
| -include lib/annotations.pro |
| |
| The annotations are effectively replacing the application-dependent `-keep` |
| options. You may still wish to add traditional [`-keep`](usage.md#keep) |
| options for processing [native methods](#native), |
| [enumerations](#enumerations), [serializable classes](#serializable), and |
| [annotations](#annotations). |
| |
| The directory `examples/annotations` contains more examples that illustrate |
| some of the possibilities. |