我发现似乎有两种一般的解决方案:
- [Retroguard, jobfusate]不要混淆通过反射API引用的内容。
- 用混淆的名称替换反射API调用中的字符串。
这些解决方案只适用于同一个项目中的调用-客户端代码(在另一个项目中)可能不使用反射API访问非公共API方法。
在2的情况下,它也只在反射API与编译时已知的字符串一起使用时起作用(私有方法测试?)。在这些情况下,dp4j还提供了在混淆后注入反射代码的解决方案。
阅读Proguard FAQ我想知道如果2总是工作,当它说:
ProGuard自动处理结构如forname("SomeClass")SomeClass.class。被引用的类在收缩中得以保存阶段,字符串参数为在混淆中正确替换阶段。
对于可变字符串参数,通常无法确定
问:黑体部分是什么意思?任何的例子吗?
对于可变字符串参数,通常无法确定它们的可能值。
public Class loadIt(String clsName) throws ClassNotFoundException {
return Class.forName(clsName);
}
基本上如果你传递一个非常量字符串给Class。对于name, proguard或任何混淆工具通常没有办法弄清楚您在谈论的是什么类,因此不能自动为您调整代码。
Zelix KlassMaster Java混淆器可以自动处理所有反射API调用。它有一个名为AutoReflection的功能,该功能使用"加密的旧名称"到"混淆的名称"查找表。
但是,它同样只能用于同一个混淆项目中的调用。
见http://www.zelix.com/klassmaster/docs/tutorials/autoReflectionTutorial.html .
这意味着:
String className;
if (Math.random() <= 0.5) className = "ca.simpatico.Foo";
else className = "ca.simpatico.Bar";
Class cl = Class.forName(className);
在混淆后不能工作。ProGuard没有做足够深入的数据流分析,以查看被加载的类名来自这两个字符串字量。
实际上,您唯一合理的选择是决定哪些类、接口和方法应该通过反射访问,然后不要混淆它们。你实际上是在为客户端定义一种奇怪的API——一种只能通过反射方式访问的API。