Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Obfuscating and Optimizing with ProGuard

Published? true
FormatLanguage: WikiFormat

Problem:

You want to obfuscate your code, or optimize it (for speed or size), or all of the above.

Solution:

The optimization and obfuscation tool ProGuard is supported by the Ant Script provided with the modern Android Project wizard in Eclipse, needing only to be enabled.

Discussion:

Obfuscation of code is the process of trying to hide information (such as compile-time names visible in the binary) that would be useful in reverse-engineering your code. If your application contains commercial or trade secrets, you probably do want to obfuscate it. If your program is open source, there is probably no need to obfuscate the code. You decide.

Optimization of code is analogous to refactoring at the source level; but it usually aims to make the code either faster, smaller, or both.

The normal development cycle with Android and Eclipse involves compilation to standard Java ByteCode (done by the Eclipse Compiler) then conversion to the Android-specific DEX (Dalvik Executable) format. ProGuard is Eric Lafortune's open-source, free software program to optimize and obfuscate Java code. ProGuard is not Android-specific; it works with console-mode applications, Applets, Swing applications, JavaME Midlets, Android, or just about any type of Java program. ProGuard works on compiled Java, so it must be interposed in the development cycle before conversion to DEX. This is most readily achieved using the standard Java build tool Ant. The Eclipse Android Project Wizard, as of Gingerbread (2.3), includes support for ProGuard in the generated build.xml file. You only need to edit the file build.properties to include the folowing line, which gives the name of the configuration file.

proguard.config=proguard.cfg

For older versions, please refer to the ProGuard Reference Manual.

Configuration File

The ProGuard processing is controlled by the configuration file (normally called proguard.cfg), which has its own syntax. Basically keywords begin with a "-" character in the first character position, followed by a keyword, followed by optional parameters. Where the parameters reference Java classes or members, the syntax somewhat mimics Java syntax to make your life easier. Here is a minimal ProGuard configuration file for an Android application:

-injars      bin/classes
-outjars     bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic

-keep public class com.example.MainActivity

The first section specifies the paths of your project, including a temporary directory for the optimized classes.

The next section lists various options. Preverification is only for full Java projects, so it's turned off. The optimizations shown are for a 1.5 Android and could probably be omitted today.

Finally, the class com.example.MainActivity has to be present in the output of the optimization and obfuscation process, since it is the main activity and is referred to by name in the AndroidManifest.

A full working proguard.cfg will normally be generated for you by the Eclipse New Android Project Wizard. Here, for example, is the configuration file generated for an Android 2.3.3 project:

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

-keepclasseswithmembernames class * {
    native <methods>;
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

The prolog is mostly similar to the earlier example. The keep, keepclasseswithmembernames, and keepclassmembers specify particular classes that must be retained. These are mostly obvious, but the enum entries may not be: the Java 5 enum methods values() and valueOf() are sometimes used with the Reflection API, so they must remain visible, as must any classes that you access via the Reflection API.

The ILicensingService entry is only needed if you are using Android's License Validation Tool (LVT):

-keep class com.android.vending.licensing.ILicensingService

One last optimization would be to remove Log.d and Log.v calls from shipped applications, which can make the app a tiny bit more more performant, but may cause the line numbers in stack traces to be off by a few lines.

-assumenosideeffects class android.util.Log {
    public static int d(...);
    public static int v(...);
}

The -assumenosideeffects tells ProGuard that the methods named don't do anything useful outside themselves and can thus be eliminated.

See Also:

The ProGuard Reference Manual has many more details. There is also information at Google's Developer Site. Finally, Matt Quigley has an article at AndroidEngineering entitled Optimizing, Obfuscating, and Shrinking your Android Applications with ProGuard.