ProGuard can also be used to list unused classes, fields, and methods in an application, and to print out the internal structure of class files.
Input jars | ||||||
Shrunk code | ||||||
Optimized code | ||||||
- shrink → | - optimize → | - obfuscate → | Output jars | |||
Library jars | ----------------- (unchanged) -----------------→ | Library jars |
ProGuard typically reads the input jars (or wars, ears, zips, or directories). It then shrinks, optimizes, and obfuscates them. It then writes the results to one or more output jars (or wars, ears, zips, or directories). The input jars can optionally contain resource files. ProGuard copies all non-class resource files from the input jars to the output jars. Their names and contents remain unchanged.
ProGuard requires the library jars (or wars, ears, zips, or directories) of the input jars to be specified. It can then reconstruct class hierarchies and other class dependencies, which are necessary for proper shrinking, optimization, and obfuscation. The library jars themselves always remain unchanged. You should still put them in the class path of your final application.
In order to determine which code has to be preserved and which code can be discarded or obfuscated, you have to specify one or more entry points to your code. These entry points are typically classes with main methods, applets, midlets, etc.
Any classes or class members of your code that are created or invoked dynamically (that is, by name) have to be specified as entry points too. It is generally impossible to determine these cases automatically, but ProGuard will offer some suggestions if keeping some classes or class members appears necessary. For proper results, you should at least be somewhat familiar with the code that you are processing.
ProGuard does handle Class.forName("SomeClass")
and
SomeClass.class
constructs automatically. The referenced classes
are preserved in the shrinking phase, and the string arguments are properly
replaced in the obfuscation phase. With variable string arguments, it is
generally impossible to determine their possible values (they might be read
from a configuration file, for instance). However, as mentioned, 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.