I am having a hell of a time with Gson and ProGuard. I have a simple object and when I parse tojson, save to sqllite and read back from the database in order to load the json back to my object, I get a java.lang.classcastexception. If I dont use ProGuard, everthing works fine.
I have verified that the json string being sent to and gotten from the database is the same. The exception is not thrown when it converts from json, but rather when I try to access the object.
Here is my simple object:
public class ScanLog extends ArrayList<SingleFrame>
{
private static final long serialVersionUID = 1L;
public ScanLog()
{
}
}
public final class SingleFrame
{
public int Position;
public int Time;
public Map<Integer,String> MainDataMap;
public Map<Integer,String> DataMap;
public SingleFrame(int position, int time,
Map<Integer,String> mainDataMap, Map<Integer,String> dataMap)
{
this.Position = position;
this.Time = time;
this.MainDataMap = mainDataMap;
this.DataMap = dataMap;
}
}
All other aspects of my app are fine, but something with proguard is causing this to happen....Ive tried all kinds of -keep commands in the proguard.cfg but I am not sure what Im doing is right.
EDIT - ADDING PROGUARD.CFG
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-dontshrink
-dontoptimize
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
#keep all classes that might be used in XML layouts
-keep public class * extends android.view.View
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.v4.Fragment
#keep all classes
-keep public class *{
public protected *;
}
#keep all public and protected methods that could be used by java reflection
-keepclassmembernames class * {
public protected <methods>;
}
-keepclasseswithmembernames class * {
native <methods>;
}
-keep public class org.scanner.scanlog.SingleFrame
-keepclassmembers class org.scanner.scanlog.ScanLog {
private <fields>;
public <fields>;
}
-keepclassmembers class org.scanner.scanlog.SingleFrame {
private <fields>;
public <fields>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-dontwarn **CompatHoneycomb
-dontwarn org.htmlcleaner.*
#-keep class android.support.v4.** { *; }
EDIT - Okay I got ACRA set up successfully in my app, pretty awesome feature!
Here is the stack trace:
java.lang.ClassCastException: java.lang.Object
at org.scanner.activity.ReaderMainActivity.AdvanceScanLog(SourceFile:1499)
at org.scanner.activity.r.onProgressChanged(SourceFile:271)
at android.widget.SeekBar.onProgressRefresh(SeekBar.java:89)
at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:507)
at android.widget.ProgressBar.refreshProgress(ProgressBar.java:516)
at android.widget.ProgressBar.setProgress(ProgressBar.java:565)
at android.widget.AbsSeekBar.trackTouchEvent(AbsSeekBar.java:337)
at android.widget.AbsSeekBar.onTouchEvent(AbsSeekBar.java:292)
at android.view.View.dispatchTouchEvent(View.java:3932)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157)
at android.app.Activity.dispatchTouchEvent(Activity.java:2181)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759)
at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2336)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1976)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4263)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
For the latest version of the recommended proguard configuraiton file, please see the gson supplied android proguard example at:
https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
These settings in the config worked for me in one of my apps:
# Add the gson class
-keep public class com.google.gson
# Add any classes the interact with gson
-keep class com.someapp.android.models.ChatModel { *; }
-keep class com.someapp.android.models.FeedModel { *; }
# Add the path to the jar
-libraryjars /Users/someuser/Documents/workspace/someapp/lib/gson-1.7.1.jar
Hopefully this helps you out.
Applying the changes found in the Android example in the Gson project worked for me
The lines needed were:
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
# and keeping the classes that will be serialized/deserialized
I know the original question was resolved by taking a different approach, but I was having a very similar issue using flexjson and Proguard on Android, and I've solved it, in case anyone runs into it themselves.
When converting back from JSON to my value object which included some ArrayLists, I would get the same ClassCastException. I got it to work by basically having obfuscation enabled but turning all parts of obfuscation off (-keep everything, -keepclassmembers everything and -keepattributes everything) and then working backwards by enabling things a bit at a time.
The result; keeping the entire flexjson library:
-keep class flexjson**
--keepclassmembers class flexjson** {
*;
}
and keeping the Signature and Annotation attribute:
-keepattributes Signature, *Annotation*
I was able to use the flexjson library without incident after that in a proguarded, release version of my app.
I was getting errors for Model classes with proguard If you look at
GSON Proguard you will find a line
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
replace com.google.gson.examples.android.model. with your model package likewise in my case i replaced it with -keep class com.consumer.myProject.model.** { *; }
rest I copied as such
So, I ended up ditching the Gson library and instead of converting my object to json using gson, I created a custom class in my app to serialize and deserialize the object and store the data that way.
I am overall more happy, even though this has cost me over 12 hours of trying to figure it out. Apparently, PROGUARD and gson must not like each other too much?
As A HUGELY added benefit to not having to use GSON, I noticed that by taking out the GSON library, my app size is cut in half. My app was 577kb and is now only 260kb after removing the gson lib.
It does look like your are keeping everything from your class (fields, methods and the class itself). But to make sure you can add -printseeds outputfile.txt to the proguard.cfg file to verify that proguard really keeps everything you need once obfuscation is done.
BTW, you might think about adding something like ACRA or Android Remote stacktrace that allows you to inspect stacktraces on a built app.
Just to add to all of the other answers, if you guys reached here, it means that you want to obfuscate your code AND use Gson.
If, at the end, you chose to -keep class your instances, it means that these Gson classes WILL NOT BE OBFUSCATED and this solution (or even Gson in general, is not an optimal solution for you).
In this case I would advise to Serialize the classes yourself and store them See #Jessy's answer.
Related
I'm using proguard to obfuscate a (SDK) jar file I've created.
The SDK contains a Java Service, a statically compiled C++ lib and a SWIG (ver 2) interface via which the Service and the lib communicates.
I've added relevant '-keep' and '-keepclasseswithmembernames,includedescriptorclasses' statements to the configuration file.
But one file keeps getting (partially) obfuscated.
The first part of the proguard config looks like this (all collected from the net):
-libraryjars '/Library/DevTools/adt-bundle-mac-x86_64-20140702/sdk/platforms/android-21/android.jar'
-libraryjars 'libs/android-support-v4.jar'
-libraryjars "libs/armeabi-v7a/libnativesdk.so"
-dontskipnonpubliclibraryclasses
-injars bin/mysdklib.jar
-verbose
-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
My specific classes addition looks like this:
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkIfJNI{
private final static native void swig_module_init();
public static *;
public final static native <methods>;
}
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkWrapper{
public *;
}
-keep class com.company.IntWrapper
-keep class com.company.StatisticsParcel{
public *;
}
-keep class com.company.JNILibCallbacks
All the classes I keep works fine. The problem is with the 'MySdkIfJNI' class.
This is an Swig (http://www.swig.org/) auto-generated interface between the native lib and the Java service.
I tried various configurations in order to keep this class as is but proguard keeps obfuscating it.
I tried '-keep' , '-keepclasseswithmembernames,includedescriptorclasses', '-keepclasseswithmembernames'
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkIfJNI{
private final static native void swig_module_init();
public static *;
public final static native <methods>;
*;
}
both with arguments and without arguments
But after proguard finishes (without any errors / warnings) I find out that only part of the methods has been obfuscated.
The native methods are kept, such as:
public final static native void JniMYSdkClient_setLogLevel(long jarg1, JniMYSdkClient jarg1_, int jarg2);
public final static native void delete_JniMYSdkClient(long jarg1);
But all the Java methods that starts with SwigDirector are obfuscated, such as:
public static void SwigDirector_JNIMyCallbacks_onEvent(JNIMyCallbacks self, int accountId, int eventId, String sessionId, String msg) {
self.onEvent(accountId, eventId, sessionId, msg);
}
This obfuscation causes the Native swig interface to fail finding this callback methods and my lib crashes.
Any ideas of how can I keep this specific class AS-IS ?
Thanks in advance,
Or Pol.
Well, I didn't find any solution to the particular SWIG methods but since the SWIG wrapping code is already really messy I have decided it doesn't have to be obfuscated with Proguard.
I moved the SWIG interface to an external JAR file and imported it as '-libraryjars'
Now the native layer finds this methods and everything works perfect.
Thanks anyway!
Best regards,
Or.
Swig callbacks need to be keep from obfuscation.
First try to keep all generated java files by swig and compile and see. Crash will fix. Like below
-keep com.custom.project** { *; }
-dontwarn com.custom.project**
Next maximize your files for obfuscation.
Hope it helps.
I have been looking to a solution to this problem, i have tried many proguard configurations without success.
The app runs perfectly until I make the release version with proguard.
I am getting the error:
"java.lang.IllegalArgumentException:The class representing the mobile serviceTable must have a single id property defined" while assigning the class
I belive that is caused by the class of the table that i am trying to reach, having its variable 'id' name changed.
I have the folowing:
public class User {
public String id;
public String nickname;
public String phone;
}
and the connection is made with:
mClient.getTable(User.class).where().field("nickname")
.eq(nick).execute(new TableQueryCallback<User>() {....
the proguard config file is:
-keep class com.microsoft.azure.storage.table.** { *; }
-dontwarn com.fasterxml.jackson.core**
-keep class com.microsoft.windowsazure.mobileservices.** { *; }
-dontwarn android.os.**
-dontwarn com.microsoft.windowsazure.mobileservices.RequestAsyncTask
##---------------from here is the part that i have modified a lot of times -
-keepattributes Signature
-keepattributes *Annotation*
-keep public class com.company.app.User.** { *; }
-keepclassmembers public class com.company.app.User.** { *; }
I have tried many modifications for hours without success.
I followed this and this among many others.
Can you please help me?
Thanks
EDIT: solved. Just remove the .** after User in the proguard file. Leave it like this:
-keep public class com.company.app.User { *; }
-keepclassmembers public class com.company.app.User { *; }
solved. Just remove the .** after User in the proguard file. Leave it like this:
-keep public class com.company.app.User { *; }
-keepclassmembers public class com.company.app.User { *; }
I have an Android-based application which is connecting to the Google App Engine using Rest services, the app works perfectly until it is obfuscated through ProGuard prior to release.
The error reported in LogCat when running the obfuscated app is:
Unable to convert a [application/json,UTF-8] representation into an object of
class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found
for type [simple type, class
com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer]:
can not instantiate from JSON object (need to add/enable type information?)
I have the following in my proguard-project.txt file:
-keepattributes *Annotation*,EnclosingMethod
-keep public class org.w3c.** {public private protected *;}
-dontwarn org.w3c.**
-keep public class org.joda.time.** {public private protected *;}
-dontwarn org.joda.time.**
-keep public class org.restlet.** { *; }
-dontwarn org.restlet.**
-keep public class org.codehaus.** { *; }
-dontwarn org.codehaus.**
-keepattributes Signature
-keepnames class com.fasterxml.jackson.** { *; }
-dontwarn com.fasterxml.jackson.databind.**
And my class the error refers to looks like:
public class WasteCollectionAreasContainer {
public List<WasteCollectionAreas> wasteCollectionAreasList;
public List<WasteCollectionAreas> getWasteCollectionAreasList() {
return wasteCollectionAreasList;
}
public void setWasteCollectionAreasist(List<WasteCollectionAreas> wasteCollectionAreasList) {
this.wasteCollectionAreasList = wasteCollectionAreasList;
}
public WasteCollectionAreasContainer() {
wasteCollectionAreasList = new ArrayList<WasteCollectionAreas>();
}
#JsonCreator
public WasteCollectionAreasContainer(List<WasteCollectionAreas> wasteCollectionAreasList) {
this.wasteCollectionAreasList = wasteCollectionAreasList;
}
}
To reiterate prior to obfuscation through ProGuard the app works perfectly.
Can anyone help me solve this problem?
Add the following to your Proguard.config. It will help you locate the issue.
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
I have the following in my proguard-project.txt file
I believe you should be using proguard-android-optimize.txt, and not proguard-android.txt.
For completeness, thank Riley Hassell on Android Security Discussions for the tricks.
The error message
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type
[simple type, class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer]:
can not instantiate from JSON object (need to add/enable type information?)
suggests that the Jackson library is trying to deserialize your class using reflection, with its original name and its annotated constructor. ProGuard can't foresee this, so it may have removed or renamed the class and its constructor. You probably need to preserve them explicitly:
-keep class com.enterprisemk.android.bcw.bincollection.WasteCollectionAreasContainer {
<init>(java.util.List);
}
There may be other similar classes/fields/methods that need to be preserved for the same reasons.
A better solution, in case anyone else has this problem, is the following:
# keep anything annotated with #JsonCreator
-keepclassmembers public class * {
#com.fasterxml.jackson.annotation.JsonCreator *;
}
That keeps any method annotated with JsonCreator, which is probably wanted to do in this case. If you have multiple classes needing to be loaded, then you can avoid having to specify each class individually.
I integrated ACRA to my application to get crash reports from my app in beta stadium so I'm able to fix bugs, find errors in code, etc. If I run this on the emulator everything works fine and ACRA is up and running, but if I export a signed package of my application with Android Tools I get an ExceptionInInitializeError and the application is force closed on the device. If I catch this Error and proceed without ACRA the app itself runs like a charm...
has anybody here got the same issue with ACRA? could it be that it has something to do with ProGuard? I followed the ProGuard how to on ACRA homepage but perhaps I'm missing something on this?
here's what my proguard.cfg looks like:
-injars 'C:\Workspaces\motodevWs\gp2012\bin\classes'
-injars 'C:\Workspaces\motodevWs\gp2012\libs'
-outjars 'C:\Workspaces\motodevWs\gp2012\bin\classes-processed.jar'
-libraryjars 'C:\android\android-sdk\platforms\android-7\android.jar'
-libraryjars 'C:\android\android-sdk\add-ons\addon_google_apis_google_inc_7 \libs\maps.jar'
-optimizations !code/simplification/arithmetic
-allowaccessmodification
-repackageclasses ''
-keepattributes *Annotation*,SourceFile,LineNumberTable,*Annotation*
-renamesourcefileattribute SourceFile
-dontpreverify
-dontwarn java.awt.**,javax.security.**,java.beans.**,com.sun.**
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context,android.util.AttributeSet);
public <init>(android.content.Context,android.util.AttributeSet,int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context,android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context,android.util.AttributeSet,int);
}
-keepclassmembers class * extends android.os.Parcelable {
static android.os.Parcelable$Creator CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
# keep this class so that logging will show 'ACRA' and not a obfuscated name like 'a'.
# Note: if you are removing log messages elsewhere in this file then this isn't necessary
-keep class org.acra.ACRA {
<fields>;
<methods>;
}
# keep this around for some enums that ACRA needs
-keep class org.acra.ReportingInteractionMode {
<fields>;
<methods>;
}
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter {
public void addCustomData(java.lang.String,java.lang.String);
}
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter {
public org.acra.ErrorReporter$ReportsSenderWorker handleSilentException(java.lang.Throwable);
}
PROBLEM SOLVED!
After some effort on research and rethinking my problem I found the solution to the problem and it was indeed in my proguard.cfg file where I missed something!
somehow I managed not to keep enums, now I added
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
to my proguard.cfg and everything is working perfectly!!
So, to close this question with the answer I found myself, here is what I did to resolve this particular problem :) (taken from my question post):
After some effort on research and rethinking my problem I found the solution to the problem and it was indeed in my proguard.cfg file where I missed something!
somehow I managed not to keep enums, now I added
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
to my proguard.cfg and everything is working perfectly!!
THere is now a wiki concerning using ACRA with ProGuard
https://github.com/ACRA/acra/wiki/Proguard
My application has many activities and uses native library too. With the default ProGuard configuration which Eclipse generates ProGuard removes many things - OnClick methods, static members, callback methods which my native library uses... Is it there a simple way to instruct ProGuard to NOT remove anything from my package? Removing things saves only about 2.5% of the application size, but breaks my application completely. Configuring, testing and maintaining it class by class in ProGuard configuration would be a pain.
EDIT This answer is 10 years old - it may not apply to newer proguard versions.
I think you need to add these flags at the very least (modify for you individual package names):
-keep class javax.** { *; }
-keep class org.** { *; }
-keep class twitter4j.** { *; }
Also, add these flags:
-dontshrink
-dontoptimize
-dontpreverify
Here's my whole config file: of my Proguard.cfg:
-dontshrink
-dontoptimize
-dontpreverify
-verbose
-dontwarn javax.management.**
-dontwarn java.lang.management.**
-dontwarn org.apache.log4j.**
-dontwarn org.apache.commons.logging.**
-dontwarn org.slf4j.**
-dontwarn org.json.**
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keep class javax.** { *; }
-keep class org.** { *; }
-keep class twitter4j.** { *; }
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
As final result I found that just keeping all class members is not enough for the correct work of my application, nor necessary. I addded to the settings file this:
-keepclasseswithmembers class * {
void onClick*(...);
}
-keepclasseswithmembers class * {
*** *Callback(...);
}
The case with onClick* is for all methods which I address in android:onClick atribute in .xml layout files (I begin the names of all such methods with 'onClick').
The case with *Callback is for all callback methods which I call from my native code (through JNI). I place a suffix 'Callback' to the name of every such method.
Also I added few rows for some special cases with variables which I use from native code, like:
-keep class com.myapp.mypackage.SomeMyClass {
*** position;
}
(for a varible with name 'position' in a class with name 'SomeMyClass' from package com.myapp.mypackage)
All this is because these onClick, callback etc. must not only be present but also kept with their original names. The other things ProGuard can optimize freely.
The case with the native methods is important also, but for it there was a declaration in the generated from Eclipse file:
-keepclasseswithmembernames class * {
native <methods>;
}
I know this is an old question but I hope that the following information might help other people.
You can prevent ProGuard from removing anything in a certain package as follows;
-keep,allowoptimization,allowobfuscation class com.example.mypackage.** { *; }
Using the modifiers allowoptimization and allowobfuscation will make sure that ProGuard still obfuscates and optimizes the code. Shrinking will of course be disabled as intended.
You can easily verify how these -keep rules affect the code without the need to (re-)build using the ProGuard Playground.