Proguard, Android, Ant, and 3rd party external JARs

Wednesday, Sep 22. 2010  –  Category: Android, Code, Musings

I’ll keep this short and sweet. Dan Galpin covered in a recent blog post how to drop in Proguard & Ant to easily do Android app builds. One hitch is that it doesn’t work for apps that have third party external jars. The simple fix to get this working is to change the libraryjars line from:

-libraryjars ${libraryjarpath}

to

-libraryjars ${external.libs.dir}:${libraryjarpath}

p.s. why are all the Android dev blogs posted only by Tim Bray and not the authors directly? p.p.s. why can’t we leave comments on the blog posts?

Tags: , , ,

One Trackback to “Proguard, Android, Ant, and 3rd party external JARs”

  1. Tweets that mention that’s whacked » Blog Archive » Proguard, Android, Ant, and 3rd party external JARs -- Topsy.com

17 Comments to “Proguard, Android, Ant, and 3rd party external JARs”

  1. eric franchomme Says:

    Apparently, Dan changed the add-proguard-release.xml to support external libraries. Howerver, the change is now breaking projects which don’t have external library. I had to remove the change back to original: -libraryjars ${libraryjarpath}

  2. Dan Galpin Says:

    Sorry about that! I suspect that the change broke Windows machines. I’ve uploaded a new version that should behave correctly. The change looks like this:

  3. eric franchomme Says:

    where did you upload the new file?

  4. eric franchomme Says:

    also I do not see the change on that page…

  5. Dan Galpin Says:

    Sorry.. that’s what I get when I paste XML and it doesn’t get quoted. The file replaced the original file, and I need to get Tim to note the change in the blog post.

  6. eric franchomme Says:

    thanks!

    Is there a way to verify the obfuscation is successful?

    Also, is there a way to hide my native library (.so file built with NDK) so it is not extractable from the APK?

  7. Dave Says:

    I have tried every option I could find to get proguard to work but no luck. My app builds but force closes when I run on my droid x phone after run through proguard. The app works fine exported from eclipse and just signed.

    I followed the directions at: http://android-developers.blogspot.com/2010/09/proguard-android-and-licensing-server.html

    I added my two classes to the keep list and no luck still force close. Then I searched for every article on proguard and disabled/tried all options including dontshtrink, dontoptimize and even dontobfuscate with no luck

  8. Dan Galpin Says:

    When the app force-closes, what exception (or stack trace) is being shown in logcat?

  9. Tertium Organum Says:

    I have such error: Failed to locateorg.apache.tools.ant.Main ant.home: c:\Tertium\!!android\ant Classpath: c:\Tertium\!!android\ant\lib\ant-launcher.jar;c:\Program Files\Java\jdk1.6.0_10\lib\tools.jar Launcher JAR: C:\Tertium Launcher Directory: C:\

    Heard it’s because old version of ant in Eclipse. It seems strange to me. Have anybody solution for this? OS: WinXP sp2 x64, Win 7 x64 (2 machines)

    Can I somehow use internal eclipse ant? It compiles project although sais “Default target help does not exist in this project” but there are no result files.

  10. Stephen Lau Says:

    @Dan: One thing that might be worth updating which I ran into is that Proguard obfuscating Parcelables can cause errors where BadParcelableException gets thrown, e.g.:

    Caused by: android.os.BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR

    I had to put the following into my procfg.txt:

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

  11. Benoit Essiambre Says:

    “Is there a way to verify the obfuscation is successful?”

    Same question. Everything seems to be working except I don’t see anything about progard or obfuscation in the ant output. Is this normal?

  12. Benoit Essiambre Says:

    Ok I figured it out, I wasn’t using the latest tools SDK.

  13. Charles Stearns Says:

    I have found the the default procfg.txt suggested has a number of issues, particularly with more complex apps. It doesn’t correctly support custom Views referenced from layout. It also doesn’t correctly support onclick methods referenced from the xml that exist in the Activity. I don’t have time to do a proper write up of my own, but for sake of sharing here is a improved starting point. If your app has any level of complexity using reflection using views etc. you will need to plan on tweaking this and sending your obfuscated app through a complete test cycle. I also added keeping the line numbers for stack traces, but prior to shipping you probably want to remove that as well, it is just very helpful in getting things working.

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

    -keep public class * extends android.app.Activity{ public void *(android.view.View); } -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 com.android.vending.licensing.ILicensingService

    -keepclasseswithmembernames class * { native ; }

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

    -keepclasseswithmembernames class * { public (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 *; }

    -keep public class * extends android.view.View { public (android.content.Context); public (android.content.Context, android.util.AttributeSet); public (android.content.Context, android.util.AttributeSet, int); public void set*(…); }

    -keep public class **.R

    -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable

  14. Charles Stearns Says:

    Trying again to fix the formatting, sorry if this doesn’t format correct. [sourcecode] -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/,!class/merging/

    -keep public class * extends android.app.Activity{ public void *(android.view.View); } -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 com.android.vending.licensing.ILicensingService

    -keepclasseswithmembernames class * { native ; }

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

    -keepclasseswithmembernames class * { public (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 *; }

    -keep public class * extends android.view.View { public (android.content.Context); public (android.content.Context, android.util.AttributeSet); public (android.content.Context, android.util.AttributeSet, int); public void set*(…); }

    -keep public class **.R

    -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable [/sourcecode]

  15. Simon Says:

    Sorry, this is the last try, think I got it now, please remove my previous double posts :(

    Also if you have problems with folder name that contain spaces, you should surround paths with apostroph as stated in Proguard documentation.

    Just change the libraryjarpath property so that it surrounds each path with apostroph…

    <!-- <property name="libraryjarpath" refid="fullclasspath"/> --> <pathconvert property="libraryjarpath">   <path refid="fullclasspath"/>   <mapper>     <globmapper from="" to="''"/>   </mapper> </pathconvert>

    …and add apostrophes to the path properties passed to proguard…

    <proguard>    @'${proguard-conf}'    -injars '${android-jar-preobfuscate}'    -outjars '${android-jar-postobfuscate}'    -libraryjars ${libraryjarpath}    -dump '${obfuscate.absolute.dir}/dump.txt'    -printseeds '${obfuscate.absolute.dir}/seeds.txt'    -printusage '${obfuscate.absolute.dir}/usage.txt'    -printmapping '${obfuscate.absolute.dir}/mapping.txt' </proguard>
  16. Brad Says:

    I ran into some problems on Windows as well. I have an external JAR in the project’s lib folder. I was able to get it to work using a variant of Simon’s method.

    First, I added this property:

    <property name="targetclasspath" refid="android.target.classpath"/

    Then, I changed the text in the proguard tag to look like this:

    <proguard>
        @'${proguard-conf}'
        -injars '${android-jar-preobfuscate}'
        -outjars '${android-jar-postobfuscate}'
        -libraryjars '${targetclasspath}';'${external.libs.dir}'
        -dump '${obfuscate.absolute.dir}/dump.txt'
        -printseeds '${obfuscate.absolute.dir}/seeds.txt'
        -printusage '${obfuscate.absolute.dir}/usage.txt'
        -printmapping '${obfuscate.absolute.dir}/mapping.txt'
    </proguard>

    Hopefully this helps others on Windows.

  17. Brad Says:

    Additionally, I also had issues with onClick methods getting zapped by Proguard. I used Charles Stearns’ example, but had to modify it a bit. It looks like the site mangled the code. Here is what worked for me:

    -optimizationpasses 5
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -dontpreverify
    -verbose
    -optimizations !code/simplification/arithmetic,!field/,!class/merging/
    
    -keep public class * extends android.app.Activity{
        public void *(android.view.View);
    }
    -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 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 *;
    }
    
    -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*(...);
    }
    
    -keep public class **.R
    
    -renamesourcefileattribute SourceFile
    -keepattributes SourceFile,LineNumberTable

Leave a Reply


Recent posts