ProGuard混淆未保留参数化构造函数public访问修饰符如何解决
问题背景
定义的类A代码如下:
class A { public A(String param1, String param2) { // 方法体 } public A(String param1, String param2, String param3) { // 方法体 } }
当前使用的ProGuard配置规则:
keep 'public class com.test.A$* { public *;}' keepclassmembers 'class * extends com.test.A { public <init>(...);}'
混淆后异常表现:类A的参数化构造函数访问修饰符从原有public被修改为private,混淆后的类结构如下:
class A { private A(String var1, String var2) { // 方法体 } private A(String var1, String var2, String var3) { // 方法体 } }
核心诉求:调整ProGuard配置,在混淆过程中保留参数化构造函数原本的访问修饰符。
原因分析
现有两条规则均未覆盖类A本身:
- 第一条规则匹配范围是
com.test.A$*,仅对A的内部类生效(JVM中内部类编译后命名格式为外部类$内部类) - 第二条规则匹配范围是所有继承自A的子类,仅对子类的public构造方法生效
ProGuard在代码未命中keep规则时,会执行访问权限优化:如果判定构造方法没有被类外部调用,会自动将其修改为private以缩小访问范围,这就是构造方法权限被篡改的直接原因。
修复方案
在原有配置基础上,新增针对类A本身的构造方法保留规则即可,调整后的完整配置如下:
# 新增规则:保留com.test.A类的所有public构造方法,不修改其访问权限 -keep class com.test.A { public <init>(...); } # 原有规则:保留A的内部类的公共成员 keep 'public class com.test.A$* { public *;}' # 原有规则:保留A子类的public构造方法 keepclassmembers 'class * extends com.test.A { public <init>(...);}'
配置说明:
<init>是ProGuard对类构造方法的固定匹配标识符,(...)代表匹配任意长度、任意类型的参数列表- 规则前置的
public限定符,会让ProGuard仅匹配原代码中声明为public的构造方法,不会改动这类方法的访问修饰符,也不会影响其他非public成员的正常混淆 - 如果需要完整保留类A的类名、所有公共方法/字段不被混淆,可以将新增规则替换为
-keep public class com.test.A { public *; },仅需要保留构造方法权限的话,上面的精简规则就足够生效。
内容的提问来源于stack exchange,提问作者Galet
相关产品推荐
相关产品推荐

