Limitations
When using ProGuard, you should be aware of a few issues, all of which are
easily avoided or resolved:
- ProGuard handles the essential elements of Java: classes, interfaces, class
members, inheritance,... ProGuard itself is not aware of any additional
naming conventions or APIs: main methods, native methods, beans,
serialization,... You'll have to specify these in your configuration. The
configuration syntax is intended to be compact, readable, expressive, and
generally applicable. It's usually quite simple. The examples section of
this manual provides many typical examples. The graphical user interface
has checkboxes for common boilerplate configurations.
- ProGuard currently copies manifest files and resource files
unchanged. Directory entries, on the other hand, are not copied to the
output jars. If your code has any special dependencies on these elements,
you should modify or add them manually.
- For efficiency, ProGuard always ignores any private or package visible
library classes while reading library jars. If any of them are
extended by public library classes, and then extended again by input
classes, ProGuard will complain it can't find them. In that case, you'll
have to use the
-dontskipnonpubliclibraryclasses
option. The
graphical user interface has a checkbox for this setting.
- For best results, ProGuard's optimization algorithms assume that
the processed code never intentionally causes NullPointerExceptions and
ArrayIndexOutOfBoundsExceptions to achieve something useful. For instance,
it may remove a method call
myObject.myMethod()
if that call
wouldn't have any effect. It ignores that myObject
might be
null, causing a NullPointerException. In some way this is a good thing:
optimized code may throw fewer exceptions. Should this entire assumption be
false, you'll have to switch off optimization using the
-dontoptimize
option.
- If an input jar and a library jar contain classes in the same
package, the obfuscated output jar may contain class names that
overlap with class names in the library jar. This is most likely if the
library jar has been obfuscated before, as it will then probably contain
classes named 'a', 'b', etc. Packages should therefore never be split
across input jars and library jars.
- ProGuard may not handle obfuscation marker interfaces as expected.
If you specify "
-keep class * implements MyKeepInterface
",
and MyKeepInterface
is not used in your code, the specified
classes are kept, but they are obfuscated. Technically, the interface is
removed in the shrinking phase, making the directive void in the
obfuscation phase. This behavior may be fixed in the future. For now, you
can get around it by explicitly keeping the interface as well:
"-keep class MyKeepInterface
". In any case, creating a proper
configuration file seems a cleaner solution than using such an obfuscation
marker interface.
- ProGuard's obfuscation process currently doesn't follow the naming
rule specifying that internal classes must be named as
ExternalClass$InternalClass
, for instance (cfr. The Java Language Specification, Second Edition, Section 13.1). This should not present a problem in practice, since
the rule is mainly intended for transformations at the source code level.
Internal-external class relationships are still represented correctly
inside the binary class files. Decompilers or others tools that rely on
the naming rule may have problems processing obfuscated jars. I'm not
aware of any such cases.
Copyright © 2002-2004
Eric Lafortune.