Each of these steps is optional. For instance, ProGuard can also be used to just list dead code in an application, or to preverify class files for efficient use in Java 6.
Input jars | ||||||||
Shrunk code | ||||||||
Optim. code | Output jars | |||||||
- shrink → | - optimize → | - obfuscate → | Obfusc. code | - preverify → | ||||
Library jars | ------------------------------- (unchanged) -------------------------------→ | Library jars |
ProGuard first reads the input jars (or aars, wars, ears, zips, apks, or directories). It then subsequently shrinks, optimizes, obfuscates, and preverifies them. You can optionally let ProGuard perform multiple optimization passes. ProGuard writes the processed results to one or more output jars (or aars, wars, ears, zips, apks, or directories). The input may contain resource files, whose names and contents can optionally be updated to reflect the obfuscated class names.
ProGuard requires the library jars (or aars, wars, ears, zips, apks, or directories) of the input jars to be specified. These are essentially the libraries that you would need for compiling the code. ProGuard uses them to reconstruct the class dependencies that are necessary for proper processing. The library jars themselves always remain unchanged. You should still put them in the class path of your final application.
The Usage section of this manual describes the
necessary -keep
options and
the Examples section provides plenty of examples.
Class.forName()
constructs may
refer to any class at run-time. It is generally impossible to compute which
classes have to be preserved (with their original names), since the class
names might be read from a configuration file, for instance. You therefore
have to specify them in your ProGuard configuration, with the same
simple -keep
options.
However, ProGuard will already detect and handle the following cases for you:
Class.forName("SomeClass")
SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod", new Class[] {})
SomeClass.class.getMethod("someMethod", new Class[] { A.class })
SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")
Furthermore, ProGuard will offer some suggestions if keeping some classes or
class members appears necessary. For example, ProGuard will note constructs
like "(SomeClass)Class.forName(variable).newInstance()
". These
might be an indication that the class or interface SomeClass
and/or its implementations may need to be preserved. You can then adapt your
configuration accordingly.
For proper results, you should at least be somewhat familiar with the code that you are processing. Obfuscating code that performs a lot of reflection may require trial and error, especially without the necessary information about the internals of the code.