Proguard混淆Java注解(Annotation)导致方法重名现象说明及解决
#现象
测试同学反映编译出来的release版本的包无法正常运行,debug倒是正常的。
一查日志,发现是类文件saveInSP找不到。如下图:
这种现象一比较,直觉是proguard混淆出错了。来验证直觉吧。
#验证
反编译release apk,发现确实找不着saveInSP这个类文件。
saveInSP是个Java Annotation注解文件,用来对类文件中的某些成员变量进行修饰。其代码如下:
1 | //仅为属性名的修饰有效 (ElementType.FIELD) |
可见只有简单的三个方法。
查一下编译日志,发现问题,提示“name already added:string{“a”}”,如下图:
是不是混淆之后存在多个方法名是相同名称“a”呢?
拿出proguard混淆后的mapping文件一查,果然isServer()和defValue()这两个不同的方法都被混淆成相同的方法名”a”了,如下图:
由此,确定了crash的原因是由于混淆时将saveInSP的方法混淆后存在同名称方法名且这两个方法都没有参数,唯一的区别只是返回类型不同而已,根据java规则是无法区别对待的,导致添加saveInSP类文件到classes.dex时不成功,自然在运行时就会发现找不到该类而抛出异常了。
但奇葩的是dx命令添加失败的时候应该中断掉呀,为毛仍会继续往下执行呢?
为了确定proguard出错的规则,继续往saveInSP中添加方法,如下:
1 | public saveInSP { |
进行混淆后,mapping文件如下图:
可见proguard对Java注解类文件的方法进行混淆时,存在一个bug:
对于方法参数个数相同只是返回参数不同的多个方法混淆后,混淆后,名称会相同,参数个数相同,只是返回类型不同。这样的混淆结果必然无法正确识别方法名呀。
#解决
1.如果为了保留混淆效果,则设置方法的参数个数不一致就可以解决。
2.拒绝混淆该注解文件,毕竟注解文件一般不涉及核心代码及逻辑,不混淆也不存在什么大问题。可在proguard.config文件中添加如下代码即可:
1 | -keep public class com.t*****download.xmldata.saveInSP{*;} |