【转】请为你的 Android 程式加上 obfuscation 吧!

http://blog.chinaunix.net/u2/85805/showart_1662783.html

Adding ProGuard task into your Android building steps.

在 Eclipse 内,用 Ant 编译你的 Android 程式 这篇中,我介绍过如何利用 Ant 来编译最佳化的 Android 程式。在那篇中,我只说到加上 debug="false" 和 optimize="true" 这两个选项。其实,这样的最佳化还是不够的。你还要加上 obfuscation 才行。

在 Java 的世界中,有许多的 obfuscators 可以选用。我在这里,只提这免费的 ProGuard,并和你分享我是如何将 ProGuard 加到 build.xml 之中,以及在 Android projects 中,使用这 obfuscator,应该要注意的事。

ProGuard 可以用来做什么?

进入 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...

因此,你可以知道 ProGuard 可以帮你,除掉多余的 classes 或是函式,或是变数,他也会最佳化你的程式。更重要的是,他还会将这些 classes, functions, variables 的名称,用较短的名称来取代。这个 obfuscation 功能,除了可以更进一步缩小程式的大小之外,还可以在别人 decompile 你的程式时,延长他读懂你程式的时间。

用 ProGuard 缩小程式大小的效果,好吗?就以我手上的一个例子来说,原先的 classes.dex 有 350,864 bytes。经过 ProGuard 处理后,大小变为 226,772 bytes,足足少了有 35.4% 之多。这应该可以减少不少,使用者要下载你程式时,所使用的时间。

将 ProGuard 加到程式的建置步骤中

我的 Eclipse 中,附带的是 Ant 1.7.0 版本。在这个版本中,已经将 ProGuard 变成是内建的 task 之一,因此你不用再像 这个作法 中一样,以 java task 执行外部 java 程式的方式,来执行 ProGuard 程式。

你只要像下面这样,写个 obfuscate target。

  1.           
  2. <target name="obfuscate" depends="compile">  
  3.   <jar basedir="${outdir-classes}" destfile="temp.jar"/>  
  4.   <taskdef resource="proguard/ant/task.properties"  
  5.            classpath="d:/proguard4.2/lib/proguard.jar" />  
  6.   <proguard>  
  7.     -injars             temp.jar  
  8.     -outjars            obfuscated.jar  
  9.     -libraryjars        ${android-jar}  
  10.     -dontpreverify  
  11.     -dontskipnonpubliclibraryclasses  
  12.     -dontusemixedcaseclassnames  
  13.     -keep public class * extends android.app.Activity  
  14.     -keep public class * extends android.content.BroadcastReceiver   
  15.     -optimizationpasses 7  
  16.   </proguard>  
  17.   <delete file="temp.jar"/>  
  18.   <delete dir="${outdir-classes-final}" failonerror="false" />  
  19.   <mkdir dir="${outdir-classes-final}"/>  
  20.   <unzip src="obfuscated.jar" dest="${outdir-classes-final}"/>  
  21.   <delete file="obfuscated.jar"/>  
  22.   <echo>Obfuscated classes are put to "${outdir-classes-final}".</echo>  
  23. </target>  

再将原先 dex target,

  1. <!-- Convert this project's .class files into .dex files. -->  
  2. <target name="dex" depends="compile">  
  3.   ...  
  4. </target>  

其中的 depends="compile" 改成 depends="obfuscate"。改好后,就像下面这样。

  1. <!-- Convert this project's .class files into .dex files. -->  
  2. <target name="dex" depends="obfuscate">  
  3.   ...  
  4. </target>  

在使用 ProGuard 的经验上,我建议是不要加上 -overloadaggressively 这个选项。要不然,有的程式,会在执行时丢出个 java.lang.VerifyError exception。我加上 -dontskipnonpubliclibraryclasses 选项,是因为要避开使用 java.lang.StringBuilder.setLength(int) 时的错误。另外,如果你程式的类别数超过 26 个时,我建议要加上 -dontusemixedcaseclassnames 选项,要不然 Android 的 dex compiler 会有问题。

另外,最让人头痛的是 -keep 这个选项。到底那些类别要加上这个选项?我的作法是,只要是出现在 AndroidManifest.xml 中的类别,及出现在 layout/*.xml 中的 custom widgets,都要加上 -keep。要不然,Android 系统,可是会找不到你的类别。

关于 ProGuard 的程式码最佳化部份,我手上几个程式都没问题,经过 ProGuard 最佳化后,还是能顺利通过 Dalvik 的验证。不过,倒是有个程式,一直没法通过 Dalvik 的验证。最后,还是在稍微改写了一下程式的写法,才避免了这个问题。所以,如果有启用 ProGuard 的程式码最佳化功能,你可要多注意一下,是否所有的功能,在模拟器上,都可以正常执行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章