Sunday, January 13, 2013

Using Proguard with Android

Some reasons you might want to use it

Security

Proguard makes it easier to hide the implementation details and keys of the services you use.

Protect IP

The work involved in creating your project is often the primary reason you don't have competitors.  Proguard obfuscates your code so your competitors can't simply decompile copy/paste your work.

Reduce APK Size

Proguard removes unused code, reduces the length of variable names, and inlines code.  All this adds up to a smaller app size and less for your users to download.

Optimization

Proguard optimizes variable allocation, arithmetic, unnecessary code, etc.

Logging

Proguard can remove all your logging by removing the actual code that calls it.  This is much simpler and more efficient than any other method.

Syntax

Reflection

Reflection is easily the biggest gotcha when it comes to Proguard.  It works by analyzing which methods and classes actually get used.  Despite some safeguards, it's generally best to assume reflected code will get removed.  You need to specify which methods and classes to keep.  Generally, you should be as specific as possible because telling Proguard to keep large chunks of code drastically reduces it's efficacy.

Setting up your proguard.cfg

Initial Template

#Remove all the injar/outjar/libraryjar junk, the android ant script takes care of this

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*

-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.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

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

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

-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}


First thing you should notice, is that we tell Proguard to keep all the classes (Activities, Services, etc) we declare in AndroidManifest.xml.  These are known as the entry points to the application.  These classes should not have their names changed because the Android won't be able to find them when needed.

Fragments

-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment

Fragments are generally created through reflection.  It's a good idea to keep them all.

3rd Party Libraries

-keep class android.** {*;}
-keep class com.millennialmedia.android.** {*;)
-keep class com.google.ads.** {*;}




It's generally a good idea to keep everything in a third-party library or jar, unless receiving a specific exclude list from the publisher.  You didn't write the code so it's hard to know what sort of issues it may have with Proguard.

Removing Logging

-assumenosideeffects class android.util.Log {
    public static *** e(...);
    public static *** w(...);
    public static *** wtf(...);
    public static *** d(...);
    public static *** v(...);
}

assumenosideeffects tells Proguard that method calls to these don't actually do anything and can be removed if the return value is not used.  android.util.Log does have a return value that's not particularly useful so keep this in mind.

Serializables

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

I'm not entirely sure why this isn't just build into the platform.  These methods and fields from Serializable are discovered at runtime and won't be used in your code.

Click Methods

-keepclassmembers class * {

public void *ButtonClicked(android.view.View);

}

Methods that are called by android:onclick in your xml layouts are referenced by reflection at runtime.  My strategy is to suffix them all with ButtonClicked and save any method that ends with that.

Native Methods

-keepclasseswithmembernames class * {
    native <methods>;
}



Native methods should not be obfuscated because they reference JNI methods relating to their name.

Obfuscating debug builds

It may be useful to obfuscate debug builds in a continuous integration environment.  If so, you can modify your Android build.xml this way to accomplish it.
<target name="-debug-obfuscation-check">
        <!-- yes, we want to obfuscate in debug too!!!! -->
        <condition property="proguard.enabled" value="true" else="false">
            <and>
                <isset property="proguard.config" />
            </and>
        </condition>
        <if condition="${proguard.enabled}">
            <then>
                <!-- Secondary dx input (jar files) is empty since all the
                     jar files will be in the obfuscated jar -->
                <path id="out.dex.jar.input.ref" />
            </then>
        </if>
    </target>

5 comments:

  1. That is really nice and easy! My son would enjoy this!
    access Mp3Raid in UK

    ReplyDelete
  2. Thank you. This article is the best :)

    ReplyDelete
  3. Youngster are just mad about android phones in the present times. Android phones has taken "Mobile Gaming" to the next level.prompter

    ReplyDelete
  4. The Dream G1 is an HTC phone that is available on T-mobile's network.
    oukitelcentral

    ReplyDelete
  5. The most recent information posted on different site delineate that Google Play Store has a considerably higher number of portable applications than Apple App Storepop over to this web-site

    ReplyDelete