proguard学习
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
补充:移动开发 , Android ,