jberkel / android-plugin

An sbt plugin for Android development in Scala
https://groups.google.com/forum/#!forum/scala-on-android
Other
476 stars 113 forks source link

ProGuard configuration breaks serialization #122

Open pimlott opened 12 years ago

pimlott commented 12 years ago

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.

rst commented 12 years ago

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 commented 12 years ago

Candidate fix submitted as pull request #131.

pimlott commented 12 years ago

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.

ezh commented 12 years ago

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.