1410 lines
51 KiB
Markdown
1410 lines
51 KiB
Markdown
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
|
|
```sh
|
|
bin/proguard @myconfig.pro
|
|
```
|
|
|
|
The configuration file specifies the input, the output, and the entry
|
|
points of the application:
|
|
```proguard
|
|
-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[]`.
|
|
|
|
You can refine your keep rules using the ProGuard Playground which visualizes
|
|
how your keep rules match the entities in your app.
|
|
|
|
<iframe frameborder="0" width="100%" height="200px" style="border-radius: 0.25rem; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);" src="https://playground.proguard.com/p/FT5qr8?embed"></iframe>
|
|
|
|
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:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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 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.
|
|
```proguard
|
|
-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 Signature,Exceptions,*Annotation*,
|
|
InnerClasses,PermittedSubclasses,EnclosingMethod,
|
|
Deprecated,SourceFile,LineNumberTable
|
|
|
|
-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 "Signature" attribute is required to be able to access generic types.
|
|
|
|
The "Exceptions" attribute has to be preserved, so the compiler knows
|
|
which exceptions methods may throw.
|
|
|
|
The various "\*Annotations\*" attributes contain any annotations, which
|
|
developers might need to access through reflection.
|
|
|
|
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 "PermittedSubclasses" attribute defines sealed classes, which developers
|
|
can't extend further.
|
|
|
|
The "EnclosingMethod" attribute marks classes that are defined inside methods.
|
|
|
|
The "Deprecated" attribute marks any deprecated classes, fields, or
|
|
methods, which may be useful for developers to know.
|
|
|
|
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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-keepclassmembers class * {
|
|
@javax.annotation.Resource *;
|
|
}
|
|
```
|
|
|
|
The Spring framework has another similar annotation `@Autowired`:
|
|
```proguard
|
|
-keepclassmembers class * {
|
|
@org.springframework.beans.factory.annotation.Autowired *;
|
|
}
|
|
```
|
|
|
|
## 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:
|
|
```proguard
|
|
-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):
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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](../tools/retrace.md) 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:
|
|
```proguard
|
|
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:
|
|
```proguard
|
|
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:
|
|
```proguard
|
|
-flattenpackagehierarchy 'myobfuscated'
|
|
```
|
|
|
|
The obfuscated class names then look as follows:
|
|
```proguard
|
|
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:
|
|
```proguard
|
|
-repackageclasses 'myobfuscated'
|
|
```
|
|
|
|
The obfuscated class names then look as follows:
|
|
```proguard
|
|
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:
|
|
```proguard
|
|
-repackageclasses 'myobfuscated'
|
|
-allowaccessmodification
|
|
```
|
|
|
|
The obfuscated class names then look as follows:
|
|
```proguard
|
|
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:
|
|
```proguard
|
|
-repackageclasses ''
|
|
-allowaccessmodification
|
|
```
|
|
|
|
The obfuscated class names are then the shortest possible names:
|
|
```proguard
|
|
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 some
|
|
logging methods:
|
|
```proguard
|
|
-assumenosideeffects class com.example.MyLogger {
|
|
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:
|
|
```proguard
|
|
-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.
|
|
|
|
### Restructuring the output archives {: #restructuring}
|
|
|
|
In simple applications, all output classes and resources files are merged into
|
|
a single jar. For example:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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.
|
|
```proguard
|
|
-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.
|
|
```proguard
|
|
-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`:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```proguard
|
|
-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:
|
|
```java
|
|
@KeepApplication
|
|
public class Application {
|
|
....
|
|
}
|
|
```
|
|
|
|
The ProGuard configuration file for the application can then be simplified by
|
|
leveraging these annotations:
|
|
```proguard
|
|
-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.
|