在代码中存储(部分)Proguard 混淆映射

Storing (partial) Proguard obfuscation mapping in code

提问人:Mohammad 提问时间:2/3/2023 更新时间:2/4/2023 访问量:186

问:

在这样的 android Java 代码中:

String methodName = "myMethod"

public void myMethod() {
}

是否可以在运行时找出方法的混淆名称?
我知道我可以要求 Proguard 不要混淆该方法,但我正在寻找一种方法来避免这种情况,并且仍然能够通过反射使用它。

我找不到 Proguard 配置,但我想知道是否可以有一个 gradle 任务来合并生成的映射?

Android Gradle 反射 android-gradle-plugin proguard

评论

0赞 bongo 2/3/2023
嘿,您能分享一下此功能的用例吗?
0赞 Mohammad 2/3/2023
什么功能?我有一个字符串常量,用于保存方法的名称。混淆后,方法名称不再与字符串匹配。所以我想找到一种方法在运行时找出新名称。
0赞 bongo 2/3/2023
我想知道为什么您需要将方法名称存储为 String。因此,也许我们将能够解决您的问题,而无需向 proguard 付款
0赞 Mohammad 2/6/2023
能够在运行时通过反射调用这些方法。

答:

1赞 Oleg 2/3/2023 #1

代码混淆通常只是将类和变量重命名为简短和随机的文本,同时保持适当的依赖关系。无法获取函数的混淆名称,因为它是随机生成的,并且每次运行总是不同的。

以下是一些选项:

  1. 相反,如果要保持函数不可读,请从混淆中排除该类,并使用随机文本命名函数。

    -keep 类 <com.package.DontObfuscate>

  2. 在第一次混淆后,保留文件并在mapping.txtproguard-rules.pro

    -应用映射映射:.txt

这将防止为类/变量生成新名称。

-applymapping- 指定重用在 ProGuard 的上一次模糊处理运行中打印出来的给定名称映射。映射文件中列出的类和类成员将接收与其一起指定的名称。未提及的类和类成员将获得新名称。

  1. 寻找一种不在代码中使用类/接口扩展的反射的方法。

评论

0赞 Mohammad 2/3/2023
谢谢。我认为这个选项最接近我想做的事情applymapping
2赞 Holger 2/4/2023 #2

如果需要方法内部的方法名称,可以使用

String methodName;

public void myMethod() {
    methodName = new Object() {}.getClass().getEnclosingMethod().getName();
}

或者,在较新的 Java 版本中

String methodName;

public void myMethod() {
    methodName = StackWalker.getInstance(Set.of(), 1)
        .walk(s -> s.map(StackWalker.StackFrame::getMethodName).findFirst())
        .orElseThrow();
}

当您需要外部名称时,即调用它时,您可以使用注释标记方法并搜索它。

@Retention(RetentionPolicy.RUNTIME) @interface Marker {}

@Marker
public void myMethod() {
}
String name = Arrays.stream(ContainingClass.class.getDeclaredMethods())
    .filter(m -> m.isAnnotationPresent(Marker.class))
    .map(Method::getName)
    .findFirst().orElseThrow();

正如其他人所说,不使用 Reflection 可能是更好的选择。例如,引用使用匹配功能接口的方法,不是反射访问:

Runnable method = this::myMethod;

public void myMethod() {
}

这将在混淆后继续工作。

评论

0赞 Mohammad 2/6/2023
感谢您的建议。可悲的是,就我而言,我正在处理许多类和方法,因此我试图避免为每个类和方法单独添加标识注释。但似乎没有一种自动化的方法。