Android升级Gradle7.x后Class.getInterfaces()返回空数组求助
问题场景与解决方案
问题复现代码
Java代码
// ITest.java interface ITest { } // TestA.java class TestA implements ITest { } // TestB.java class TestB extends TestA implements ITest { } // main function void main() { TestB testB = new TestB(); Class[] interfaces = testB.getClass().getInterfaces(); // Gradle7.x开启minifyEnabled=true时,count为0 int count = interfaces.length; }
Build配置
// build.gradle android { buildTypes { debug { minifyEnabled true } } }
问题原因
Gradle7.x搭配的Android Gradle Plugin7.x默认使用的R8混淆器会做冗余接口实现移除优化:TestB继承的TestA已经实现了ITest,R8判定TestB显式声明implements ITest属于冗余代码,编译时会移除这个声明,导致反射调用getInterfaces()拿不到ITest接口。而Gradle6.x用的旧版混淆工具没有这个优化,所以能正常返回长度1。
解决方案
方案1:添加R8规则保留接口声明
在项目的proguard-rules.pro(或r8-rules.pro)里加下面的规则,替换成实际包名:
-keep class 你的包名.TestB implements 你的包名.ITest
这条规则告诉R8不要移除TestB对ITest的显式实现声明,反射就能正常获取到接口。
方案2:修改代码逻辑遍历父类接口
不想依赖混淆规则的话,改反射逻辑,递归遍历当前类和所有父类的接口,确保收集到所有实现的接口:
void main() { TestB testB = new TestB(); Set<Class<?>> allInterfaces = new HashSet<>(); Class<?> currentClass = testB.getClass(); // 遍历当前类及父类,收集所有接口 while (currentClass != null) { Collections.addAll(allInterfaces, currentClass.getInterfaces()); currentClass = currentClass.getSuperclass(); } // 此时allInterfaces.size()为1,包含ITest int count = allInterfaces.size(); }
这种方式不依赖混淆配置,兼容性更强,后续R8规则变化也不受影响。
内容的提问来源于stack exchange,提问作者user23188580
相关产品推荐
相关产品推荐

