2008年10月13日 星期一

請為你的 Android 程式加上 obfuscation 吧!

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。

再將原先 dex target,

其中的 depends="compile" 改成 depends="obfuscate"。改好後,就像下面這樣。

在使用 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 的程式碼最佳化功能,你可要多注意一下,是否所有的功能,在模擬器上,都可以正常執行。

7 則留言:

匿名 提到...

请问,我在eclipse中使用ANT,一个工程在 [javac] Compiling 39 source files to E:\Android\com.netdragon.pandareader\bin\classes时就没有响应了,
另一些则会出现
[exec] Unable to access jarfile ..\framework\apkbuilder.jar
这个错误.
请问有什么办法解决么

samlu 提到...

sorry, 沒遇過這問題。

阿德 提到...

您好,我試者把您說的方法,
加到 AutoAndroid 的 sample project,
http://code.google.com/p/autoandroid/
但是就是不能執行,不知道您是否有試過?
可否提供一些建議?

另外,我依您另一篇寫的方法,
將release build 加入到上面說的那個 project中,
這是ok 的,感謝您的分享

還有,上面大大問題,我正好有遇到,
Unable to access jarfile ..\framework\apkbuilder.jar
這需要去修改 apkbuilder.bat 裡
的path,讓它指到正確的位置就可以了

東港漁郎 提到...

老師阿, 在這裡 http://www.cublog.cn/u2/85805/showart_1662783.html 有篇文章跟您發表的一模一樣, 雖然它在頁尾有註明出處, 但總覺得這樣很不好, 它有經過您的同意轉載嗎 ?

samlu 提到...

當然沒經我同意就轉載了。有註明出處,已算有道德心的了,一推抄人文章,甚至抄我上課講義,也大有人在。

匿名 提到...

您好, 請問上方您有提到說有需求的就要-keep起來, 否則會被亂碼掉, 但是我看了以上您的解說, 我還是卡在這部分, 不曉得到底怎麼將我在xml或者layout裡面建立的xml來做keep呢?

匿名 提到...

问题同上,请问老师,对于XML活着LAYOUT里面的XML怎么建立KEEP呢?

張貼留言