Proguard and Serialized Java Objects

With one of my apps, I recently had the problem of altering one of my Serialized classes.  I was careful to check that the changes I was making were valid changes to a class implementing Serializable.

When I tested the app from within eclipse (both on a phone and in the emulator), there were no problems with the previously published apk and my new apk with the changes to my serialized class.  Woo hoo!

I then exported the apk and uploaded the change to the Android market.  The next morning I saw the dreaded error reports provided by the market.  Ugh.  There were problems related to objects saved with the previous version of the apk and the new version of the apk.

After asking a question on stackoverflow, a tip was provided to look at the effects of Proguard on my app.  This led me to look at the proguard manual.  They have some notes on protecting your serializable classes, but the problem now was that my previously published apk did not take these notes into account.  So, what’s the problem with that? Proguard will completely mangle your serialVersionUID if you don’t ask it to protect that field and have changed the class at all (whether the changes were ‘legal’ or not).

If you find yourself in this situation:

  1. Exported an app using proguard with a serialized class.
  2. You didn’t take precautions by setting your proguard.cfg appropriately.
  3. You now need to publish an updated apk with a change to your serialized class.

The fix that work for me is to add the following to your proguard.cfg:

-keepclassmembers class com.example.full.class.Name {
static final long serialVersionUID;
java.lang.Object writeReplace();
java.lang.Object readResolve();
private static final java.io.ObjectStreamField[] serialPersistentFields;
}

After that you need to determine what serialVersionUID was set for your class after you exported your original apk.  I found this by looking at the stack trace.  If you tried to publish the update without taking the steps I’m describing, you probably got an error like:

java.io.InvalidClassException: my.class.Name; Incompatible class (SUID): my.class.Name: static final long serialVersionUID =<some long value>; but expected my.class.Name: static final long serialVersionUID =<some other long value>;

You can use that reported long value in your class now.  You should set your serialVersionUID to <some long value> and then build your apk.  Because of the directives in proguard.cfg, this value will be preserved and your new apk shouldn’t have problems reading old, saved versions of the same class.

Note that if you add more fields to your later, the order you add them might affect how proguard obfuscates them.  I’d suggest protecting the new field names in the “-keepclassmemebers” directive above to be safe.

Hope this saves someone some of the hours of pain I experienced.

Littlepancake Software by Littlepancake Software