转自:http://www.cnitblog.com/zouzheng/archive/2011/01/12/72630.aspx
前段时间把Android的工程用Ant Build搞定后,现在需要把编译后.class进行混淆,以优化减少体积和防止别人反编译,开始在网上看了一些关于ProGuard的介绍,以后能够比较快的解决,但是还是花了两天半的时间才搞定,也许是自己对Java和ProGuard不了解,网上也有一些例子介绍Android ProGuard,但是你全部拿过来肯定是不行的,这需要你认真的读他的手册和国外开发人员写的Blog,我是把这个ProGuard手册看了两遍才把问题解决的。下面转帖一些别人写的内容:
主题:Android Ant编译时候进行混淆
Xml代码 复制代码
1. <property name="proguard-home" value="D:/eclipsetools/proguard4.4/lib"/>
<property name="proguard-home" value="D:/eclipsetools/proguard4.4/lib"/>
加入混淆的target配置到build.xml中去:
Xml代码 复制代码
1. <!--Execute proguard class flies-->
2. <target name="optimize">
3. <jar basedir="${outdir-classes}" destfile="temp.jar"/>
4. <java jar="${proguard-home}/proguard.jar" fork="true" failonerror="true">
5. <jvmarg value="-Dmaximum.inlined.code.length=32"/>
6. <arg value="-injars temp.jar"/>
7. <arg value="-outjars optimized.jar"/>
8. <arg value="-libraryjars ${android-jar}"/>
9.
10. <!-- <arg value="-libraryjars ${external-libs}/*.jar"/>-->
11. <arg value="-dontpreverify"/>
12. <arg value="-dontoptimize"/>
13. <arg value="-dontusemixedcaseclassnames"/>
14. <arg value="-repackageclasses ''"/>
15. <arg value="-allowaccessmodification"/>
16. <!--<arg value="-keep public class ${exclude-activity}"/>-->
17. <!--<arg value="-keep public class ${exclude-provider}"/>-->
18. <arg value="-keep public class * extends android.app.Activity"/>
19. <arg value="-keep public class * extends android.content.ContentProvider"/>
20. <arg value="-keep public class * extends android.view.View"/>
21.
22. <arg value="-keep public class * extends android.preference.Preference"/>
23. <arg value="-optimizationpasses 7"/>
24. <arg value="-verbose"/>
25. <arg value="-dontskipnonpubliclibraryclasses"/>
26. <arg value="-dontskipnonpubliclibraryclassmembers"/>
27. </java>
28. <delete file="temp.jar"/>
29. <delete dir="${outdir-classes}"/>
30. <mkdir dir="${outdir-classes}"/>
31. <unzip src="optimized.jar" dest="${outdir-classes}"/>
32. <delete file="optimized.jar"/>
33. </target>
<!--Execute proguard class flies-->
<target name="optimize">
<jar basedir="${outdir-classes}" destfile="temp.jar"/>
<java jar="${proguard-home}/proguard.jar" fork="true" failonerror="true">
<jvmarg value="-Dmaximum.inlined.code.length=32"/>
<arg value="-injars temp.jar"/>
<arg value="-outjars optimized.jar"/>
<arg value="-libraryjars ${android-jar}"/>
<!-- <arg value="-libraryjars ${external-libs}/*.jar"/>-->
<arg value="-dontpreverify"/>
<arg value="-dontoptimize"/>
<arg value="-dontusemixedcaseclassnames"/>
<arg value="-repackageclasses ''"/>
<arg value="-allowaccessmodification"/>
<!--<arg value="-keep public class ${exclude-activity}"/>-->
<!--<arg value="-keep public class ${exclude-provider}"/>-->
<arg value="-keep public class * extends android.app.Activity"/>
<arg value="-keep public class * extends android.content.ContentProvider"/>
<arg value="-keep public class * extends android.view.View"/>
<arg value="-keep public class * extends android.preference.Preference"/> <arg value="-optimizationpasses 7"/>
<arg value="-verbose"/>
<arg value="-dontskipnonpubliclibraryclasses"/>
<arg value="-dontskipnonpubliclibraryclassmembers"/>
</java>
<delete file="temp.jar"/>
<delete dir="${outdir-classes}"/>
<mkdir dir="${outdir-classes}"/>
<unzip src="optimized.jar" dest="${outdir-classes}"/>
<delete file="optimized.jar"/>
</target>
注意:-keep这个参数是表示哪些类不被混淆,具体查看progurard的文档。这里凡是在xml文件中配置的文件均不可混淆,否则运行时候会找不到类的。
在编译的 target中加入 调用混淆target的命令 :
Xml代码 复制代码
1. <antcall target="optimize"/>
这样既可。
如果你使用了xmlpull类库的话,混淆的时候请不要加入到源代码中,android的类库中已经包含了 xmlpull,否则的话混淆是无法成功的,会出现Warning: library class android.content.res.XmlResourceParser extends or implements program class org.xmlpull .v1.XmlPullParser等相关的错误。
为Eclipse ADT创建的android项目通过ant添加proguard混淆支持(转载)
经本人测试,可行,测试时间2010-10-12
以下为转载内容:
假设已有ADT创建的android项目HelloAndroid并且已经有可用的proguard混淆器(我用的proguard4.4)。
第一步要做的是为项目添加ant build支持。由于ADT插件并不直接支持proguard等混淆器,所以不能像j2me那样在有功能比较完善的插件(如EclipseME等)的基础上直接一键混淆一键打包,不过好在android sdk本身提供了比较完善的ant编译支持,可以通过类似命令行编译的方式,对android项目的整个编译、生成过程进行自定义,从而能够实现对编译中途生成的java bytecode进行插入proguard混淆操作然后再转android dex码生成apk。
进入命令行模式,并切换到项目目录,执行如下命令为ADT创建的项目添加ant build支持:
d:\android-sdk-windows\tools\android.bat update project -p . -t 3
结果如下:
Updated default.properties
Updated local.properties
Added file D:\Projects\HelloAndroid\build.xml
刷新eclipse项目文件夹,侦测出sdk工具添加的build.xml和local.properties文件。然后,修改项目属性,在 Builders栏中新建一个Ant Builder(Ant在较新版本的Eclipse中已经内置,旧版本的话可能需要自己安装相关插件),对其中Buildfile选择生成的 build.xml,Base Directory选择项目目录即可。如果希望在编译项目时自动执行ant build就在刚创建builder的地方给ant builder打上勾,不勾的话就得手动执行build.xml进行编译。
现在尝试编译项目的话,会在控制台内显示类似如下的信息:
Buildfile: D:\Projects\HelloAndroid\build.xml
[setup] Project Target: Android 2.1
[setup] API level: 7
help:
[echo] Android Ant Build. Available targets:
[echo] help: Displays this help.
[echo] clean: Removes output files created by other targets.
[echo] compile: Compiles project’s .java files into .class files.
[echo] debug: Builds the application and signs it with a debug key.
[echo] release: Builds the application. The generated apk file must be
[echo] signed before it is published.
[echo] install: Installs/reinstalls the debug package onto a running
[echo] emulator or device.
[echo] If the application was previously installed, the
[echo] signatures must match.
[echo] uninstall: Uninstalls the application from a running emulator or
[echo] device.
BUILD SUCCESSFUL
Total time: 375 milliseconds
这样就基本说明使用ant build的android项目已经ok了,build脚本默认target是help,所以会显示如上信息,修改target为debug或release就可以像无ant时一样编译、生成以及调试了。
接下来看这一部分:
<!– Execute the Android Setup task that will setup some properties specific to the target,
and import the build rules files.
The rules file is imported from
<SDK>/platforms/<target_platform>/templates/android_rules.xml
To customize some build steps for your project:
- copy the content of the main node <project> from android_rules.xml
- paste it in this build.xml below the <setup /> task.
- disable the import by changing the setup task below to <setup import=”false” />
This will ensure that the properties are setup correctly but that your customized
build steps are used.
–>
<setup />
上面提示的就是我们需要做的,自定义build过程,根据提示copy android_rules.xml里
节点的内容(建议copy ant_rules_r3.xml)到下,然后修改setup属性,加入import=”false”。
完事后再次执行build.xml的话就已经用自己的build.xml覆盖了默认的整个build过程了。
如果在以上编译过程中控制台提示了编码问题,如中文注释等,可以对target compile中的
<javac encoding=”ascii” target=”1.5″ debug=”true” extdirs=”"
destdir=”${out.classes.absolute.dir}”
bootclasspathref=”android.target.classpath”
verbose=”${verbose}” classpath=”${extensible.classpath}”>
<src path=”${source.absolute.dir}” />
<src path=”${gen.absolute.dir}” />
<classpath>
<fileset dir=”${external.libs.absolute.dir}” includes=”*.jar” />
</classpath>
</javac>
中的encoding值进行修改,如改为GBK。
接下来,添加调用proguard混淆器的build targe:”optimize”
<!– Using proguard for the actual obfuscation.
Referenced from: http://code.google.com/p/zxing/source/browse/trunk/android-m3/build.xml?r=321 –>
<target name=”optimize” depends=”compile”>
<jar basedir=”${out.classes.absolute.dir}” destfile=”temp.jar”/>
<java jar=”D:/Program Files/proguard4.4/lib/proguard.jar” fork=”true” failonerror=”true”>
<jvmarg value=”-Dmaximum.inlined.code.length=32″/>
<arg value=”-injars temp.jar”/>
<arg value=”-outjars optimized.jar”/>
<arg value=”-libraryjars ${android.jar}”/>
<!– <arg value=”-libraryjars ${library-jar}/some_lib_used.jar”/> –>
<arg value=”-dontpreverify”/>
<arg value=”-dontoptimize”/>
<arg value=”-dontusemixedcaseclassnames”/>
<arg value=”-repackageclasses ””/>
<arg value=”-allowaccessmodification”/>
<arg value=”-keep public class com.HelloAndroid.Main”/>
<!– <arg value=”-keep public class com.just2me.obfapp.receiver.*”/> –>
<arg value=”-optimizationpasses 1″/>
<arg value=”-verbose”/>
<arg value=”-dontskipnonpubliclibraryclasses”/>
<arg value=”-dontskipnonpubliclibraryclassmembers”/>
</java>
<delete file=”temp.jar”/>
<delete dir=”${out.classes.absolute.dir}”/>
<mkdir dir=”${out.classes.absolute.dir}”/>
<unzip src=”optimized.jar” dest=”${out.classes.absolute.dir}”/>
<delete file=”optimized.jar”/>
</target>
其中需要修改java jar=”D:/Program Files/proguard4.4/lib/proguard.jar”中的proguard路径为对应路径,
<arg value=”-keep public class com.HelloAndroid.Main”/> 这部分中的class需要按照manifest中指定的类进行修改,同时,引用的外部lib也需要在这里指定,具体过程可以参考最后的几篇文章。
最后,修改-dex target的depends项,depends=”compile”加入optimize,为:depends=”compile,optimize”
再次执行编译,可看到optimize target的输出如下:
optimize:
[jar] Building jar: D:\Projects\HelloAndroid\temp.jar
[java] ProGuard, version 4.4
[java] Reading input…
[java] Reading program jar [D:\Projects\HelloAndroid\temp.jar]
[java] Reading library jar [D:\android-sdk-windows\platforms\android-2.1\android.jar]
[java] Initializing…
[java] Ignoring unused library classes…
[java] Original number of library classes: 2514
[java] Final number of library classes: 196
[java] Shrinking…
[java] Removing unused program classes and class elements…
[java] Original number of program classes: 13
[java] Final number of program classes: 5
[java] Obfuscating…
[java] Writing output…
[java] Preparing output jar [D:\Projects\HelloAndroid\optimized.jar]
[java] Copying resources from program jar [D:\Projects\HelloAndroid\temp.jar]
[delete] Deleting: D:\Projects\HelloAndroid\temp.jar
[delete] Deleting directory D:\Projects\HelloAndroid\bin\classes
[mkdir] Created dir: D:\Projects\HelloAndroid\bin\classes
[unzip] Expanding: D:\Projects\HelloAndroid\optimized.jar into D:\Projects\HelloAndroid\bin\classes
[delete] Deleting: D:\Projects\HelloAndroid\optimized.jar
表示proguard混淆已成功运作。
PS:如果在以上过程中提示javac不能找到这样类似的问题的话,可能的原因是创建的ant builder中的JRE项没有指定对,可以尝试修改为使用Separate JRE换换ant的JRE试试。
主要参考文章:
为android项目增加支持ant构建 http://marshal.easymorse.com/archives/1665
請為你的 Android 程式加上 obfuscation 吧! http://ysl-paradise.blogspot.com/2008/10/android-obfuscation.html
android混淆(Obfuscate) http://fonter.javaeye.com/blog/489728
android混淆(Obfuscate)
《Obfuscate an Android application》 这篇文章的作者介绍了如何在Android平台下混淆程序,并且给出ant的build.xml文件,经过自己的测试,发现里面少了一些target项,在Eclips会出错,后来结合zxing开源项目的build.xml文件,终于混淆成功,项目包减少了不少。
这里主要提一些注意事项,不提供源代码
1、创建build.xml文件
直接在项目的目录下新建一个名为build.xml的文件
2、创建Ant打包方式
项目 –> properties –> builders –> new –> ant builder
接着Buildfile选择项目build.xml文件,Base Dir选择项目目录就行了,记得勾上你的builders
3、build.xml文件修改
zxing这个文件没有加入混淆包选项,所以得做一些修改,如下示例
Xml代码 复制代码
1. <property name="proguard-home" value="D:\\Program Files\\proguard4.2\\lib\\"/>
2.
3. <target name="optimize" depends="compile">
4. <jar basedir="${outdir-classes}" destfile="temp.jar"/>
5. <java jar="${proguard-home}/proguard.jar" fork="true" failonerror="true">
6. <jvmarg value="-Dmaximum.inlined.code.length=32"/>
7. <arg value="-injars temp.jar"/>
8. <arg value="-outjars optimized.jar"/>
9. <arg value="-libraryjars ${android-jar}"/>
10. <!-- <arg value="-libraryjars ${library-jar}/some_lib_used.jar"/> -->
11. <arg value="-dontpreverify"/>
12. <arg value="-dontoptimize"/>
13. <arg value="-dontusemixedcaseclassnames"/>
14. <arg value="-repackageclasses ''"/>
15. <arg value="-allowaccessmodification"/>
16. <arg value="-keep public class com.iwidsets.WidsetsActivity"/>
17. <!-- <arg value="-keep public class com.just2me.obfapp.receiver.*"/> -->
18. <arg value="-optimizationpasses 7"/>
19. <arg value="-verbose"/>
20. <arg value="-dontskipnonpubliclibraryclasses"/>
21. <arg value="-dontskipnonpubliclibraryclassmembers"/>
22. </java>
23. <delete file="temp.jar"/>
24. <delete dir="${outdir-classes}"/>
25. <mkdir dir="${outdir-classes}"/>
26. <unzip src="optimized.jar" dest="${outdir-classes}"/>
27. <delete file="optimized.jar"/>
28. </target>
<property name="proguard-home" value="D:\\Program Files\\proguard4.2\\lib\\"/>
<target name="optimize" depends="compile">
<jar basedir="${outdir-classes}" destfile="temp.jar"/>
<java jar="${proguard-home}/proguard.jar" fork="true" failonerror="true">
<jvmarg value="-Dmaximum.inlined.code.length=32"/>
<arg value="-injars temp.jar"/>
<arg value="-outjars optimized.jar"/>
<arg value="-libraryjars ${android-jar}"/>
<!-- <arg value="-libraryjars ${library-jar}/some_lib_used.jar"/> -->
<arg value="-dontpreverify"/>
<arg value="-dontoptimize"/>
<arg value="-dontusemixedcaseclassnames"/>
<arg value="-repackageclasses ''"/>
<arg value="-allowaccessmodification"/>
<arg value="-keep public class com.iwidsets.WidsetsActivity"/>
<!-- <arg value="-keep public class com.just2me.obfapp.receiver.*"/> -->
<arg value="-optimizationpasses 7"/>
<arg value="-verbose"/>
<arg value="-dontskipnonpubliclibraryclasses"/>
<arg value="-dontskipnonpubliclibraryclassmembers"/>
</java>
<delete file="temp.jar"/>
<delete dir="${outdir-classes}"/>
<mkdir dir="${outdir-classes}"/>
<unzip src="optimized.jar" dest="${outdir-classes}"/>
<delete file="optimized.jar"/>
</target>
注意:keep public class com.iwidsets.WidsetsActivity需改成你的主Activity
并修改target dex
Xml代码 复制代码
1. <!-- Convert this project's .class files into .dex files. -->
2. <target name="dex" depends="compile,optimize">
3. <echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo>
4. <apply executable="${dx}" failonerror="true" parallel="true">
5. <arg value="--dex" />
6. <arg value="--output=${intermediate-dex-location}" />
7. <arg path="${outdir-classes-location}" />
8. <fileset dir="${external-libs-folder}" includes="*.jar"/>
9. </apply>
10. </target>
<!-- Convert this project's .class files into .dex files. -->
<target name="dex" depends="compile,optimize">
<echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo>
<apply executable="${dx}" failonerror="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-location}" />
<arg path="${outdir-classes-location}" />
<fileset dir="${external-libs-folder}" includes="*.jar"/>
</apply>
</target>
請為你的 Android 程式加上 obfuscation 吧!
Adding ProGuard task into your Android building steps.
在 在 Eclipse 內,用 Ant 編譯你的 Android 程式 這篇中,我介紹過如何利用 Ant 來編譯最佳化的 Android 程式。在那篇中,我只說到加上 debug="false" 和 ptimize="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。
- <target name="obfuscate" depends="compile">
- <jar basedir="${outdir-classes}" destfile="temp.jar"/>
- <taskdef resource="proguard/ant/task.properties"
- classpath="d:/proguard4.2/lib/proguard.jar" />
- <proguard>
- -injars temp.jar
- -outjars obfuscated.jar
- -libraryjars ${android-jar}
- -dontpreverify
- -dontskipnonpubliclibraryclasses
- -dontusemixedcaseclassnames
- -keep public class * extends android.app.Activity
- -keep public class * extends android.content.BroadcastReceiver
- -optimizationpasses 7
- </proguard>
- <delete file="temp.jar"/>
- <delete dir="${outdir-classes-final}" failonerror="false" />
- <mkdir dir="${outdir-classes-final}"/>
- <unzip src="obfuscated.jar" dest="${outdir-classes-final}"/>
- <delete file="obfuscated.jar"/>
- <echo>Obfuscated classes are put to "${outdir-classes-final}".</echo>
- </target>
再將原先 dex target,
- <!-- Convert this project's .class files into .dex files. -->
- <target name="dex" depends="compile">
- ...
- </target>
其中的 depends="compile" 改成 depends="obfuscate"。改好後,就像下面這樣。
- <!-- Convert this project's .class files into .dex files. -->
- <target name="dex" depends="obfuscate">
- ...
- </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 的程式碼最佳化功能,你可要多注意一下,是否所有的功能,在模擬器上,都可以正常執行。
Android代码混淆
2.3SDK的两个新特点:
1.刚安装上2.3时,查看sdk目录,发现 在<SDK_PATH>\tools下新增了一文件夹“proguard”,如下图,我就在想是不是Google终于官方对proguard 考虑进去了。理论上,对java的混淆都是可以的,但关键在于如何编写proguard的混淆脚本。
2.使用SDK2.3后,新建的工程下和之前相比,都会多了一个文件“proguard.cfg”。一打开,相当惊喜,这就是混淆所需的proguard脚本啊。
如下图:
其代码如下:
- -optimizationpasses 5
- -dontusemixedcaseclassnames
- -dontskipnonpubliclibraryclasses
- -dontpreverify
- -verbose
- -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
- -keep public class * extends android.app.Activity
- -keep public class * extends android.app.Application
- -keep public class * extends android.app.Service
- -keep public<