Saturday, June 18, 2011

Android ProGuard Optimization Setup & Configuration

 

Optimizing the app APK is usually the last step of Android development. Google recommend using the open source ProGuard tool to optimize the apk for final delivery. Here we explore the benefits, issues, and suggest a proper configuration for optimizing your apk.

Benefit

  • Reduced APK size
  • Improve performance
  • Obfuscation

Drawback

  • Potential misconfiguration
  • Additional testing required
  • Stacktraces are difficult to read with obfuscated method names

The major drawback is that your app might crash when misconfigured.

Configuration for Android

There are many ways to configure the ProGuard tool for optimization. Google already provided a default configuration named “proguard.cfg” under the project root folder for newly created projects. However, this configuration is outdated due to the introduction of the Fragment API and the onClick XML attribute. Since the default configuration renames public method names, some java reflection might not work and, as a result, method/class not found exceptions might be thrown.

We have updated the configuration to accommodate the new Fragment classes (and the compatibility version) and tested several configuration with different level of optimization. The following table shows the resulted apk size when optimizing our AQuery demo app VikiSpot Reader:

Configuration Notes APK Size (kb) Size %
No Optimization Original APK. 323 100%
Safest Remove no classes and only rename private methods. 266 82.4%
Recommended Remove unused classes and only rename private methods. 205 63.5%
Risky Remove unused classes and rename most public/protected methods. 203 62.8%

Note: Size reduction % varies depends on your project structure and other factors.

The “Safest” configuration reduced our apk size by about 17%, whereas the “Recommended” configuration reduce the apk size by 36%.

The “Risky” configuration only reduce an additional 0.7% beyond the “Recommended” settings.

Therefore, we believe that the marginal benefit of renaming public and protected methods does not warrant its risk and maintenance overhead.

Recommended Configuration

Here’s a safe configuration that give most benefits. See source file.

   1: -optimizationpasses 5
   2: -dontusemixedcaseclassnames
   3: -dontskipnonpubliclibraryclasses
   4: -dontpreverify
   5: -verbose
   6: -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
   7:  
   8: -keep public class * extends android.app.Activity
   9: -keep public class * extends android.app.Application
  10: -keep public class * extends android.app.Service
  11: -keep public class * extends android.content.BroadcastReceiver
  12: -keep public class * extends android.content.ContentProvider
  13: -keep public class * extends android.app.backup.BackupAgentHelper
  14: -keep public class * extends android.preference.Preference
  15: -keep public class com.android.vending.licensing.ILicensingService
  16:  
  17: #keep all classes that might be used in XML layouts
  18: -keep public class * extends android.view.View
  19: -keep public class * extends android.app.Fragment
  20: -keep public class * extends android.support.v4.Fragment
  21:  
  22:  
  23: #keep all public and protected methods that could be used by java reflection
  24: -keepclassmembernames class * {
  25:     public protected <methods>;
  26: }
  27:  
  28: -keepclasseswithmembernames class * {
  29:     native <methods>;
  30: }
  31:  
  32: -keepclasseswithmembernames class * {
  33:     public <init>(android.content.Context, android.util.AttributeSet);
  34: }
  35:  
  36: -keepclasseswithmembernames class * {
  37:     public <init>(android.content.Context, android.util.AttributeSet, int);
  38: }
  39:  
  40:  
  41: -keepclassmembers enum * {
  42:     public static **[] values();
  43:     public static ** valueOf(java.lang.String);
  44: }
  45:  
  46: -keep class * implements android.os.Parcelable {
  47:   public static final android.os.Parcelable$Creator *;
  48: }
  49:  
  50: -dontwarn **CompatHoneycomb
  51: -dontwarn org.htmlcleaner.*

Line 17-20: We want to keep classes that can be referenced in XML layouts. Those classes include custom View and Fragment.

Line 23-26: We want to keep the method names for public/protected methods to avoid problems with onClick method names specified in XML.

Setup

Here we highlight the necessary steps to enable ProGuard optimization with Eclipse.

Enable ProGuard

Open the “default.properties” file under the project root.

Enter “proguard.config=proguard.cfg”, like this:

# Project target.
target=android-12
proguard.config=proguard.cfg

Note that the file comments says not to edit this file. Ignore that outdated comment.

Next, make sure your SDK location path has no space in it, like this:

android-sdk-path

There is a bug in the SDK that causes ProGuard to fail when there’s a space in the SDK path. If you are developing on Windows and installed the SDK to the default location, you most likely will need to fix the SDK path.

Configuration

Create or edit the file “proguard.cfg” under the project folder. We recommend using our updated recommended configuration to accommodate the new Fragments and onClick listeners.

Export APK

With the above setup, ProGuard will silently run when the APK is generated. Pay attention to the console and make sure there’s no ProGuard related errors.

For testing, you can export the APK to the project /bin folder.

Test APK

Install the APK to a test device. If you export the APK to the /bin folder, just run the project like normal development testing and the optimized APK will be deployed. Note that you might need to uninstall the development version of the app in your device, because the optimized APK will be signed and the dev app must be removed first.

Feedback

We hope our guide help your Android development.

If you have issues or have other insights regarding Android ProGuard optimization, please feel free to leave a comment!

Also, take a look at our open source framework Android Query for more Android goodies.

No comments:

Post a Comment