8

A common pattern in ProGuard configs for Android applications is to preserve custom View classes, since they are probably referenced only from layout XML instead of application code.

Upon project creation, the ADT therefore add these rules to a project's proguard.cfg:

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

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

I guess the idea here is to say that whenever a class defines a constructor that may be called by a layout inflater, then preserve it. However, according to the ProGuard docs, the keepclasseswithmembernames qualifier is shorthand for keepclasseswithmembers and allowshrinking, which if I understand correctly means: it's allowed to remove these classes, but if they're kept, don't obfuscate its member names (probably to not break bindings between XML attribute names and class setters).

But doesn't that mean that those classes will still be removed during the shrinking phase (allowshrinking = true), unless they are referenced directly in code? Indeed that is what happened with a custom widget we're using in our app, and I could fix the issue by setting the rule to just keepclasseswithmembers since that will simply preserve the matching classes entirely (it's worth noting that this is what the official ProGuard Android example does, too).

Am I misreading the ProGuard docs or is this a bug in the ADT project wizard?

Matthias
  • 41,630
  • 28
  • 100
  • 129

2 Answers2

7

The configuration in the Android SDK (at least up to version 11) is not entirely correct, indeed.

The configuration for Android in the ProGuard documentation correctly specifies "-keepclasseswithmembers", not "-keepclasseswithmembernames".

Eric Lafortune
  • 43,056
  • 7
  • 106
  • 100
  • Thanks, I've raised an issue: http://code.google.com/p/android/issues/detail?id=16384 – Matthias Apr 27 '11 at 07:42
  • Thanks for this remark, saved me a lot of time. However, first time for me to configure Proguard, too bad there is no automatic configuration by going through the project content. – Vincent B. Jun 15 '12 at 18:43
0

When I first tried the integrated proguard with Ant, my app kept crashing with runtime errors on the clickhandlers. (I always set these in XML). I assumed I must be doing something wrong, couldn't work out what, so added the line

-dontshrink

at the top of the proguard.cfg.

Maybe this isn't optimal but it stopped the run time errors!

Addendum

In fact I checked this by looking at usage.txt. The clickhandlers were listed in there before I added the dontshrink option, after I added it, usage.txt was empty as would be expected.

NickT
  • 23,183
  • 11
  • 76
  • 115
  • Hey Nick, that's exactly what I suspected, too. The problem is that click handlers in XML are translated to method invocations via reflection, but if ProGuard obfuscates method names, then this of course breaks. The `dontshrink` option would of course fix this, but it's a bit of a sledgehammer, since it will apply to all classes. – Matthias Apr 27 '11 at 07:28
  • Well, it still obfuscates all the method names that haven't been been excluded by the keepclasseswithmembernames directive including the clickhandler. The problem wasn't the obfuscation, it was that the fact that it removed the method because it wasn't referenced in the code anywhere. So as long as you are prepared to remove any truly unused code yourself, it doesn't seem to be that much of a sledgehammer. – NickT Apr 27 '11 at 12:05
  • 2
    I use a rule like this to keep XML-defined click handlers: `-keepclassmembers class * extends android.app.Activity { public void *(android.view.View); }` rather than disabling shrinking. – Christopher Orr Apr 27 '11 at 17:51