Data Modeling With Jackson Json and Scala - Proguard
關於Proguard,官方的網頁是這麼自述的:
在Mobile App開發的時候,多會用proguard把沒有用到的程式碼濾除,並把變數名稱跟函式名稱用更精簡的字串來取代,這樣編出來的程式會更小,以我用Scala開發的Android程式,使用的的函式庫大小超過10MB,但是用proguard編出來的class.min.jar只有1.7MB,8.xMB的scala-runtime.jar一大票沒用到的功能都被移掉了。
這麼好的功具當然也有他的問題存在,proguard是使用靜態分析的方式,去追縱看有那些程式碼會被執行到,有那些程式碼是不會被碰到的可以被移除的;但由於Jackson是使用Reflection的方式去取得物件的屬性及是用reflection的方式去生成物件,因此,這些行為並不會被proguard偵測到,反而是被認為是dead code而被移除掉。
另外proguard會把變數名稱改寫,這也是跟jackson不相容的地方,當getXxxx被改寫成gY,jackson自然無法知道這是Xxxx的getter,因此若是要在proguard的環境下使用jackson,obfuscator是要被關掉的。
底下這邊,是我在台北積水地圖內,用的proguard設定檔
ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names. Finally, it preverifies the processed code for Java 6 or for Java Micro Edition.
在Mobile App開發的時候,多會用proguard把沒有用到的程式碼濾除,並把變數名稱跟函式名稱用更精簡的字串來取代,這樣編出來的程式會更小,以我用Scala開發的Android程式,使用的的函式庫大小超過10MB,但是用proguard編出來的class.min.jar只有1.7MB,8.xMB的scala-runtime.jar一大票沒用到的功能都被移掉了。
這麼好的功具當然也有他的問題存在,proguard是使用靜態分析的方式,去追縱看有那些程式碼會被執行到,有那些程式碼是不會被碰到的可以被移除的;但由於Jackson是使用Reflection的方式去取得物件的屬性及是用reflection的方式去生成物件,因此,這些行為並不會被proguard偵測到,反而是被認為是dead code而被移除掉。
另外proguard會把變數名稱改寫,這也是跟jackson不相容的地方,當getXxxx被改寫成gY,jackson自然無法知道這是Xxxx的getter,因此若是要在proguard的環境下使用jackson,obfuscator是要被關掉的。
底下這邊,是我在台北積水地圖內,用的proguard設定檔
proguardOption in Android :=
("-dontoptimize -dontpreverify -dontobfuscate" // shrinking only
:: "-dontskipnonpubliclibraryclassmembers" // keep Jackson's internal classes
:: "-dontskipnonpubliclibraryclasses" // keep Jackson's internal classes
:: "-keepattributes *Annotation*." // keep Jackson Json Annotations.
:: "-keep class org.codehaus.jackson.**"
:: "-keep class com.bluetangstudio.android.model.**"
:: "-keep class com.bluetangstudio.searchcloud.client.**"
:: """-keep class com.bluetangstudio.searchcloud.client.** {
(...);
public static ** valueOf(...);
}"""
:: """-keep class com.bluetangstudio.** {
void set*(***);
void set*(int, ***);
boolean is*();
boolean is*(int);
*** get*();
*** get*(int);
}"""
:: """-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}"""
:: """-keepclassmembers class * {
** MODULE$;
}"""
:: "-keep public class org.xml.sax.EntityResolver"
:: "-keep public class scala.Either"
:: "-keep public class scala.Function1"
:: "-keep public class scala.Function2"
:: "-keep public class scala.Tuple2"
:: "-keep public class scala.collection.Iterable"
:: "-keep public class scala.PartialFunction"
:: "-keep public class scala.collection.Seq"
:: "-keep public class scala.collection.TraversableOnce"
:: "-keep public class scala.collection.generic.CanBuildFrom"
:: "-keep public class scala.collection.immutable.Map"
:: "-keep public class scala.collection.immutable.List"
:: "-keep public class scala.collection.mutable.StringBuilder"
:: "-keep public class scala.Predef$$less$colon$less"
:: "-keep public class scala.math.Numeric"
:: "-keep public class scala.math.Ordering"
:: "-keep public class scala.reflect.ClassManifest"
:: "-keep public class scala.runtime.IntRef"
:: "-keep public class scala.runtime.BooleanRef"
:: "-keep public class scala.runtime.AbstractFunction1"
:: "-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.appwidget.AppWidgetProvider"
:: "-keep public class * extends android.content.BroadcastReceiver"
:: "-keep public class * extends android.content.BroadcastReceiver"
:: "-keep public class * extends android.app.backup.BackupAgentHelper"
:: "-keep public class * extends android.content.ContentProvider"
:: "-keep public class * extends android.view.View"
:: "-keep public class * extends android.preference.Preference"
:: Nil
) mkString " "
</pre></div>