简体   繁体   English

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

[英]NoSuchMethodException when accessing method via reflection after using Proguard

I wish to use Proguard to reduce the size and method count in an Android app. 我希望使用Proguard减少Android应用程序的大小和方法数量。 Currently obfuscating the code is not necessary. 目前不需要对代码进行混淆。 The REST api for the app is using reflection to call the appropriate method for the endpoint. 该应用程序的REST api使用反射来为端点调用适当的方法。 This will be changing to Callbacks the in the future, but for the moment I need to work with this method. 将来它将更改为Callbacks,但目前我需要使用此方法。

This method is called when the request is successful and calls an appropriate method, saltSucceeded in the error message below. 请求成功后将调用此方法,并调用下面的错误消息中的适当方法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();
    }
}

When Proguard has been run this error results when onSuccess is called from the salt action. 运行Proguard后,从操作中调用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)

Here is the proguard-rules.pro file. 这是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
...

It is called thus from app/build.gradle : 因此从app / build.gradle调用它:

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

Unsurprisingly in unused.txt 毫不奇怪,在unused.txt中

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

I have looked at several sites and references talking about trouble with Proguard and reflection, however the various recommendations have not solved the problem. 我看过几个站点和参考资料,它们讨论了Proguard和反射的问题,但是各种建议都没有解决问题。 Currently I am trying to stop proguard from modifying the com.someapp code at all to try and get back to a working state. 目前,我正试图阻止proguard修改com.someapp代码,以尝试恢复工作状态。 From there I can spend more time trying to only preserve methods: *Failed, *Succeeded, *Complete, *NoConnection. 从那里,我可以花更多时间尝试仅保留方法:*失败,*成功,*完成,* NoConnection。

Thank you for any input you have. 感谢您的任何投入。

http://www.alexeyshmalko.com/2014/proguard-real-world-example/ http://www.alexeyshmalko.com/2014/proguard-real-world-example/
Proguard and reflection in Android Android中的Proguard和反思

The option -keepclasseswithmembers has a special meaning, more intended for finding main classes with their main methods, for instance. 选项-keepclasseswithmembers具有特殊含义,例如,其更多用途是使用其主要方法查找主要类。 When in doubt, just use -keep . 如有疑问,请使用-keep The following should work: 以下应该工作:

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

Note the fully qualified class name (ProGuard prints out a note if it seems to be incorrect or incomplete). 记录全限定的类名(如果ProGuard似乎不正确或不完整,则会打印出一个注释)。 I've used wildcards for the arguments, but you can be more specific if you wish. 我已经使用了通配符作为参数,但是如果您愿意,可以更具体一些。

You need a separate option if you want to match methods in extensions: 如果要匹配扩展中的方法,则需要一个单独的选项:

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

You should see the matched methods in seeds.txt. 您应该在seeds.txt中看到匹配的方法。 The standard Android build process already writes out this file to a different location (eg build/outputs/mapping/release/seeds.txt in Gradle). 标准的Android构建过程已经将此文件写出到其他位置(例如Gradle中的build / outputs / mapping / release / seeds.txt)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM