java -jar proguard.jar
options ...
lib
directory of the
ProGuard distribution. Options can also be put in one or more configuration
files. Typically, you'll put most options in a configuration file (say,
myconfig.pro
), and just call:
java -jar proguard.jar @myconfig.pro
java -jar proguard.jar @myconfig.pro -verbose
In a configuration file, a #
sign and all remaining
characters on that line are ignored, allowing you to add comments.
Extra whitespace between words and delimiters is ignored. To specify file names with spaces or special characters, words can be quoted with single or double quotes. Note that the quotes may need to be escaped when used on the command line, to avoid them being gobbled by the shell.
Options can be grouped arbitrarily in arguments on the command line and in lines in configuration files. This means that you can quote any arbitrary section of command line options, to avoid shell expansion of special characters, for instance.
The order of the options is generally irrelevant. They can be abbreviated to their first unique characters.
The sections below provide more details:
Keep
Options
@
filename-include
filename'.-include
filename-basedirectory
directoryname-injars
class_path-injars
options.-outjars
class_path-injars
options will be written to the named jars. This allows you to collect the
contents of groups of input jars into corresponding groups of output jars.
In addition, the output entries can be filtered, as explained in the filters section. Each processed class file or resource
file is then written to the first output entry with a matching filter,
within the group of output jars.
You must avoid letting the output files overwrite any input files. For
better readability, class path entries can be specified using multiple
-outjars
options. Without any -outjars
options,
no jars will be written.
-libraryjars
class_path-libraryjars
options.
Please note that the boot path and the class path set for running ProGuard are not considered when looking for library classes. This means that you explicitly have to specify the run-time jar that your code will use. Although this may seem cumbersome, it allows you to process applications targeted at different run-time environments. For example, you can process J2SE applications as well as JME midlets, just by specifying the appropriate run-time jar.
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-target
version1.0
, 1.1
,
1.2
, 1.3
, 1.4
, 1.5
(or
just 5
), or 1.6
(or just 6
). By
default, the version numbers of the class files are left unchanged. For
example, you may want to upgrade class
files to Java 6, by changing their version numbers and having them
preverified.-forceprocessing
-keep
[,modifier,...]
class_specification-keepclassmembers
[,modifier,...]
class_specificationSerializable
interface.-keepclasseswithmembers
[,modifier,...]
class_specification-keepnames
class_specification-keep
,allowshrinking
class_specification
Specifies classes and class members whose names are to be preserved, if
they aren't removed in the shrinking phase. For example, you may want to
keep all class names of classes
that implement the Serializable
interface, so that the
processed code remains compatible with any originally serialized classes.
Classes that aren't used at all can still be removed. Only applicable when
obfuscating.
-keepclassmembernames
class_specification-keepclassmembers
,allowshrinking
class_specification
Specifies class members whose names are to be preserved, if they aren't
removed in the shrinking phase. For example, you may want to preserve the
name of the synthetic class$
methods when processing a library, so obfuscators can
detect it again when processing an application that uses the processed
library (although ProGuard itself doesn't need this). Only applicable when
obfuscating.
-keepclasseswithmembernames
class_specification-keepclasseswithmembers
,allowshrinking
class_specification
Specifies classes and class members whose names are to be preserved, on the condition that all of the specified class members are present after the shrinking phase. For example, you may want to keep all native method names and the names of their classes, so that the processed code can still link with the native library code. Native methods that aren't used at all can still be removed. If a class file is used, but none of its native methods are, its name will still be obfuscated. Only applicable when obfuscating.
-printseeds
[filename]-keep
options. The list is printed to the standard
output or to the given file. The list can be useful to verify if the
intended class members are really found, especially if you're using
wildcards. For example, you may want to list all the applications or all the applets that you are keeping.-dontshrink
-keep
options, and the ones on which
they depend, directly or indirectly. A shrinking step is also applied
after each optimization step, since some optimizations may open the
possibility to remove more classes and class members.-printusage
[filename]-whyareyoukeeping
class_specification-verbose
option if specified, the traces
include full field and method signatures. Only applicable when
shrinking.-dontoptimize
-optimizationpasses
n-assumenosideeffects
class_specificationSystem.currentTimeMillis()
, so that any idle calls to it will
be removed. Note that ProGuard applies the option to the entire hierarchy
of the specified methods. Only applicable when optimizing. In general,
making assumptions can be dangerous; you can easily break the processed
code. Only use this option if you know what you're doing!-allowaccessmodification
-repackageclasses
option).
Counter-indication: you probably shouldn't use this option when processing code that is to be used as a library, since classes and class members that weren't designed to be public in the API may become public.
-mergeinterfacesaggressively
Counter-indication: setting this option can reduce the performance of the processed code on some JVMs, since advanced just-in-time compilation tend to favor more interfaces with fewer implementing classes.
-dontobfuscate
-keep
options.
Internal attributes that are useful for debugging, such as source files
names, variable names, and line numbers are removed.-printmapping
[filename]-applymapping
filename-useuniqueclassmembernames
.
Only applicable when obfuscating.-obfuscationdictionary
filename#
sign are ignored. Note that an
obfuscation dictionary hardly improves the obfuscation. Decent compilers
can automatically replace them, and the effect can fairly simply be undone
by obfuscating again with simpler names. The most useful application is
specifying strings that are typically already present in class files (such
as 'Code'), thus reducing the class file sizes just a little bit more.
Only applicable when obfuscating.-classobfuscationdictionary
filename-obfuscationdictionary
.
Only applicable when obfuscating.-packageobfuscationdictionary
filename-obfuscationdictionary
.
Only applicable when obfuscating.-overloadaggressively
Counter-indication: the resulting class files fall within the Java bytecode specification (cfr. The Java Virtual Machine Specification, Second Edition, first paragraphs of Section 4.5 and Section 4.6), even though this kind of overloading is not allowed in the Java language (cfr. The Java Language Specification, Second Edition, Section 8.3 and Section 8.4.7). Still, some tools have problems with it. Notably:
javac
compiler produces an exception when
compiling with such a library (cfr. Bug
#4216736). You probably shouldn't use this option for processing
libraries.
pack200
tool reportedly has problems with
overloaded class members.
-useuniqueclassmembernames
For instance, consider two distinct interfaces containing methods with the same name and signature. Without this option, these methods may get different obfuscated names in a first obfuscation step. If a patch is then added containing a class that implements both interfaces, ProGuard will have to enforce the same method name for both methods in an incremental obfuscation step. The original obfuscated code is changed, in order to keep the resulting code consistent. With this option in the initial obfuscation step, such renaming will never be necessary.
This option is only applicable when obfuscating. In fact, if you are planning on performing incremental obfuscation, you probably want to avoid shrinking and optimization altogether, since these steps could remove or modify parts of your code that are essential for later additions.
-dontusemixedcaseclassnames
-flattenpackagehierarchy
[package_name]-repackageclasses
[package_name]-flattenpackagehierarchy
option. It is another example of further obfuscating package names. It can
make the processed code even smaller and less comprehensible. Its
deprecated name is -defaultpackage
. Only applicable when
obfuscating.
Counter-indication: classes that look for resource files in their package directories will no longer work properly if they are moved elsewhere. When in doubt, just leave the packaging untouched by not using this option.
-keepattributes
[attribute_name,...]-keepattributes
directives.
Multiple attributes should be separated by commas. An empty list preserves
all attributes. Attribute names can contain ? and
* wildcards, and they can be preceded by the ! negator (much
like file name filters). Typical optional
attributes are Exceptions
, Signature
,
Deprecated
, SourceFile
, SourceDir
,
LineNumberTable
, LocalVariableTable
,
LocalVariableTypeTable
, Synthetic
,
EnclosingMethod
, RuntimeVisibleAnnotations
,
RuntimeInvisibleAnnotations
,
RuntimeVisibleParameterAnnotations
,
RuntimeInvisibleParameterAnnotations
, and
AnnotationDefault
. The InnerClasses
attribute
name can be specified as well, referring to the source name part of this
attribute. For example, you should at least keep the
Exceptions
, InnerClasses
, and
Signature
attributes when processing a library. As another example,
you should keep the SourceFile
and
LineNumberTable
attributes for producing useful obfuscated stack
traces. Only applicable when obfuscating.-renamesourcefileattribute
[string]SourceFile
attributes (and SourceDir
attributes) of the class files.
Note that the attribute has to be present to start with, so it also has to
be preserved explicitly using the -keepattributes
directive.
For example, you may want to have your processed libraries and
applications produce useful obfuscated
stack traces. Only applicable when obfuscating.-adaptresourcefilenames
[filter]-adaptresourcefilecontents
[filter]-dontpreverify
-microedition
-verbose
-dontnote
-dontwarn
-ignorewarnings
-printconfiguration
[filename]-dump
[filename]Each input entry can be:
The paths of directly specified class files and resource files is ignored, so class files should generally be part of a jar file, a war file, an ear file, a zip file, or a directory. In addition, the paths of class files should not have any additional directory prefixes inside the archives or directories.
Each output entry can be:
When writing output entries, ProGuard will generally package the results in a sensible way, reconstructing the input entries as much as required. Writing everything to an output directory is the most straightforward option: the output directory will contain a complete reconstruction of the input entries. The packaging can be almost arbitrarily complex though: you could process an entire application, packaged in a zip file along with its documentation, writing it out as a zip file again. The Examples section shows a few ways to restructure output archives.
Files and directories can be specified as discussed in the section on file names below.
In addition, the individual class patch entries and their contents can be filtered, as explained in the filters section below. This allows for an almost infinite number of packaging and repackaging possibilities.
The names can contain Java system properties delimited by '<' and '>'. The system properties are automatically replaced by their respective values.
For example, <java.home>/lib/rt.jar
will automatically be
expanded to something like /usr/local/java/jdk/jre/lib/rt.jar
.
Similarly, <user.home>
will be expanded to the user's home
directory, and <user.dir>
will be expanded to the current
working directory.
Names with special characters like spaces and parentheses must be quoted with single or double quotes. Note that each file name in a list of names has to be quoted individually. Also note that the quotes themselves may need to be escaped when used on the command line, to avoid them being gobbled by the shell.
For example, on the command line, you could use an option like '-injars
"my program.jar":"/your directory/your program.jar"'
.
If fewer than 5 filters are specified, they are assumed to be the latter filters. Any empty filters are ignored. More formally, a filtered class path entry looks like this:
classpathentry([[[[zipfilter;]earfilter;]warfilter;]jarfilter;]filefilter)
Square brackets "[]" mean that their contents are optional.
A filter consists of one or more comma-separated file names that can contain wildcards. Only files with matching file names are read (in the case of input jars), or written (in the case of output jars). The following wildcards are supported:
? |
matches any single character in a file name. |
* |
matches any part of a filename not containing the directory separator. |
** |
matches any part of a filename, possibly containing any number of directory separators. |
rt.jar(java/**.class,javax/**.class)
" matches all
class files in the java
and javax
directories inside
the rt
jar.
Furthermore, a file name can be preceded by an exclamation mark '!' to exclude the file name from further attempts to match with subsequent file names. You can think of the filtering mechanism as a conveyor belt, with pushers that accept or reject files as they pass by.
For example, "input.jar(!**.gif,images/**)
" matches all files in
the images
directory inside the input
jar, except
gif files.
Note that the different filters are applied to all corresponding file types, irrespective of their nesting levels in the input; they are orthogonal.
For example,
"input.war(lib/**.jar,support/**.jar;**.class,**.gif)
" only
considers jar files in the lib
and support
directories in the input
war, not any other jar files. It then
matches all class files and gif files that are encountered.
The Examples section provides a few more examples for filtering input and output.
Keep
Options-keep
options for shrinking and obfuscation may seem
a bit confusing at first, but there's actually a pattern behind them. The
following table summarizes how they are related:
Keep | From being removed or renamed | From being renamed |
---|---|---|
Classes and class members | -keep |
-keepnames |
Class members only | -keepclassmembers |
-keepclassmembernames |
Classes and class members, if class members present | -keepclasseswithmembers |
-keepclasseswithmembernames |
Each of these -keep
options is of course followed by a
specification of the classes and class
members (fields and methods) to which it should be applied.
If you're not sure which option you need, you should probably simply use
-keep
. It will make sure the specified classes and class members
are not removed in the shrinking step, and not renamed in the obfuscation step.
Always remember:
|
allowshrinking
allowoptimization
allowobfuscation
-keep
options and in the
-assumenosideeffects
option. The corresponding option is only
applied to classes and class members that match the template.
The template was designed to look very Java-like, with some extensions for wildcards. To get a feel for the syntax, you should probably look at the examples, but this is an attempt at a complete formal definition:
[@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname [extends|implements [@annotationtype] classname] [{ [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> | (fieldtype fieldname); [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> | <init>(argumenttype,...) | classname(argumenttype,...) | (returntype methodname(argumenttype,...)); [@annotationtype] [[!]public|private|protected|static ... ] *; ... }]
Square brackets "[]" mean that their contents are optional. Ellipsis dots "..." mean that any number of the preceding items may be specified. A vertical bar "|" delimits two alternatives. Non-bold parentheses "()" just group parts of the specification that belong together. The indentation tries to clarify the intended meaning, but white-space is irrelevant in actual configuration files.
class
keyword refers to any interface or class.
The interface
keyword restricts matches to interface
classes. The enum
keyword restricts matches to
enumeration classes. Preceding the interface
or
enum
keywords by a !
restricts
matches to classes that are not interfaces or enumerations, respectively.
java.lang.String
. Class names may be specified as regular
expressions containing the following wildcards:
? |
matches any single character in a class name, but not the package
separator. For example, "mypackage.Test? " matches
"mypackage.Test1 " and "mypackage.Test2 ", but not
"mypackage.Test12 ". |
* |
matches any part of a class name not containing the package separator. For
example, "mypackage.*Test* " matches
"mypackage.Test " and
"mypackage.YourTestApplication ", but not
"mypackage.mysubpackage.MyTest ". Or, more generally,
"mypackage.* " matches all classes in
"mypackage ", but not in its subpackages. |
** |
matches any part of a class name, possibly containing any number of
package separators. For example, "**.Test " matches all
Test classes in all packages except the root package. Or,
"mypackage.** " matches all classes in
"mypackage " and in its subpackages. |
!
negators, just
like file name filters. This notation doesn't look very Java-like, so it
should be used with moderation.
For convenience and for backward compatibility, the class name
*
refers to any class, irrespective of its package.
extends
and implements
specifications are typically used to restrict classes with wildcards. They
are currently equivalent, specifying that only classes extending or
implementing the given class qualify. Note that the given class itself is
not included in this set. If required, it should be specified in a
separate option.
@
specifications can be used to restrict classes
and class members to the ones that are annotated with the specified
annotation types. An annotationtype is specified just like a
classname.
javadoc
and javap
). The specifications can
also contain the following catch-all wildcards:
<init> |
matches any constructor. |
<fields> |
matches any field. |
<methods> |
matches any method. |
* |
matches any field or method. |
<init>
wildcard has an argument list.
Fields and methods may also be specified using regular expressions. Names can contain the following wildcards:
? |
matches any single character in a method name. |
* |
matches any part of a method name. |
% |
matches any primitive type ("boolean ", "int ",
etc, but not "void "). |
? |
matches any single character in a class name. |
* |
matches any part of a class name not containing the package separator. |
** |
matches any part of a class name, possibly containing any number of package separators. |
*** |
matches any type (primitive or non-primitive, array or non-array). |
... |
matches any number of arguments of any type. |
?
, *
, and **
wildcards will never match primitive types. Furthermore, only the
***
wildcards will match array types of any dimension. For
example, "** get*()
" matches "java.lang.Object
getObject()
", but not "float getFloat()
", nor
"java.lang.Object[] getObjects()
".
!
specifies that the corresponding access
flag should be unset.
Combining multiple flags is allowed (e.g. public static
). It
means that both access flags have to be set (e.g. public
and static
), except when they are conflicting, in
which case at least one of them has to be set (e.g. at least
public
or protected
).