android-plugin icon indicating copy to clipboard operation
android-plugin copied to clipboard

ProGuard configuration breaks serialization

Open pimlott opened this issue 12 years ago • 4 comments

The default ProGuard configuration in src/main/scala/AndroidInstall.scala is missing many of the suggested configurations in the ProGuard documentation (http://proguard.sourceforge.net/index.html#manual/examples.html), including those for serializable classes. For example, if my class relies on a readResolve method for deserialization, that method is stripped ProGuard and so deserialization breaks.

I suggest putting a more complete and conservative ProGuard configuration in sbt-android-plugin by default. I'm still learning, so I don't have a full proposal, but I would include at least:

-keepclassmembers class * implements java.io.Serializable { private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); }

It may be worth centrally maintaining a ProGuard configuration that works reliably for the Scala library.

pimlott avatar Mar 23 '12 17:03 pimlott

FWIW, this can be worked around by adding the text suggested above to the build settings in a project's build.scala. roughly like so:

lazy val fullAndroidSettings = General.settings ++ AndroidProject.androidSettings ++ TypedResources.settings ++ AndroidMarketPublish.settings ++ Seq ( keyalias in Android := "change-me", libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test", proguardOption in Android := """ -keepclassmembers class * implements java.io.Serializable { private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } """ )

It can be useful to do so, as storing serializable objects in a Bundle is one of the more straightforward ways of handling saveInstanceState/restoreInstanceState in an Activity.

rst avatar May 18 '12 16:05 rst

Candidate fix submitted as pull request #131.

rst avatar May 18 '12 22:05 rst

I agree about your use case (storing serializable objects in a Bundle), and this is exactly what I was trying to do. I did soon realize that since so many of the standard Scala classes are polymorphic, the lack of full type checking on deserialize (even with manifests as currently available) can bite. So now I usually use my own non-polymorphic classes instead.

That said, serialization and deserialization of standard Scala classes ought to work reliably. It took me a long time to figure out what was going wrong.

pimlott avatar May 28 '12 13:05 pimlott

I tried to use serialization in my projects DigiControl/DigiSSHD, but there was an errors when I passed serialized object between different apk (transport level not significant) that shared in single library with serialized object.

I have something like client-server model that based on common code (DigiLib). Inside single apk all works well (intents and so on). So I am afraid that you find that your serialized data broken if you upgrade you application someday or try to send it to other application.

Of course ,I tried to set serial number by hand and I read proguard serialization manuals. So now I use only parcelable, even for persistent storage (Google prohibit this, but I read android source code and daresay, that parcelable chunk writen relatively well for my needs)

PS I think that scala bytecode generation maybe affected, so class in pure java will be consistent. But I don't want to use java code in my project.

ezh avatar May 29 '12 16:05 ezh