ProGuard runs only when you build your application in release mode,so you do not have to deal with obfuscated code when you build your applicationin debug mode.
在default.properties中配置:(如果隱藏在某個路徑中,則需要加上路徑)
proguard.config=proguard.cfg
When you build yourapplication in release mode, either by running antrelease or by using the Export Wizard inEclipse, the build system automatically checks to see if theproguard.config property is set. If it is, ProGuardautomatically processes the application's bytecode before packaging everythinginto an .apk file. Building in debug mode does not invoke ProGuard,because it makes debugging more cumbersome.
ProGuard outputs thefollowing files after it runs:
dump.txt···描述apk文件中所有類文件的內部結構
mapping.txt···列出了類、方法、成員的原貌與混淆後的映射表。在收到錯誤報告時,可以用它翻譯混淆後的堆棧信息。
seeds.txt···列出未混淆的類與成員
usage.txt···列出從apk中清除的無用代碼
這些文件的位置在:
<project_root>/bin/proguard if you are using Ant.
<project_root>/proguard if you are using Eclipse.
但是,proguard.cfg文件在以下情況下可能移除開發者要用到的類:
僅在AndroidManifest.xml文件中用到的類
從JNI中調用的方法
動態引用的fields和methods
這時,便會出現ClassNotFoundException的問題,需要在文件中加入:
-keep public class<MyClass>
The retrace.bat script on Windows or the retrace.shscript on Linux or Mac OS X can convert an obfuscated stack trace to a readableone. It is located in the <sdk_root>/tools/proguard/directory. The syntax for executing the retrace tool is:
retrace.bat|retrace.sh[-verbose] mapping.txt [<stacktrace_file>]
For example: retrace.bat -verbosemapping.txt obfuscated_trace.txt
Proguard manual的學習
經歷四步(shrink 瘦身-去除無用代碼,optimize 優化-優化方法的字節碼 ,obfuscate 混淆-用無意義段短名稱替代 ,preverify 預驗證-添加預驗證信息)。
對於使用反射的類,類名稱設置可能從配置文件中讀出,故需要專門指定為entry points.
不過,proguard還是對以下情況做了處理:
Class.forName("SomeClass")
SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod",new Class[] {})
SomeClass.class.getMethod("someMethod",new Class[] { A.class })
SomeClass.class.getMethod("someMethod",new Class[] { A.class, B.class })
SomeClass.class.getDeclaredMethod("someMethod",new Class[] {})
SomeClass.class.getDeclaredMethod("someMethod",new Class[] { A.class })
SomeClass.class.getDeclaredMethod("someMethod",new Class[] { A.class, B.class })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class,"someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class,"someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class,SomeType.class, "someField")
瘦身階段,保留以上類與方法;混淆階段,更新上面的字串。
指定injar/outjar時,可以使用文件夾或者非jar文件,而libraryjars允許我們處理android,j2ee等運行文件,例子:
-injars bin/classes
-injars libs
-outjars bin/classes-processed.jar
-libraryjars/usr/local/java/android-sdk/platforms/android-9/android.jar
-skipnonpubliclibraryclasses
跳過庫中非public的類,可以加快proguard處理速度;
但是有些類庫包含從public類中繼承來的非public類,
這時如果加了這條會產生一個warning(find classes)
-dontskipnonpubliclibraryclasses
從prog4.5開始,這時默認設置
-dontskipnonpubliclibraryclassmembers
默認會跳過,不過有時位於同一個包中的程序類作為庫類,
且他們引用了包內可見的類成員。
-printmapping myapplication.map
指定輸出映射文件
-keep
保留某類
-keepclassmembers
保留某類成員
-keepclasseswithmembers
保留類和類成員
-keepnames
相當於-keep,allowshrinking class_specification.同理,
對於其他的-keepXXXXXnames,同樣是加了allowshrinking 的簡稱
通配符:
? matchesany single character in a file name.
* matchesany part of a filename not containing the directory separator.
** matches any part of a filename, possibly containingany number of directory separators(可以跨文件夾或者包).
For example,"java/**.class,javax/**.class" matches all class files in the javaand javax.
Keep
From being removed or renamed
From being renamed
Classes and class members
-keep
-keepnames
Class members only
-keepclassmembers
-keepclassmembernames
Classes and class members, if class members present
-keepclasseswithmembers
-keepclasseswithmembernames
替代符:
<init> matchesany constructor.
<fields> matchesany field.
<methods> matchesany method.
* matchesany field or method.
Note that the abovewildcards don't have return types. Only the <init> wildcard has anargument list.
% matchesany primitive type ("boolean", "int", etc, but not"void").
? matchesany single character in a class name.
* matchesany part of a class name not containing the package separator.
** matchesany part of a class name, possibly containing any number of package separators.
*** matchesany type (primitive or non-primitive, array or non-array).
... matchesany number of arguments of any type.
Note,only the ***wildcards will match array types of any dimension. For example, "**get*()" matches "java.lang.Object getObject()", but not"float getFloat()", nor "java.lang.Object[] getObjects()".
作者:houshunwei