I originally tried to get help for this problem on StackOverflow but didn't get anything.
http://stackoverflow.com/questions/22418691/why-does-proguard-keepclassmembers-behave-differently-based-on-class-specifier
It seems like it may be a bug...
I've been debugging a ProGuard issue in an Android app I'm writing caused by it removing field names that are needed to extract the fields from a JSON string. To make sure those members remained with their original names, I added this:
-keepclassmembers class com.example.common.regions.** { !static !final !transient <fields>; }
This seemed to work and the output mapping.txt showed the following:
com.example.common.regions.RegionMapMeta -> com.example.b.d.b: java.lang.String mapVid -> mapVid int mapVersion -> mapVersion double topLeftLat -> topLeftLat double topLeftLong -> topLeftLong double topRightLat -> topRightLat double topRightLong -> topRightLong double bottomLeftLat -> bottomLeftLat double bottomLeftLong -> bottomLeftLong double bottomRightLat -> bottomRightLat double bottomRightLong -> bottomRightLong double boundingTopLat -> boundingTopLat double boundingBottomLat -> boundingBottomLat double boundingLeftLong -> boundingLeftLong double boundingRightLong -> boundingRightLong int minZoom -> minZoom int maxZoom -> maxZoom int maxZoomMinX -> maxZoomMinX int maxZoomMaxX -> maxZoomMaxX int maxZoomMinY -> maxZoomMinY int maxZoomMaxY -> maxZoomMaxY int stackOrder -> stackOrder java.lang.String thumbnailImage -> thumbnailImage java.util.Set mapLayers -> mapLayers
Then I thought I didn't like having to specify directories in ProGuard and that it would be better to have an annotation to distinguish these classes.
@Target(ElementType.TYPE) public @interface ProguardKeepClassMembers { }
I then annotated my classes (not the members, just the classes) with @ProguardKeepClassMembers and changed the ProGuard rule to be as such:
-keepclassmembers @com.example.common.ProguardKeepClassMembers class * { !static !final !transient <fields>; }
However, this does not work the same. The mapping.txt file has the same fields but now they're being obfuscated.
com.example.common.regions.RegionMapMeta -> com.example.b.d.b: java.lang.String mapVid -> a int mapVersion -> b double topLeftLat -> c double topLeftLong -> d double topRightLat -> e double topRightLong -> f double bottomLeftLat -> g double bottomLeftLong -> h double bottomRightLat -> i double bottomRightLong -> j double boundingTopLat -> k double boundingBottomLat -> l double boundingLeftLong -> m double boundingRightLong -> n int minZoom -> o int maxZoom -> p int maxZoomMinX -> q int maxZoomMaxX -> r int maxZoomMinY -> s int maxZoomMaxY -> t int stackOrder -> u java.lang.String thumbnailImage -> v java.util.Set mapLayers -> w
So... Why is -keepclassmembers behaving different when only the class matcher has changed?
ProGuard is probably removing the annotation itself, since the code is not using it. You should keep it:
Alternatively, you can collect such annotations in a jar annotations.jar and specify it as a library (without leaving it in the source code or in libs):
The annotation classes then won't be in the resulting code, which is fine. This is the approach from the example examples/annotations/examples.pro (e.g. in android-sdk/tools/proguard).
Also see the ProGuard manual > Troubleshooting > Unexpected observations after processing > Classes or class members not being kept.