问题
Following the suggestions from @AlexWein in this question and looking at ProGuard Troubleshooting, I have the following in a SherlockFragment:
Class<?> c = Class.forName("co.uk.MyApp.pdf.MyData");
Method main = c.getDeclaredMethod("pdfsleep", Report_Holder.class);
Report_Holder paramsh = null;
paramsh = SRH;
main.invoke(null, (Object)paramsh);
"co.uk.MyApp.pdf.Data" constructor is:
public class MyData {
public static void pdfsleep(Report_Holder args) {
...
}
}
Proguard is set up like so:
-keepnames class co.uk.MyApp.classes.Report_Holder
-keepclassmembers class co.uk.MyApp.pdf.Data { public static void pdfsleep(Report_Holder); }
-keepnames class co.uk.MyApp.DataActivity
But I am still getting a NoSuchMethodException:
05/23/13 12:14:28 GMT+01:00 ERROR AsyncTask #2 - java.lang.NoSuchMethodException: pdfsleep [class co.uk.MyApp.classes.Report_Holder]
at java.lang.Class.getConstructorOrMethod(Class.java:460)
at java.lang.Class.getDeclaredMethod(Class.java:685)
at co.uk.MyApp.fy.a(Unknown Source)
at co.uk.MyApp.fy.doInBackground(Unknown Source)
at android.os.AsyncTask$2.call(AsyncTask.java:264)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
What am I missing?
Update
I have changed the Proguard lines to:
-keepattributes Signature
-keepnames class co.uk.MyApp.classes.Report_Holder
-keepclasseswithmembers class co.uk.MyApp.DataActivity
-keepclasseswithmembers class co.uk.MyApp.pdf.Data { void pdfsleep(Report_Holder); }
And am still getting the error.
Looking at the mapping file, I think that I see what is causing the issue:
co.uk.MyApp.classes.Report_Holder -> co.uk.MyApp.classes.Report_Holder:
co.uk.MyApp.DataActivity -> co.uk.MyApp.DataActivity:
java.util.ArrayList arrDataItems -> a
co.uk.MyApp.classes.Report_Holder SRH -> b
It looks like Proguard is keeping the reference to co.uk.MyApp.classes.Report_Holder, but is obfuscating it when referencing it as a child of co.uk.MyApp.DataActivity.
I've tried different ways of keeping co.uk.MyApp.DataActivity, trying to get it to stop obfuscating co.uk.MyApp.classes.Report_Holder, but can't get the syntax correct. Any suggestions?
Update 2
I have updated some code and the ProGuard config file as suggested by Eric Lafortune (btw, I am showing proper package/classnames now):
In co.uk.FibroApp.SleepDataActivity
Class<?> c = Class.forName("co.uk.FibroApp.pdf.SleepData");
Method main = c.getDeclaredMethod("pdfsleep", co.uk.FibroApp.classes.SleepReport_Holder.class);
SleepReport_Holder paramsh = SRH;
co.uk.FibroApp.pdf.SleepData is:
public class SleepData {
public static void pdfsleep(co.uk.FibroApp.classes.SleepReport_Holder args) {
...
}
}
Full ProGuard config is:
-keepattributes Signature
-keep class co.uk.FibroApp.classes.SleepReport_Holder
-keep class co.uk.FibroApp.pdf.SleepData
-keepclassmembers class co.uk.FibroApp.pdf.SleepData {
public static void pdfsleep(co.uk.FibroApp.classes.SleepReport_Holder);
}
# do not obfuscate the classes from droidtext but shrink them
-keep,allowshrinking class harmony.java.awt.** { *; }
-keep,allowshrinking class org.apache.harmony.** { *; }
-keep,allowshrinking class org.bouncycastle.** { *; }
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class com.actionbarsherlock.** { *; }
-keep interface com.actionbarsherlock.** { *; }
-keepattributes *Annotation*
And the full error log is:
05/24/13 08:25:52 WEST ERROR AsyncTask #2 - java.lang.NoSuchMethodException: sleeppdf [class co.uk.FibroApp.classes.SleepReport_Holder]
at java.lang.Class.getConstructorOrMethod(Class.java:460)
at java.lang.Class.getDeclaredMethod(Class.java:685)
at co.uk.FibroApp.fy.a(Unknown Source)
at co.uk.FibroApp.fy.doInBackground(Unknown Source)
at android.os.AsyncTask$2.call(AsyncTask.java:264)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
回答1:
Your code accesses a method by means of reflection. The stack trace indicates that ProGuard has removed or renamed it. So, you should preserve it, with a line that is almost a direct copy of the headers of your code:
-keepclassmembers class co.uk.MyApp.pdf.MyData {
public static void pdfsleep(co.uk.MyApp.classes.Report_Holder);
}
ProGuard recognizes the Class.forName construct and already preserves the class MyData. For good measure, you can make sure ProGuard doesn't remove the class Report_Holder (should the class happen to be unused, other than as an argument type):
-keep,allowobfuscation class co.uk.MyApp.classes.Report_Holder
Notes:
The ProGuard documentation explains the differences between the various -keep options. If you're not sure, just use -keep. Cfr. Usage > Overview of Keep Options.
You may have seen a warning in your console log that Report_Holder has to be specified with its fully qualified name.
回答2:
Solved!
I added these lines to the ProGuard config file:
-keep class co.uk.FibroApp.pdf.SleepDataActivity
-keep class co.uk.FibroApp.pdf.SleepMainActivity
I added SleepDataActivity because that is the class which holds the Async task which contacts pdfsleep.
I added SleepMainActivity because SleepDataActivity is, technically, a Fragment within a TabSwipe Activity and SleepMainActivity is the parent of those tabs.
'pdfsleep' is now mentioned in mapping.txt, and all works as intended.
I will accept Eric Lafortune's reply as the answer to this question, as his syntax for '-keepclassmembers' is not something I would have gotten to by myself, and also because I accepted the answer from AlexWien in a previous question which got me to this stage.
Thank you both, you have saved my launch date!
回答3:
One of your problems probably is that in the obfuscation rules you specify Report_Holder,
but the method to exclude uses SleepReport_Holder.
I use this rule It is in ant proguard extension, but you can easily translate that to the other rule description system:
<keepclasseswithmembers name="co.uk.MyApp.pdf.MyData" access="public">
<method access="public static" type="void" name="pdfsleep" parameters="co.uk.MyApp.classes.SleepReport_Holder" />
</keepclasseswithmembers>
additionaly vor java > 1.5 use rule
-keepattributes Signature
otherwise collections and generics will not work
来源:https://stackoverflow.com/questions/16703291/proguard-causing-nosuchmethodexception-followup