java - 使用 Proguard 后通过反射访问方法时出现 NoSuchMethodException

标签 java android reflection proguard

我希望使用 Proguard 来减少 Android 应用程序的大小和方法数量。目前没有必要混淆代码。应用程序的 REST API 使用反射来调用端点的适当方法。将来这将更改为回调,但目前我需要使用此方法。

当请求成功并调用适当的方法(下面的错误消息中的saltSucceeded)时,会调用此方法。

public void onSuccess(int statusCode, String response) {
    try {
        getClass().getDeclaredMethod(action + "Succeeded", Integer.TYPE, String.class).invoke(this, statusCode, response);

    } catch (Exception e) {
        Logger.error(e);
        callFailedMethod();
    }
}

当 Proguard 运行时,从 salt 操作调用 onSuccess 时会出现此错误。

ERROR: ResponseHandler.onSuccess(113) ->  
java.lang.NoSuchMethodException: saltSucceeded [int, class java.lang.String]
    at java.lang.Class.getConstructorOrMethod(Class.java:472)
    at java.lang.Class.getDeclaredMethod(Class.java:640)
    at com.someapp.api.response.ResponseHandler.onSuccess(ResponseHandler.java:110)
    at com.someapp.api.response.ResponseHandler.onSuccess(ResponseHandler.java:94)
    at com.loopj.android.http.AsyncHttpResponseHandler.handleMessage(AsyncHttpResponseHandler.java:359)
    at com.loopj.android.http.AsyncHttpResponseHandler$ResponderHandler.handleMessage(AsyncHttpResponseHandler.java:183)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:157)
    at android.app.ActivityThread.main(ActivityThread.java:5356)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
    at dalvik.system.NativeStart.main(Native Method)

这是proguard-rules.pro文件。

-dontobfuscate
-dontoptimize
-dontpreverify

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-printconfiguration configuration.txt

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable

-keepclasseswithmembers class com.someapp.** { *; }

# Library Specific Configurations follows
...

它是从app/build.gradle调用的:

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  

不出所料,在unused.txt

...
27:28:public void saltFailed(java.lang.Throwable,java.lang.String)
32:41:public void saltSucceeded(int,java.lang.String)
...

我查看了几个网站和引用文献,讨论了 Proguard 和反射的问题,但是各种建议都没有解决问题。目前我正在尝试阻止 proguard 修改 com.someapp 代码以尝试恢复到工作状态。从那里我可以花更多的时间尝试只保留方法:*失败、*成功、*完成、*NoConnection。

感谢您提供的任何意见。

http://www.alexeyshmalko.com/2014/proguard-real-world-example/
Proguard and reflection in Android

最佳答案

选项-keepclasseswithmembers具有特殊含义,例如,更适合使用其main方法查找主类。如有疑问,只需使用-keep。以下内容应该有效:

-keepclassmembers class com.someapp.api.response.ResponseHandler {
    public void *Succeeded(...);
    public void *Complete(...);
    public void *NoConnection(...);
    public void *Failed(...);
}

记下完全限定的类名(如果它看起来不正确或不完整,ProGuard 会打印出一条注释)。我在参数中使用了通配符,但如果您愿意,可以更具体。

如果您想匹配扩展中的方法,则需要一个单独的选项:

-keepclassmembers class * extends com.someapp.api.response.ResponseHandler {
    public void *Succeeded(...);
    public void *Complete(...);
    public void *NoConnection(...);
    public void *Failed(...);
}

您应该在 seeds.txt 中看到匹配的方法。标准 Android 构建过程已将此文件写入不同位置(例如 Gradle 中的 build/outputs/mapping/release/seeds.txt)。

关于java - 使用 Proguard 后通过反射访问方法时出现 NoSuchMethodException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29416985/

相关文章:

java - 如何用Jsoup只获取n层元素?

java - 让我的类(class)进行争论

java - 如何使用 Object[] 数组调用 MethodHandle.invokeExact()?

java - 使用反射获取私有(private)非原始字段的值

c# - 检查类字段事件背后生成字段的属性

java - 非阻塞 IO 与异步 IO 以及 Java 中的实现

java - 将持久化实体更改为同级子类

c# - Java 中的 Integer.valueOf() 是否转换为 C# 中的 int.Parse()?

Android动态显示图像

android - 如何知道 Android 上的 JSON 中是否存在对象值?