proguard_proguard配置 - CSDN
精华内容
参与话题
  • jar包混淆工具ProGuard 5.3

    热门讨论 2016-09-22 16:16:29
    官方网址:http://proguard.sourceforge.net/
  • Proguard用法

    千次阅读 2018-07-18 16:05:20
    混淆(Proguard)用法 最近项目中遇到一些混淆相关的问题,由于之前对proguard了解不多,所以每次都是面向Stackoverflow的编程。copy别人的答案内心还可以接受,但是copy了之后不懂别人的逻辑是无法忍受的。首先不...

    混淆(Proguard)用法

    最近项目中遇到一些混淆相关的问题,由于之前对proguard了解不多,所以每次都是面向Stackoverflow的编程。copy别人的答案内心还可以接受,但是copy了之后不懂别人的逻辑是无法忍受的。首先不清楚别人的答案是不是一定符合自己的需求;其次,再遇到同类问题还是得抓瞎。于是下决心看了一下proguard的官方文档。很长,但是很详细,在这里整理一下笔记,分享给大家。

    介绍


    我们通常说的proguard包括四个功能,shrinker(压缩), optimizer(优化),obfuscator(混淆),preverifier(预校验)。

    proguard process

    • shrink: 检测并移除没有用到的类,变量,方法和属性;
    • optimize: 优化代码,非入口节点类会加上private/static/final, 没有用到的参数会被删除,一些方法可能会变成内联代码。
    • obfuscate: 使用短又没有语义的名字重命名非入口类的类名,变量名,方法名。入口类的名字保持不变。
    • preverify: 预校验代码是否符合Java1.6或者更高的规范(唯一一个与入口类不相关的步骤)

    如果你的代码中用到了反射,那需要把反射调用的类,变量,方法也设置成入口节点。只需要加上-keep就可以了。(下面会讲)

    除了proguard之外,还有一个DexGuard,是专门用来优化混淆Android应用的。它的功能包括资源混淆,字符串加密,类加密和dex文件分割等。它是在android编译的时候直接产生Dalvik字节码。(这个有兴趣的同学自行了解,这里不详述了)

    用法


    要执行proguard,可以直接执行命令:

    java -jar proguard.jar options ...

    如果有Android SDK的同学可以在{ANDROID_SDK_ROOT}/tools/proguard/lib/目录下找到proguard.jar这个jar包。或者,也可以在{ANDROID_SDK_ROOT}/tools/proguard/bin目录下直接使用脚本执行命令。

    我们也可以把proguard的参数写到一个配置文件中,比如说proguard.cfg。那我们的命令可以这样写:

    java -jar proguard.jar @proguard.cfg

    这个文件也就是我们在Android Studio中经常配置的混淆文件了。我们在编译正式包的时候打包脚本自动帮我们执行了这条命令。通过这个脚本可以避免重复输入参数。

    当然,我们也可以配置文件与命令行参数混用,例如:

    java -jar proguard.jar @proguard.cfg -verbose
    • 配置文件中 # 放在行首,用来做注释;
    • 单词之间多余的空格或分隔符会被忽略;
    • 如果文件名包含空格或者其它特殊符号,应当用单引号或者双引号括起来;
    • 配置参数的顺序与混淆结果是没有关系的

    输入/输出选项


    这部分内容平常比较少用到,如果仅仅是做app开发的话,了解一下这一节即可。

    @_filename_ -include 的简写

    -include filename 需要读取的配置文件

    -basedirectory directory 为所有引用的相对路径指定一个根路径

    -injars classpath 指定输入的包,可以包括 jar, aar, war, ear, zip, apk或者文件目录。这些包或者目录下的class文件将被处理后写入到输出文件中。默认情况下非class文件会被原封不动的复制到输出文件中。

    需要注意的是,默认情况下,一些编译器的临时的文件也会被写入到输出文件中。可以使用过滤选项过滤掉他们。过滤选选项后面有讲到。

    -outjars classpath 指定输出文件,类型包括 jar, aar, war, ear, zip, apk和 目录。

    不要让输出文件覆盖任何一个输入文件!

    -libraryjars classpaath 指定输入文件引用的类库。这些类库不会被写入到输出文件中。每个库至少要有一个类被引用。

    在查找类库的时候,proguard运行时的类库是不算在内的。需要指明的是应用在运行时依赖的类库。

    简单用法:

    
     
    1. -injars classes

    2. -injars in1.jar

    3. -injars in2.jar

    4. -injars in3.jar

    5. -libraryjars <java.home>/lib/rt.jar(java/**,javax/**)

    6. -outjars out.jar

    -skipnonpubliclibraryclasses 指定读取引用库文件的时候跳过非public类。这样做可以提高处理速度并节省内存。一般情况下非public在应用内是引用不到的,跳过它们也没什么关系。但是,在一些java类库中中出现了public类继承非public类的情况,这样就不能用这个选项了。这种情况下,会打印一个警告出来,提示找不到类。

    -dontskipnonpubliclibraryclasses 跟上面的参数相对。版本4.5以上,这个是默认的选项。

    -dontskipnonpubliclibraryclassmembers 指定不忽略库类库中的非public成员(成员变量和方法)。默认情况下,proguard在读取库文件的时候会自动忽略这些类的成员,因为这些非public成员不会被源代码引用到。但有时候他们是可以被引用到的。比如说,源代码中与库文件用同一个包名,那么源代码就可以访问包作用域的变量。在这些情况下,为了引用一致,不被混淆,就需要指定不跳过这些类。

    -keepdirectories directory_filter 指定输出jar包中需要保留的目录名。为了减少输出文件的体积,默认情况下所有的目录都会被删除(个人这里不是很理解,猜测意思是默认所有目录都会被混淆吧)。但是如果你的代码中有需要从目录中寻找文件的逻辑,那你就需要保持目录名一致。这项配置后面不加过滤器的时候,所有目录都会被保留。加了过滤器之后,只有过滤器匹配的目录才会被保留。

    -target version 指定处理的class文件中java的目标版本。版本号是1.0, 1.1, 1.2, 1.3, 1.4, 1.5(或者5), 1.6(或者6), 1.7(或者7),1.8(或者8)之中的一个。默认情况下,class文件的版本号是不会变的。

    -forceprocessing 尽管输出文件已经是最新的,还是强制进行处理一次。

    Keep配置


    -keep [,modifier, ...] class_specification 指定类和类的成员变量是入口节点,保护它们不被移除混淆。例如,对一个可执行jar包来说,需要保护main的入口类;对一个类库来说需要保护它的所有public元素。例子:

    
     
    1. -injars myapplication.jar

    2. -outjars myapplication_out.jar

    3. -libraryjars <java.home>/lib/rt.jar

    4. -printmapping myapplication.map

    5.  
    6. -keep public class mypackage.MyMain {

    7. public static void main(java.lang.String[]);

    8. }

    -keepclassmembers [,modifier] class_specification 保护的指定的成员变量不被移除、优化、混淆。例如,保护所有序列化的类的成员变量。
    例子:

    
     
    1. -keepnames class * implements java.io.Serializable

    2. # 这指定了继承Serizalizable的类的如下成员不被移除混淆

    3. -keepclassmembers class * implements java.io.Serializable {

    4. static final long serialVersionUID;

    5. private static final java.io.ObjectStreamField[] serialPersistentFields;

    6. !static !transient <fields>;

    7. !private <fields>;

    8. !private <methods>;

    9. private void writeObject(java.io.ObjectOutputStream);

    10. private void readObject(java.io.ObjectInputStream);

    11. java.lang.Object writeReplace();

    12. java.lang.Object readResolve();

    13. }

    -keepclasseswithmembers [,modifier,...] class_specification 拥有指定成员的类将被保护,根据类成员确定一些将要被保护的类。例如保护所有含有main方法的类。
    例子:

    
     
    1. # 这种情况下含有main方法的类和mainf方法都不会被混淆。

    2. -injars in.jar

    3. -outjars out.jar

    4. -libraryjars <java.home>/lib/rt.jar

    5. -printseeds

    6.  
    7. -keepclasseswithmembers public class * {

    8. public static void main(java.lang.String[]);

    9. }

    -keepnames class_specification 是 -keep,allowshrinking class_pecification 的简写。指定一些类名受到保护,前提是他们在shrink这一阶段没有被去掉。也就是说没有被入口节点直接或间接引用的类还是会被删除。仅在obfuscate阶段有效。

    -keepclassmembernames class_specification 是-keepclasseswithmembers,allowshrinking class_specification的简写。与-keepclassmember相似。保护指定的类成员,前提是这些成员在shrink阶段没有被删除。仅在obfuscate阶段有效。

    -keepclasseswithmembernames class_specification 是-keepclasseswithmembers,allowshrinking class_specification的简写。与-keepclasseswithmembers类似。保护指定的类,如果它们没有在shrink阶段被删除。仅在obfuscate阶段有效。

    -printseeds [filename] 指定通过-keep配置匹配的类或者类成员的详细列表。列表可以打印到标准输出流或者文件里面。这个列表可以看到我们想要保护的类或者成员有没有被真正的保护到,尤其是那些使用通配符匹配的类。

    代码压缩配置


    -dontshrink 声明不压缩输入文件。默认情况下,除了-keep相关配置指定的类,所有其它没有被引用到的类都会被删除。每次optimizate操作之后,也会执行一次压缩操作,因为每次optimizate操作可能删除一部分不再需要的类。

    -printusage [filename] 声明 打印出那些被删除的元素。这个列表可能打印到标准输出流或者一个文件中。仅在shrink阶段有效。

    whyareyoukeeping class_specification 声明 打印为什么一个类或类的成员变量被保护。这对检查一个输出文件中的类的结果有帮助。

    代码优化配置


    -dontoptimize 声明不优化输入文件。默认情况下,优化选项是开启的,并且所有的优化都是在字节码层进行的。

    -optimizations optimization_filter 更加细粒度地声明优化开启或者关闭。只在optimize这一阶段有效。这个选项的使用难度较高。

    -optimizationpasses n 指定执行几次优化,默认情况下,只执行一次优化。执行多次优化可以提高优化的效果,但是,如果执行过一次优化之后没有效果,就会停止优化,剩下的设置次数不再执行。这个选项只在optimizate阶段有效

    assumenosideeffects class_specification 指定一些方法被删除也没有影响(尽管这些方法可能有返回值),在optimize阶段,如果确定这些方法的返回值没有使用,那么就会删除这些方法的调用。proguard会自动的分析你的代码,但不会分析处理类库中的代码。例如,可以指定System.currentTimeMillis(),这样在optimize阶段就会删除所有的它的调用。还可以用它来删除打印Log的调用。这条配置选项只在optimizate阶段有用。
    例子:

    
     
    1. # 删除代码中Log相关的代码

    2. -assumenosideeffects class android.util.Log {

    3. public static boolean isLoggable(java.lang.String, int);

    4. public static int v(...);

    5. public static int i(...);

    6. public static int w(...);

    7. public static int d(...);

    8. public static int e(...);

    9. }

    使用这条配置有点危险,如果删除了一些预料之外的代码,很容易就会导致代码崩溃。所以,谨慎使用

    -allowaccessmodification 这项配置是设置是否允许改变作用域的。使用这项配置之后可以提高优化的效果。**但是,如果你的代码是一个库的话,最好不要配置这个选项,因为它可能会导致一些private变量被改成public

    -mergeinterfacesaggressively 指定一些接口可能被合并,即使一些子类没有同时实现两个接口的方法。这种情况在java源码中是不允许存在的,但是在java字节码中是允许存在的。它的作用是通过合并接口减少类的数量,从而达到减少输出文件体积的效果。仅在optimize阶段有效。

    这项配置对于一些虚拟机的65535方法数限制是有一定效果的。

    混淆配置


    -dontobfuscate 声明不混淆。默认情况下,混淆是开启的。除了keep配置中声明的类,其它的类或者类的成员混淆后会改成简短随机的名字。

    -printmapping [filename] 指定输出新旧元素名的对照表的文件。映射表会被输出到标准输出流或者是一个指定的文件。

    这个文件在追踪异常的时候是有用的,在{android_sdk_home}/tools/proguard/lib目录下有一个retrace.jar文件。我们可以把混淆后的Stack Trace用这个工具处理一下,就会转变成容易阅读的类。所以,做app应用的同学每次发版本的时候都要把这个文件留下来,并标记清楚版本。这对线上版本的调试非常重要。

    -applymapping filename 指定重用一个已经写好了的map文件作为新旧元素名的映射。元素名已经存在在mapping文件中的元素,按照映射表重命名;没有存在到mapping文件的元素,重新赋一个新的名字。mapping文件可能引用到输入文件中的类和类库中的类。这里只允许设置一个mapping文件。仅在obfuscate阶段有效。

    -obfuscationdictionary filename 指定一个文本文件用来生成混淆后的名字。默认情况下,混淆后的名字一般为a,b,c这种。通过使用-obfuscationdictionary配置的字典文件,可以使用一些非英文字符做为类名。成员变量名、方法名。字典文件中的空格,标点符号,重复的词,还有以'#'开头的行都会被忽略。需要注意的是添加了字典并不会显著提高混淆的效果,只不过是更不利与人类的阅读。正常的编译器会自动处理他们,并且输出出来的jar包也可以轻易的换个字典再重新混淆一次。最有用的做法一般是选择已经在类文件中存在的字符串做字典,这样可以稍微压缩包的体积。

    查找了字典文件的格式:一行一个单词,空行忽略,重复忽略

    例如:

    
     
    1. # 这里巧妙地使用java中的关键字作字典,混淆之后的代码更加不利于阅读

    2. #

    3. # This obfuscation dictionary contains reserved Java keywords. They can't

    4. # be used in Java source files, but they can be used in compiled class files.

    5. # Note that this hardly improves the obfuscation. Decent decompilers can

    6. # automatically replace reserved keywords, and the effect can fairly simply be

    7. # undone by obfuscating again with simpler names.

    8. # Usage:

    9. # java -jar proguard.jar ..... -obfuscationdictionary keywords.txt

    10. #

    11.  
    12. do

    13. if

    14. for

    15. int

    16. new

    17. try

    18. byte

    19. case

    20. char

    21. else

    22. goto

    23. long

    24. this

    25. void

    26. break

    27. catch

    28. class

    29. const

    30. final

    31. float

    32. short

    33. super

    34. throw

    35. while

    36. double

    37. import

    38. native

    39. public

    40. return

    41. static

    42. switch

    43. throws

    44. boolean

    45. default

    46. extends

    47. finally

    48. package

    49. private

    50. abstract

    51. continue

    52. strictfp

    53. volatile

    54. interface

    55. protected

    56. transient

    57. implements

    58. instanceof

    59. synchronized

    -classobfuscationdictionary filename 指定一个混淆类名的字典,字典的格式与-obfuscationdictionary相同

    -packageobfuscationdictionary filename 指定一个混淆包名的字典,字典格式与-obfuscationdictionary相同

    -overloadaggressively 混淆的时候大量使用重载,多个方法名使用同一个混淆名,但是他们的方法签名不同。这可以使包的体积减小一部分,也可以加大理解的难度。仅在混淆阶段有效。

    注意,这项配置有一定的限制:

    Sun的JDK1.2上会报异常

    Sun JRE 1.4上重载一些方法之后会导致序列化失败

    Sun JRE 1.5上pack200 tool重载一些类之后会报错

    java.lang.reflect.Proxy类不能处理重载的方法

    Google's Dalvik VM can't handle overloaded static fields(这句我不懂,重载静态变量是什么意思?有看懂的同学可以回复一下)

    -useuniqueclassmembernames 指定相同的混淆名对应相同的方法名,不同的混淆名对应不同的方法名。如果不设置这个选项,同一个类中将会有很多方法映射到相同的方法名。这项配置会稍微增加输出文件中的代码,但是它能够保证保存下来的mapping文件能够在随后的增量混淆中继续被遵守,避免重新命名。比如说,两个接口拥有同名方法和相同的签名。如果没有这个配置,在第一次打包混淆之后,他们两个方法可能会被赋予不同的混淆名。如果说下一次添加代码的时候有一个类同时实现了两个接口,那么混淆的时候必然会将两个混淆后的方法名统一起来。这样就必须要改混淆文件其中一处的配置,也就不能保证前后两次混淆的mapping文件一致了。(如果你只想保留一份mapping文件迭代更新的话,这项配置比较有用)

    -dontusemixedcaseclassnames 指定在混淆的时候不使用大小写混用的类名。默认情况下,混淆后的类名可能同时包含大写字母和小写字母。这样生成jar包并没有什么问题。只有在大小写不敏感的系统(例如windows)上解压时,才会涉及到这个问题。因为大小写不区分,可能会导致部分文件在解压的时候相互覆盖。如果有在windows系统上解压输出包的需求的话,可以加上这个配置。

    -keeppackagenames [package_filter] 声明不混淆指定的包名。 配置的过滤器是逗号隔开的一组包名。包名可以包含?,,*通配符,并且可以在前面加!否定符。

    -flatternpackagehierarchy [packagename] 所有重新命名的都重新打包,并把所有的类移动到packagename包下面。如果没有指定packagename或者packagename为"",那么所有的类都会被移动到根目录下

    -repackageclasses [package_name] 所有重新命名过的都重新打包,并把他们移动到指定的packagename目录下。如果没有指定packagename,同样把他们放到根目录下面。这项配置会覆盖-flatternpackagehierarchy的配置。它可以代码体积更小,并且更加难以理解。这个与废弃的配置-defaultpackage作用相同。

    如果需要从目录中读取资源文件,移动包的位置可能会导致异常。如果出现问题,就不要用这个配置了。

    -keepattributes [attribute_filter] 指定受保护的属性,可以有一个或者多个-keepattributes配置项,每个配置项后面跟随的是Java虚拟机和proguard支持的attribute(具体支持的属性先看这里),两个属性之间用逗号分隔。属性名中可以包含*,**,?等通配符。也可以加!做前导符,将某个属性排除在外。当混淆一个类库的时候,至少要保持InnerClassesExceptionsSignature属性。为了跟踪异常信息,需要保留SourceFileLineNumberTable两个属性。如果代码中有用到注解,需要把Annotion的属性保留下来。
    例子:

    
     
    1. -keepattributes SourceFile, LineNumberTable

    2. -keepattributes *Annotation*

    3. -keepattributes EnclosingMethod

    4.  
    5. # 可以直接写在一行

    6. -keepattributes Exceptions, InnerClasses, Signature, Deprecated,

    7. SourceFile, LineNumberTable, *Annotation*, EnclosingMethod

    -keepparameternames 指定被保护的方法的参数类型和参数名不被混淆。这项配置在混淆一些类库的时候特别有用,因为根据IDE提示的参数名和参数类型,开发者可以根据他们的语义获得一些信息,这样的类库更友好。

    -renamesourcefileattribute [string] 指定一个字符串常量设置到源文件的类的属性当中。这样就可以在-keepattributes配置中使用。(这条我理解的也不是很清楚)

    -adaptclassstrings [classfilter] 指定字符串常量如果与类名相同,也需要被混淆。如果没有加classfilter,所有的符合要求的字符串常量都会被混淆;如果带有classfilter,只有在匹配的类中的字符串常量才会受此影响。例如,在你的代码中有大量的类名对应的字符串的hard-code,并且不想保留他们的本名,那就可以利用这项配置完成。这项配置只在混淆阶段有效,但是在压缩/优化阶段,涉及到的类会自动保留下来。

    adaptresourcefilenames [file_filter] 如果资源文件与某类名同,那么混淆后资源文件被命名为与之对应的类的混淆名。不加file_filter的情况下,所有资源文件都受此影响;加了file_filter的情况下,只有匹配到的类受此影响。

    adaptresourcefilecontents [file_filter] 指定资源文件的中的类名随混淆后的名字更新。根据被混淆的名字的前后映射关系,更新文件中对应的包名和类名。同样,如果不配置file_filter,所有的资源文件都会受此影响;配置了filter之后,只有对应的资源文件才受此影响。

    文件的读写都是按照系统默认的字符集。如果有特殊的字符集的需求,可以修改java的执行参数,或者直接修改java虚拟机的配置文件。

    注意,这项配置最好只能影响到字符文件。如果影响到一些二进制文件会产生意外影响。所以,设置filter的时候,要设置的足够 '严格'

    预校验配置


    -dontpreverify 声明不预校验即将执行的类。默认情况下,在类文件的编译版本为java micro 版本或者大于1.6版本时,预校验是开启的。目标文件针对java6的情况下,预校验是可选的;针对java7的情况下,预校验是必须的,除非目标运行平台是Android平台,设置它可以节省一点点时间。

    目标为Java Micro版本的情况下,预校验是必须的。如果你声明了这项配置,你还需要加上下面一条配置。

    -microedition 声明目标平台是java micro版本。预校验会根据这项配置加载合适的StackMap,而不是用标准的StackMap

    普通配置


    -verbose 声明在处理过程中输出更多信息。添加这项配置之后,如果处理过程中出现异常,会输出整个StackTrace而不是一条简单的异常说明。

    -dontnote [class_filter] 声明不输出那些潜在的错误和缺失,比如说错别字或者重要的配置缺失。配置中的class_filter是一串正则表达式,混淆过程中不会输出被匹配到的类相关的内容。

    -dontwarn [class_filter] 声明不输出那些未找到的引用和一些错误,但续混淆。配置中的class_filter是一串正则表达式,被匹配到的类名相关的警告都不会被输出出来。

    慎用!

    -ignorewarnings 输出所有找不到引用和一些其它错误的警告,但是继续执行处理过程。不处理警告有些危险,所以在清楚配置的具体作用的时候再使用。

    -printconfiguration [filename] 输出整个处理过程中的所有配置参数,包括文件中的参数和命令行中的参数。可以不加文件名在标准输出流中输出,也可以指定文件名输出到文件中。它在调试的时候比较有用。

    -dump [filename] 声明输出整个处理之后的jar文件的类结构,可以输出到标准输出流或者一个文件中。

    下面这些说明对应了之前每个参数后面的过滤器

    Class Paths


    它对应上文中的所有class_path,他是用来指定输入输出文件的路径的。它可以有多个路径用分隔符隔开。

    我们也可以使用过滤器来过滤需要输出的文件。过滤器的格式如下:

    classpathentry([[[[[[aarfilter;]apkfilter;]zipfilter;]earfilter;]warfilter;]jarfilter;]filefilter)

    []中包含的内容是可选的意思。这样看有些麻烦,直接上个例子:

    
     
    1. -injars in1.jar

    2. # 输入文件中排除了META-IF/MANIFEST.MF文件

    3. -injars in2.jar(!META-INF/MANIFEST.MF)

    4. -injars in3.jar(!META-INF/MANIFEST.MF)

    5. -outjars out.jar

    
     
    1. # 这个的意思是只引入`java`,`javax`包中的类

    2. -libraryjars rt.jar(java/**.class,javax/**.class)

    File Names


    proguard支持绝对路径和相对路径。相对路径按照下面顺序被解释:

    • 如果设置了base directory,首先按照它来定位;
    • 其次,按照配置文件所在的路径定位;
    • 最后,按照工作路径(working directory,也就是执行这条命令的路径)来解释。(这个不可能没有!)

    名称中可以包含java系统属性,用<>包围。例如:

    -libraryjars <java.home>/lib/rt.jar # 可能代表/usr/local/java/jdk/jre/lib/rt.jar

    如果路径名中带有特殊字符,可以使用单引号或者双引号括起来。

    File Filters


    就像普通的匹配器一样,可以使用通配符来过滤文件名。

    • ? 代表文件名中的一个字符
    • * 代表文件名中的一部分,不包括文件分隔符
    • ** 代表文件名中的一部分,包括文件分隔符
    • ! 放在文件名前面表示将某文件排除在外

    Filters


    匹配的规则与File Filters相似。只是过滤的范围更加广泛。

    Keep配置整理


    -keep-keepnames的关系一开始理解的时候有些混乱。但是它们背后是有一定规则的,下面的表格展示了它们的联系与不同

    <ul><li>class 关键字可以匹配class类或interface类,但是<code>interface</code>关键字只能匹配interface类,<code>enum</code>关键字只能匹配enum类。在<code>interface</code>或<code>enum</code>关键字前加一个<code>!</code>,可以表示非这种类型的类。</li><li>
    <p>classname 必须写全名,比如<code>java.lang.String</code>。内部类用<code>$</code>间隔,例如,<code>java.lang.Thread$State</code>。类名可以用含有下面这些通配符的正则表达式匹配:</p>
    <ul><li>? 匹配类名中的一个字符,不包括文件分隔符。例如,<code>mypackage.Test?</code>可以匹配<code>mypackage.Test1</code>,<code>mypackage.Test2</code>,但不能匹配<code>mypackage.Test12</code>。</li><li>* 匹配类名中的0到多个字符但不包括文件分隔符。例如,<code>mypackage.*Test*</code>可以匹配到<code>mypackage.Test</code>和<code>mypackage.YourTestApplication</code>但是不能匹配<code>mypackage.mysubpackage.MyTest</code>。一种常用的写法<code>mypackage.*</code>就是匹配<code>mypackage</code>下的所有子文件。</li><li>** 可以匹配类名中的所有字符,可能包含多个分隔符。例如,<code>**.Test</code>就是匹配所有目录下的<code>Test</code>类,<code>mypackage.**</code>就是匹配mypackage及其子目录下的所有类。</li></ul></li><li>extend与implements 关键字是用来限制类的范围的。他们目前是等价的,用来匹配某些类的子类。需要注意的是,这个指定的类并不包括在匹配结果中,如果想要该类也被匹配到,就需要额外声明一项配置。</li><li>@ 符号匹配那些注解标志的类或类成员,它的通配符形式与classname的形式一样。</li><li>
    <p>成员变量和成员方法的匹配形式与java非常像,只是方法的参数不带参数名。此外,他们还可以使用通配符:</p>
    <blockquote>
    <p>变量名和方法名可以使用的通配符:</p>
    <ul><li>&lt;init&gt; 匹配一个类的所有构造函数</li><li>&lt;fields&gt; 匹配一个类中的所有成员变量</li><li>&lt;methods&gt; 匹配一个类中的所有方法</li><li>* 匹配类中的所有成员<br>
    列表。</li><li>? 匹配一个字符</li><li>* 匹配0到多个字符<br><strong>注意</strong>上述通配符并不能设置返回类型,并且只有&lt;init&gt;方法带有参数<br>
    修饰符中可以使用以下通配符匹配:</li><li>% 匹配java中的初始类型(int, boolean, long, float,double等)</li><li>? </li><li>* </li><li>** (这三个不解释了,同上)</li><li>*** 匹配所有类型,包括初始类型和非初始类型,数组和非数组。</li><li>... 匹配任意参数列表<br>
    需要注意的是?, *, **不能够匹配初始类型和数组。***可以匹配到数组。例子:
    <pre class="hljs lisp" name="code" οnclick="hljs.copyCode(event)"><code class="lisp hljs vbscript">** <span class="hljs-keyword">get</span>*<span class="hljs-list">()</span></code><div class="hljs-button" data-title="复制"></div></pre>
    上面的例子可以匹配到<code>java.lang.Object getObject()</code>,但是不能匹配<code>float getFloat()</code>或者<code>java.lang.Object[] getObjects()</code>。</li></ul></blockquote>
    </li><li>
    <p>构造函数也可以使用简单类名或全类名来指定。就像java中的构造函数一样有参数列表但是没有返回类型。</p>
    </li><li>
    <p>类或者类成员的修饰符也是匹配类的限制条件。通过修饰符限制,可以缩小匹配的范围。修饰符组合也是可以的,就像java中的<code>public static</code>一样,但是不能冲突, 比如<code>public private</code>。</p>
    </li></ul>
       
         
         
         

    如果不确定自己该用哪个的话,就用-keep吧,它能保证匹配的类在压缩这一阶段不被移除,并且在混淆阶段不会被重新命名。

    • 如果只声明保护一个类,并没有指定受保护的成员。proguard只会保护它的类名和它的无参构造函数。其它成员依旧会被压缩、优化、混淆。
    • 如果声明保护一个方法,proguard会把它当作程序的入口点,方法名不会变,但它里面的代码依旧会被优化、混淆。

    Keep配置的修饰符


    includedescriptorclasses

    它是用来声明描述目标成员的元素也应当被保护。它在保护native方法时特别有效。因为它可以同时保证参数类型,返回类型不被混淆。保证最终的方法签名保持一致。

    例子:

    
     
    1. -keepclasseswithmembernames,includedescriptorclasses class * {

    2. native <methods>;

    3. }

    -keepclasseswithmembernames是保护符合条件的含有native方法的类。附加的includedescriptorclasses是保证参数和返回类型的类同样不被混淆。这样就可以做到这些类的方法签名与调试时完全一致。

    allowshrinking

    修饰-keep, 声明一个元素可以被移除,即使它已经声明了被保护。意味着它有可能在压缩阶段被删除,但是它又是必须的入口,所以它有可能不参与优化和混淆阶段。
    (这里我也看不太懂,压缩阶段不是依赖keep声明的入口节点吗?)

    allowoptimization

    修饰-keep, 声明一个元素可以被优化,即使它已经声明被保护。这意味着该元素参与优化阶段,但是不参与压缩和混淆阶段。特殊用途的时候使用。

    allowobfuscation

    与前几个类似,修饰-keep,只参与混淆阶段,但是不参与压缩和优化阶段。

    类的匹配


    Class Specification是指一个类和类成员的模板。它一般跟在各种-keep配置或者assumenosideeffects配置之后,只有匹配到的类和类成员会受到影响。

    Class Specification的形式与java的类的形式很像,只是而外加了几个通配符。如果想要清晰的看它的形式,最好看例子。但这里还是给出了通用的模型:

    
     
    1. [@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname

    2. [extends|implements [@annotationtype] classname]

    3. [{

    4. [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> |

    5. (fieldtype fieldname);

    6. [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> |

    7. <init>(argumenttype,...) |

    8. classname(argumenttype,...) |

    9. (returntype methodname(argumenttype,...));

    10. [@annotationtype] [[!]public|private|protected|static ... ] *;

    11. ...

    12. }]

    • []代表可选可不选;
    • ···代表还有更多选项可以配置;
    • |分隔的部分代表多选一;
    • ()括起来的部分代表是一个整体,不能分割。
    • class 关键字可以匹配class类或interface类,但是interface关键字只能匹配interface类,enum关键字只能匹配enum类。在interfaceenum关键字前加一个!,可以表示非这种类型的类。
    • classname 必须写全名,比如java.lang.String。内部类用$间隔,例如,java.lang.Thread$State。类名可以用含有下面这些通配符的正则表达式匹配:

      • ? 匹配类名中的一个字符,不包括文件分隔符。例如,mypackage.Test?可以匹配mypackage.Test1,mypackage.Test2,但不能匹配mypackage.Test12
      • * 匹配类名中的0到多个字符但不包括文件分隔符。例如,mypackage.*Test*可以匹配到mypackage.Testmypackage.YourTestApplication但是不能匹配mypackage.mysubpackage.MyTest。一种常用的写法mypackage.*就是匹配mypackage下的所有子文件。
      • ** 可以匹配类名中的所有字符,可能包含多个分隔符。例如,**.Test就是匹配所有目录下的Test类,mypackage.**就是匹配mypackage及其子目录下的所有类。
    • extend与implements 关键字是用来限制类的范围的。他们目前是等价的,用来匹配某些类的子类。需要注意的是,这个指定的类并不包括在匹配结果中,如果想要该类也被匹配到,就需要额外声明一项配置。
    • @ 符号匹配那些注解标志的类或类成员,它的通配符形式与classname的形式一样。
    • 成员变量和成员方法的匹配形式与java非常像,只是方法的参数不带参数名。此外,他们还可以使用通配符:

      变量名和方法名可以使用的通配符:

      • <init> 匹配一个类的所有构造函数
      • <fields> 匹配一个类中的所有成员变量
      • <methods> 匹配一个类中的所有方法
      • * 匹配类中的所有成员
        列表。
      • ? 匹配一个字符
      • * 匹配0到多个字符
        注意上述通配符并不能设置返回类型,并且只有<init>方法带有参数
        修饰符中可以使用以下通配符匹配:
      • % 匹配java中的初始类型(int, boolean, long, float,double等)
      • ?
      • *
      • ** (这三个不解释了,同上)
      • *** 匹配所有类型,包括初始类型和非初始类型,数组和非数组。
      • ... 匹配任意参数列表
        需要注意的是?, *, **不能够匹配初始类型和数组。***可以匹配到数组。例子:
        ** get*()
        上面的例子可以匹配到java.lang.Object getObject(),但是不能匹配float getFloat()或者java.lang.Object[] getObjects()
    • 构造函数也可以使用简单类名或全类名来指定。就像java中的构造函数一样有参数列表但是没有返回类型。

    • 类或者类成员的修饰符也是匹配类的限制条件。通过修饰符限制,可以缩小匹配的范围。修饰符组合也是可以的,就像java中的public static一样,但是不能冲突, 比如public private

    混淆相关的点就这些了,下面的例子中是Android应用混淆的默认文件。它放在{android_sdk_home}/tools/proguard/proguard-android.txt文件中,其它的可以参考的例子在{android_sdk_home}/tools/proguard/examples/目录下。

    
     
    1. # This is a configuration file for ProGuard.

    2. # http://proguard.sourceforge.net/index.html#manual/usage.html

    3.  
    4. -dontusemixedcaseclassnames

    5. -dontskipnonpubliclibraryclasses

    6. -verbose

    7.  
    8. # Optimization is turned off by default. Dex does not like code run

    9. # through the ProGuard optimize and preverify steps (and performs some

    10. # of these optimizations on its own).

    11. -dontoptimize

    12. -dontpreverify

    13. # Note that if you want to enable optimization, you cannot just

    14. # include optimization flags in your own project configuration file;

    15. # instead you will need to point to the

    16. # "proguard-android-optimize.txt" file instead of this one from your

    17. # project.properties file.

    18.  
    19. -keepattributes *Annotation*

    20. -keep public class com.google.vending.licensing.ILicensingService

    21. -keep public class com.android.vending.licensing.ILicensingService

    22.  
    23. # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native

    24. -keepclasseswithmembernames class * {

    25. native <methods>;

    26. }

    27.  
    28. # keep setters in Views so that animations can still work.

    29. # see http://proguard.sourceforge.net/manual/examples.html#beans

    30. -keepclassmembers public class * extends android.view.View {

    31. void set*(***);

    32. *** get*();

    33. }

    34.  
    35. # We want to keep methods in Activity that could be used in the XML attribute onClick

    36. -keepclassmembers class * extends android.app.Activity {

    37. public void *(android.view.View);

    38. }

    39.  
    40. # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations

    41. -keepclassmembers enum * {

    42. public static **[] values();

    43. public static ** valueOf(java.lang.String);

    44. }

    45.  
    46. -keepclassmembers class * implements android.os.Parcelable {

    47. public static final android.os.Parcelable$Creator CREATOR;

    48. }

    49.  
    50. -keepclassmembers class **.R$* {

    51. public static <fields>;

    52. }

    53.  
    54. # The support library contains references to newer platform versions.

    55. # Don't warn about those in case this app is linking against an older

    56. # platform version. We know about them, and they are safe.

    57. -dontwarn android.support.**

    展开全文
  • 关于proguard的使用总结

    千次阅读 2017-12-05 11:50:18
    在聊proguard使用之前,先说说proguard到底是什么东东,我主要做android开发,平时一般都听过android混淆打包的说法,直观的感觉就是把写好的java代码,通过一种编码方式给混淆了,让别人不容易看出代码逻辑以及java...

    在聊proguard使用之前,先说说proguard到底是什么东东,我主要做android开发,平时一般都听过android混淆打包的说法,直观的感觉就是把写好的java代码,通过一种编码方式给混淆了,让别人不容易看出代码逻辑以及java类之间的关系。其实,殊不知,这种混淆打包所依仗的就是这里要讲的progurad工具。

    progurad工具实际上有四个功能。

    压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute)。
    
    优化(Optimize):对字节码进行优化,移除无用的指令。
    
    混淆(Obfuscate):使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名。
    
    预检(Preveirfy):在Java平台上对处理后的代码进行预检,确保加载的class文件是可执行的。

    但是在android混淆打包中,我们实际上只需要使用Obfusacate这个混淆功能。

    我们是通过配置命令的方式来使用proguard的,而命令又需要一些参数什么的,这个就涉及到通配符的问题,这里就从命令、通配符以及proguard不能混淆三个部分来对proguard进行总结。

    1、proguard命令

    根据我的个人经验,proguard使用最多的命令就是keep以及dontwarn这两个命令一个,一个表示保留对应的类方法属性等不要混淆,另一个就是表示不对指定的类、包中的不完整的引用发出警告。关于proguard的命令真的很多,遇到不懂得可以到ProGuard 最全混淆规则说明这篇文章中去查找,或者查看proguard manual

    我们知道android中混淆打包需要进行配置

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    这里有一个proguard-android.txt是基础配置,还有一个proguard-rules.pro这个文件中开发这可以添加自己的一些配置。我们就以proguard-android.txt文件中的配置来简单说说proguard命令吧。

    -dontusemixedcaseclassnames      #混淆时不生成大小写混合的类名,windows系统不能识别大小写
    
    -dontskipnonpubliclibraryclasses #不忽略指定jars中的非public calsses
    
    -verbose          #混淆过程中打印详细信息,如果异常终止则打印整个堆栈信息
    
    -dontoptimize     #关闭优化
    
    -dontpreverify    #关闭预验证,加快编译速度
    
    -keepattributes *Annotation* #指定要保留的任何可选属性,可以指定多个,用逗号分隔符分割
    
    -keep public class com.google.vending.licensing.ILicensingService   #指定对象不被混淆
    -keep public class com.android.vending.licensing.ILicensingService
    
    #指定保留的类和类成员,这里是指保留带native方法的类不被混淆
    -keepclasseswithmembernames class * { 
        native <methods>;
    }
    
    #指定需要保留的类成员:变量或者方法,这里保留自定义控件的set/get方法不被混淆
    -keepclassmembers public class * extends android.view.View {
       void set*(***);
       *** get*();
    }
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    -keepclassmembers class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator CREATOR;
    }
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    #不对指定的类、包中的不完整的引用发出警告
    -dontwarn android.support.**
    
    #指定对象不被混淆
    -keep class android.support.annotation.Keep
    -keep @android.support.annotation.Keep class * {*;}
    
    #指定保留的类和类成员,这里指带Keep annotation的类不被混淆
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <methods>;
    }
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <fields>;
    }
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <init>(...);
    }

    基础配置已经把常用的proguard命令都用上了,代码中也给出了解释,还有不懂得,请查看上面提到的两篇文章。

    2、proguard的关键字和通配符

    肯定有同学看了上面的配置后还是有疑惑,proguard命令知道了,那么第一小节代码中的*、…这些符号是啥啊,这些就是这一小节要讲的通配符了。

    我们要指定混淆规则,但是项目中的类啊,方法什么的太多了,我们不能一个个去指定,那么通配符便大有用武之地了,通配符的作用便是通过符号统一指定一种类型的类、方法以及属性等的特殊符号。

    那么关键字是什么呢,这个比较简单,就是配置代码中的class、interface、enum、extends、implements等字符。

    class 关键字表示任何接口类、抽象类和普通类; interface 关键字表示只能是接口类; enum 关键字表示只能是枚举类。如果在 interface 和 enum 关键字前面加上感叹号(“ ! ”)分别表示不是接口类的类和不是枚举类的类,而 class 关键字前面不能加感叹号。

    extends表示存在继承关系,而implements表示存在实现关系。

    下面来分类说说通配符,proguard的“?”以及“*”应该是可以通用的,可以分别表示一个字符和n个字符(不含”.”)。但是对于类,方法、属性、以及参数、返回类型、参数类型等的通配符还是有一定差异的,下面直接给出作为参考。

    类名

    1) ? :问好代表一个任意字符,但不能是句号(“ . ”,因为句号是包名分隔符);
    2) * :单个星号代表任意个任意字符,但不能代表句号”.”
    3) ** :两个星号代表任意个任意字符,且能代表句号

    成员变量

    1)可以通过变量类型 fieldtype 和变量名 fieldname 来精确指定
    2)可以通过 表示类中的任何成员变量
    3)星号(“ * ”)可以匹配类中的任何成员变量和函数

    成员函数

    1)可以通过返回类型 returntype 、方法名 methodname 和参数类型 argumenttype 来唯一限定,
    2) 可以通过 来表示类中的任何成员函数,
    3)星号(“ * ”)可以匹配类中的任何成员函数

    构造函数

    1)可以用 加上构造函数的参数来指定。

    成员函数名、成员变量名

    1)问号(“ ? ”)可以匹配一个任意字符
    2)星号(“ * ”)可以匹配任意多个任意字符

    成员变量类型、成员函数返回类型以及参数、构造函数参数类型

    1) % :匹配任何原始类型,如 boolean 、 int 等,但不包括 void ;

    2) ? :匹配一个任意字符,不包括句号;

    3) * :匹配任意个任意字符,不包括句号;

    4) ** :匹配任意个任意字符,包括句号;

    5) * :匹配任意类型,包括原始类型和非原始类型,数组类型和非数组类型;

    6) … :匹配任何数目个任何类型的参数。

    另外还需要说明的是,在类名前、类中成员变量和成员函数名前,可以加上访问限定符(如 public 、 private 、 protected 等,修饰类、成员变量和成员函数的访问限定符各不相同),如果加上了访问限定符后,就表示要匹配的类、成员变量或成员函数的定义中必须包含这些限定符。

    3、android中不能混淆的代码

    proguard混淆是把混淆对象的名字进行修改,而有些对象的名字不能被修改,否则会报错,比如Activity类,修改后AndroidManifest中就找不到对应的Activityl了肯定要报错,还有反射也是。那么这里便总结下android开发中不能被混淆的代码

    1) Android系统组件

    即在AndroidManifest文件中注册的组件,如Activity,Service,BroadcastReceiver,ContentProvider,Application等。这些组件通过字符串的形式告知系统,当被调用的时候,如果这些类名被改变了,那么系统就会找不到它们。所以一般组件不进行混淆。

    2)Resource文件的使用

    例如各种资源的名字在xml已经固定使用,如果混淆也将找不到。所以一般R文件不混淆。

    3)序列化的类

    包括Parcelable和Serializable。如果混淆了可能UID等会错误,而且在反序列化的时候会找不到对应的名字。

    4)自定义控件

    如果自定义控件在xml中使用了,那么也不能混淆,否则找不到,当然如果在代码中用的话应该没问题。

    5)本地方法

    不能修改本地方法名,否则和so文件对应的方法就无法找到了。

    6.枚举

    系统需要处理枚举的固定方法。

    7)用到反射的地方

    因为反射需要通过名字去找变量和方法名,所以混淆后可能找不到。例如实际情况中的接口返回数据对应的实体类等等。

    8)ILicensingService系列

    ILicensingService系列(好像是aidl用的)和BackupAgentHelper备份相关的,不能进行混淆,不过这个东西一般没人用,所以不必在意。

    9)annotations 注释

    一般注释混淆其实可以混淆,但是混淆常会和反射相关联,所以还是不要混淆的好。

    10)android.preference.Preference

    此Preference可不是SharedPrefrences(但是有点关联),这个Preference也是一个组件,所以不能混淆。

    11)第三方包一般不混淆

    首先,第三方包没必要混淆,既然是第三方的,那么一般都是公开的,也就没有必要保护。其次,第三方包可能自己已经混淆过了,不用我们动手了。最后,第三方包里面可能用到了上述的这些不能混淆的点,如果我们不了解它,擅自去混淆,可能导致不能正常运行的结果。

    12)WebView中Java和Javascript互调的方法不能混淆

    因为它们都是通过名字去互相调用,如果名字变了就会找不到对应的方法。

    13)某些内部类的使用和泛型的使用需要避免混淆

    到这里proguard知识,我想总结的就算是总结完了,可能看了这些都不能立即写出很好的proguard配置来,但是了解本博文知识点后会对怎么配置成竹在胸,也能知道什么对象是不能混淆的。关于proguard的配置,最好的还是在实际开发中多尝试,找感觉。

    4、参考文献

    本文的内容很多都来自于其它博客,都是稍作修改,感谢那些童鞋们的辛苦付出,把参考文献列在这里吧,也方便自己查看。

    1、ProGuard 最全混淆规则说明

    2、Android ProGuard混淆基本语法(和通用配置)

    3、Android中混淆技术总结

    4、ProGuard代码混淆技术详解

    5、Android Studio(十一):代码混淆及打包apk

    6、Android混淆打包那些事儿

    展开全文
  • Proguard使用最新,最全教程,亲自试验

    万次阅读 多人点赞 2015-04-29 16:25:12
    最近公司有一个项目,是外包项目,由于对方也有技术人员,出于技术上的保密,需要对class文件进行二次处理,于是网上找了好久,只发现Proguard是用的最广泛而且网上资料最多的。由于不是纯JAVA项目,而是WEB项目,...

    最近公司有一个项目,是外包项目,由于对方也有技术人员,出于技术上的保密,需要对class文件进行二次处理,于是网上找了好久,只发现Proguard是用的最广泛而且网上资料最多的。由于不是纯JAVA项目,而是WEB项目,涉及到大量的配置文件,所以用这个工具稍显吃力,于是开始研究这玩意,花了好长一段时间,重复试验了N次,终于整出来了,下面总结一下我的经验。。

    首先我介绍下我要混淆的项目框架是jeecg+easyui+spring(包含xml配置文件,导致部分class文件不能直接混淆)。下面开始说详细的操作步奏:

    1)将web项目的src目录的java文件打包,只需要选择java文件即可,其他配置文件什么的都不用选择,如图


    2)http://proguard.sourceforge.net/下载proguard,目前我下载并使用的是proguard5.1(注:本人下载频道也有proguard5.1)。

    3)解压proguard5.1,执行 bin目录下的proguardgui.bat


    然后会弹出如下图所示窗口


    4)点击左边“input/output”菜单,然后点击右边的“Add input”按钮,添加需要混淆的jar包,我这里是test.jar,然后点击“add output”,选择输出的路径和包名。


    5)下面开始添加支持库,这个地方很重要,很多同学刚开始使用这个工具的时候就是这里老是出问题。
       点击右边的“add”。

    说明一下,这里最好把你的eclipse里java project里的libraries所有Library的jar包,包含web项目lib下面的包,jdk中jre下面的包和servlet.jar包等copy到一个目录,然后在这里加入这些jar包。系统默认会带上rt.jar,这里我们可以先remove掉,然后到jre下面copy所有的包。


    6)点击“shrinking”,设置成如图所示。


    7)点击“obfuscation”,设置如图所示


    8)点击“optimization”设置如图所示

    9)点击information,设置如图所示,注意选择jdk版本(Target


    10) 点击“process”,再点击“save configuration”,在弹出的对话框中,输入要保存的配置文件名称(这里我的是1111111.pro),最后点击保存”.



    11) 设置基本完成,关掉proguard窗口,找到刚刚保存的配置文件,开始手动修改部分配置。

    以下是我的配置文件,经测试通过,手动修改的部分为红色字体

    -injars Test\test.jar

    -outjars Test\test--.jar

     

    -libraryjars 'D:\jdk1.6.0_45\jre\lib\rt.jar'

    -libraryjars hunxiao\a\activation-1.1.jar

    -libraryjars hunxiao\a\activiti-cxf-5.10.jar

    -libraryjars hunxiao\a\activiti-engine-5.10.jar

    -libraryjars hunxiao\a\activiti-spring-5.10.jar

    -libraryjars hunxiao\a\alt-rt.jar

    -libraryjars hunxiao\a\alt-string.jar

    -libraryjars hunxiao\a\aopalliance-1.0.jar

    -libraryjars hunxiao\a\c3p0-0.9.1.2.jar

    -libraryjars hunxiao\a\charsets.jar

    -libraryjars hunxiao\a\commons-beanutils-1.9.1.jar

    -libraryjars hunxiao\a\commons-codec-1.9.jar

    -libraryjars hunxiao\a\commons-collections-3.2.1.jar

    -libraryjars hunxiao\a\commons-digester-1.7.jar

    -libraryjars hunxiao\a\commons-digester3-3.2.jar

    -libraryjars hunxiao\a\commons-io-2.0.1.jar

    -libraryjars hunxiao\a\commons-lang3-3.3.jar

    -libraryjars hunxiao\a\commons-logging-1.1.3.jar

    -libraryjars hunxiao\a\cos-26Dec2008.jar

    -libraryjars hunxiao\a\deploy.jar

    -libraryjars hunxiao\a\dom4j-1.6.1.jar

    -libraryjars hunxiao\a\druid-0.2.6.jar

    -libraryjars hunxiao\a\edtftpj.jar

    -libraryjars hunxiao\a\ehcache-core-2.5.2.jar

    -libraryjars hunxiao\a\fastjson-1.2.0.jar

    -libraryjars hunxiao\a\fprzMock.jar

    -libraryjars hunxiao\a\freemarker-2.3.16.jar

    -libraryjars hunxiao\a\groovy-all-1.5.5.jar

    -libraryjars hunxiao\a\guava-16.0.1.jar

    -libraryjars hunxiao\a\hessian-4.0.7.jar

    -libraryjars hunxiao\a\itext-2.1.7.jar

    -libraryjars hunxiao\a\iTextAsian-2.1.jar

    -libraryjars hunxiao\a\jasperreports-3.7.4.jar

    -libraryjars hunxiao\a\javaws.jar

    -libraryjars hunxiao\a\javax.servlet.jsp.jstl-1.2.0.v201105211821.jar

    -libraryjars hunxiao\a\jce.jar

    -libraryjars hunxiao\a\jfinal-1.6-bin-with-src.jar

    -libraryjars hunxiao\a\jfinal-ext-eu.jar

    -libraryjars hunxiao\a\jna-4.1.0.jar

    -libraryjars hunxiao\a\jna-platform-4.1.0.jar

    -libraryjars hunxiao\a\joda-time-2.1.jar

    -libraryjars hunxiao\a\joor-0.9.3.jar

    -libraryjars hunxiao\a\jsse.jar

    -libraryjars hunxiao\a\jxls-core-0.9.9.jar

    -libraryjars hunxiao\a\kaptcha-2.3.2.jar

    -libraryjars hunxiao\a\log4j-1.2.16.jar

    -libraryjars hunxiao\a\management-agent.jar

    -libraryjars hunxiao\a\mybatis-3.1.1.jar

    -libraryjars hunxiao\a\mysql-connector-java-5.1.20-bin.jar

    -libraryjars hunxiao\a\ojdbc6.jar

    -libraryjars hunxiao\a\org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar

    -libraryjars hunxiao\a\org.springframework.aop-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.asm-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.aspects-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.beans-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.context-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.context.support-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.core-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.expression-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.instrument-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.instrument.tomcat-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.jdbc-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.jms-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.org.apache.commons.logging-1.1.1.jar

    -libraryjars hunxiao\a\org.springframework.orm-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.oxm-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.test-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.transaction-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.web-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.web.portlet-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\org.springframework.web.servlet-3.1.1.RELEASE.jar

    -libraryjars hunxiao\a\plugin.jar

    -libraryjars hunxiao\a\poi-3.9.jar

    -libraryjars hunxiao\a\quartz-1.8.6.jar

    -libraryjars hunxiao\a\resources.jar

    -libraryjars hunxiao\a\rt.jar

    -libraryjars hunxiao\a\servlet-api.jar

    -libraryjars hunxiao\a\shiro-all-1.2.3.jar

    -libraryjars hunxiao\a\slf4j-api-1.6.1.jar

    -libraryjars hunxiao\a\slf4j-log4j12-1.6.1.jar

    -libraryjars hunxiao\a\sqlite-jdbc-3.7.2.jar

    -libraryjars hunxiao\a\ssosdk-2.0-SNAPSHOT.jar

    -libraryjars hunxiao\a\TaxWsBean.jar

     

    -target 1.6

    -dontshrink

    -useuniqueclassmembernames

    -keeppackagenames

    -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod

    -keepparameternames

     

    #保留单个类

    -keep public class net.easyunion.common.shiro.ShiroDbRealm

    -keep public class net.easyunion.common.filters.SetCharacterEncodingFilter

    -keep public class net.easyunion.common.queue.MakeQueue

     

    #保留所有控制类(如果是SSH三大框架,由于页面发出请求到struts核心拦截器拦截之后,找到配置文件,配置文件必须对应action里面的类和方法,这里就不能混淆类和方法,所以所有的action类包括里面的方法都不需要混淆,按照如下方式设置就行,保留所有的Action类名和方法名)

    -keep public class net.easyunion.app.invoice.controller.* {*;}

    -keep public class net.easyunion.app.sysseting.controller.* {*;}

    -keep public class net.easyunion.app.system.controller.* {*;}

    -keep public class net.easyunion.app.system.model.* {*;}

    -keep public class net.easyunion.app.supplier.controller.*  {*;}

    -keep public class net.easyunion.common.controller.*  {*;}

     

    -keep public class net.easyunion.app.Config

     

     

    # Keep names - Native method names. Keep all native class/method names.

    -keepclasseswithmembers,includedescriptorclasses,allowshrinking class * {

        native <methods>;

    }

     

    # Keep names - _class method names. Keep all .class method names. This may be

    # useful for libraries that will be obfuscated again with different obfuscators.

    -keepclassmembers,allowshrinking class * {

        java.lang.Class class$(java.lang.String);

        java.lang.Class class$(java.lang.String,boolean);

    }

     

    # Remove - System method calls. Remove all invocations of System

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.System {

        public static long currentTimeMillis();

        static java.lang.Class getCallerClass();

        public static int identityHashCode(java.lang.Object);

        public static java.lang.SecurityManager getSecurityManager();

        public static java.util.Properties getProperties();

        public static java.lang.String getProperty(java.lang.String);

        public static java.lang.String getenv(java.lang.String);

        public static java.lang.String mapLibraryName(java.lang.String);

        public static java.lang.String getProperty(java.lang.String,java.lang.String);

    }

     

    # Remove - Math method calls. Remove all invocations of Math

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.Math {

        public static double sin(double);

        public static double cos(double);

        public static double tan(double);

        public static double asin(double);

        public static double acos(double);

        public static double atan(double);

        public static double toRadians(double);

        public static double toDegrees(double);

        public static double exp(double);

        public static double log(double);

        public static double log10(double);

        public static double sqrt(double);

        public static double cbrt(double);

        public static double IEEEremainder(double,double);

        public static double ceil(double);

        public static double floor(double);

        public static double rint(double);

        public static double atan2(double,double);

        public static double pow(double,double);

        public static int round(float);

        public static long round(double);

        public static double random();

        public static int abs(int);

        public static long abs(long);

        public static float abs(float);

        public static double abs(double);

        public static int max(int,int);

        public static long max(long,long);

        public static float max(float,float);

        public static double max(double,double);

        public static int min(int,int);

        public static long min(long,long);

        public static float min(float,float);

        public static double min(double,double);

        public static double ulp(double);

        public static float ulp(float);

        public static double signum(double);

        public static float signum(float);

        public static double sinh(double);

        public static double cosh(double);

        public static double tanh(double);

        public static double hypot(double,double);

        public static double expm1(double);

        public static double log1p(double);

    }

     

    # Remove - Number method calls. Remove all invocations of Number

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.* extends java.lang.Number {

        public static java.lang.String toString(byte);

        public static java.lang.Byte valueOf(byte);

        public static byte parseByte(java.lang.String);

        public static byte parseByte(java.lang.String,int);

        public static java.lang.Byte valueOf(java.lang.String,int);

        public static java.lang.Byte valueOf(java.lang.String);

        public static java.lang.Byte decode(java.lang.String);

        public int compareTo(java.lang.Byte);

        public static java.lang.String toString(short);

        public static short parseShort(java.lang.String);

        public static short parseShort(java.lang.String,int);

        public static java.lang.Short valueOf(java.lang.String,int);

        public static java.lang.Short valueOf(java.lang.String);

        public static java.lang.Short valueOf(short);

        public static java.lang.Short decode(java.lang.String);

        public static short reverseBytes(short);

        public int compareTo(java.lang.Short);

        public static java.lang.String toString(int,int);

        public static java.lang.String toHexString(int);

        public static java.lang.String toOctalString(int);

        public static java.lang.String toBinaryString(int);

        public static java.lang.String toString(int);

        public static int parseInt(java.lang.String,int);

        public static int parseInt(java.lang.String);

        public static java.lang.Integer valueOf(java.lang.String,int);

        public static java.lang.Integer valueOf(java.lang.String);

        public static java.lang.Integer valueOf(int);

        public static java.lang.Integer getInteger(java.lang.String);

        public static java.lang.Integer getInteger(java.lang.String,int);

        public static java.lang.Integer getInteger(java.lang.String,java.lang.Integer);

        public static java.lang.Integer decode(java.lang.String);

        public static int highestOneBit(int);

        public static int lowestOneBit(int);

        public static int numberOfLeadingZeros(int);

        public static int numberOfTrailingZeros(int);

        public static int bitCount(int);

        public static int rotateLeft(int,int);

        public static int rotateRight(int,int);

        public static int reverse(int);

        public static int signum(int);

        public static int reverseBytes(int);

        public int compareTo(java.lang.Integer);

        public static java.lang.String toString(long,int);

        public static java.lang.String toHexString(long);

        public static java.lang.String toOctalString(long);

        public static java.lang.String toBinaryString(long);

        public static java.lang.String toString(long);

        public static long parseLong(java.lang.String,int);

        public static long parseLong(java.lang.String);

        public static java.lang.Long valueOf(java.lang.String,int);

        public static java.lang.Long valueOf(java.lang.String);

        public static java.lang.Long valueOf(long);

        public static java.lang.Long decode(java.lang.String);

        public static java.lang.Long getLong(java.lang.String);

        public static java.lang.Long getLong(java.lang.String,long);

        public static java.lang.Long getLong(java.lang.String,java.lang.Long);

        public static long highestOneBit(long);

        public static long lowestOneBit(long);

        public static int numberOfLeadingZeros(long);

        public static int numberOfTrailingZeros(long);

        public static int bitCount(long);

        public static long rotateLeft(long,int);

        public static long rotateRight(long,int);

        public static long reverse(long);

        public static int signum(long);

        public static long reverseBytes(long);

        public int compareTo(java.lang.Long);

        public static java.lang.String toString(float);

        public static java.lang.String toHexString(float);

        public static java.lang.Float valueOf(java.lang.String);

        public static java.lang.Float valueOf(float);

        public static float parseFloat(java.lang.String);

        public static boolean isNaN(float);

        public static boolean isInfinite(float);

        public static int floatToIntBits(float);

        public static int floatToRawIntBits(float);

        public static float intBitsToFloat(int);

        public static int compare(float,float);

        public boolean isNaN();

        public boolean isInfinite();

        public int compareTo(java.lang.Float);

        public static java.lang.String toString(double);

        public static java.lang.String toHexString(double);

        public static java.lang.Double valueOf(java.lang.String);

        public static java.lang.Double valueOf(double);

        public static double parseDouble(java.lang.String);

        public static boolean isNaN(double);

        public static boolean isInfinite(double);

        public static long doubleToLongBits(double);

        public static long doubleToRawLongBits(double);

        public static double longBitsToDouble(long);

        public static int compare(double,double);

        public boolean isNaN();

        public boolean isInfinite();

        public int compareTo(java.lang.Double);

        public byte byteValue();

        public short shortValue();

        public int intValue();

        public long longValue();

        public float floatValue();

        public double doubleValue();

        public int compareTo(java.lang.Object);

        public boolean equals(java.lang.Object);

        public int hashCode();

        public java.lang.String toString();

    }

     

    # Remove - String method calls. Remove all invocations of String

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.String {

        public static java.lang.String copyValueOf(char[]);

        public static java.lang.String copyValueOf(char[],int,int);

        public static java.lang.String valueOf(boolean);

        public static java.lang.String valueOf(char);

        public static java.lang.String valueOf(char[]);

        public static java.lang.String valueOf(char[],int,int);

        public static java.lang.String valueOf(double);

        public static java.lang.String valueOf(float);

        public static java.lang.String valueOf(int);

        public static java.lang.String valueOf(java.lang.Object);

        public static java.lang.String valueOf(long);

        public boolean contentEquals(java.lang.StringBuffer);

        public boolean endsWith(java.lang.String);

        public boolean equalsIgnoreCase(java.lang.String);

        public boolean equals(java.lang.Object);

        public boolean matches(java.lang.String);

        public boolean regionMatches(boolean,int,java.lang.String,int,int);

        public boolean regionMatches(int,java.lang.String,int,int);

        public boolean startsWith(java.lang.String);

        public boolean startsWith(java.lang.String,int);

        public byte[] getBytes();

        public byte[] getBytes(java.lang.String);

        public char charAt(int);

        public char[] toCharArray();

        public int compareToIgnoreCase(java.lang.String);

        public int compareTo(java.lang.Object);

        public int compareTo(java.lang.String);

        public int hashCode();

        public int indexOf(int);

        public int indexOf(int,int);

        public int indexOf(java.lang.String);

        public int indexOf(java.lang.String,int);

        public int lastIndexOf(int);

        public int lastIndexOf(int,int);

        public int lastIndexOf(java.lang.String);

        public int lastIndexOf(java.lang.String,int);

        public int length();

        public java.lang.CharSequence subSequence(int,int);

        public java.lang.String concat(java.lang.String);

        public java.lang.String replaceAll(java.lang.String,java.lang.String);

        public java.lang.String replace(char,char);

        public java.lang.String replaceFirst(java.lang.String,java.lang.String);

        public java.lang.String[] split(java.lang.String);

        public java.lang.String[] split(java.lang.String,int);

        public java.lang.String substring(int);

        public java.lang.String substring(int,int);

        public java.lang.String toLowerCase();

        public java.lang.String toLowerCase(java.util.Locale);

        public java.lang.String toString();

        public java.lang.String toUpperCase();

        public java.lang.String toUpperCase(java.util.Locale);

        public java.lang.String trim();

    }

     

    # Remove - StringBuffer method calls. Remove all invocations of StringBuffer

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.StringBuffer {

        public java.lang.String toString();

        public char charAt(int);

        public int capacity();

        public int codePointAt(int);

        public int codePointBefore(int);

        public int indexOf(java.lang.String,int);

        public int lastIndexOf(java.lang.String);

        public int lastIndexOf(java.lang.String,int);

        public int length();

        public java.lang.String substring(int);

        public java.lang.String substring(int,int);

    }

     

    # Remove - StringBuilder method calls. Remove all invocations of StringBuilder

    # methods without side effects whose return values are not used.

    -assumenosideeffects public class java.lang.StringBuilder {

        public java.lang.String toString();

        public char charAt(int);

        public int capacity();

        public int codePointAt(int);

        public int codePointBefore(int);

        public int indexOf(java.lang.String,int);

        public int lastIndexOf(java.lang.String);

        public int lastIndexOf(java.lang.String,int);

        public int length();

        public java.lang.String substring(int);

        public java.lang.String substring(int,int);

    }


    12)手动设置完成后保存,然后重新打开progrard,执行 bin目录下的proguardgui.bat。

       点击第一个选项“Proguard”,再点击“Load configuration”,选择我们刚才保存的“1111111.pro”进行加载。



    13然后点击Process,然后点击View configuration查看是否是已经修改过后的配置文件。


    14) 确认是最新修改过的配置文件,然后点击process!开始混淆。。

    如下图,表示混淆成功。。



    15)我们可以用jd-gui反编译工具看看混淆后的效果。可以看到,之前设置不混淆的类都没有更换类名,而混淆的类都自动更换为a,b,c等类名了。到此,整个java项目混淆就成功了,然后把混淆成功的class文件拷贝到自己的web项目中,替换原先的class文件,然后用tomcat跑项目,发现和正常的class文件运行效果一样,项目正常运行。



    16)说明下配置

    参数: 
     
    -include {filename}    从给定的文件中读取配置参数 
    -basedirectory {directoryname}    指定基础目录为以后相对的档案名称 
    -injars {class_path}    指定要处理的应用程序jar,war,ear和目录 
    -outjars {class_path}    指定处理完后要输出的jar,war,ear和目录的名称 
    -libraryjars {classpath}    指定要处理的应用程序jar,war,ear和目录所需要的程序库文件 
    -dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。 
    -dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。 

    保留选项 

    -keep {Modifier} {class_specification}    保护指定的类文件和类的成员 
    -keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好
    -keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。 
    -keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除) 
    -keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
    -keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后) 
    -printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件 
     
    压缩 

    -dontshrink    不压缩输入的类文件 
    -printusage {filename} 
    -whyareyoukeeping {class_specification}     
     
    优化 

    -dontoptimize    不优化输入的类文件 
    -assumenosideeffects {class_specification}    优化时假设指定的方法,没有任何副作用 
    -allowaccessmodification    优化时允许访问并修改有修饰符的类和类的成员 
     
    混淆 

    -dontobfuscate    不混淆输入的类文件 
    -printmapping {filename} 
    -applymapping {filename}    重用映射增加混淆 
    -obfuscationdictionary {filename}    使用给定文件中的关键字作为要混淆方法的名称 
    -overloadaggressively    混淆时应用侵入式重载 
    -useuniqueclassmembernames    确定统一的混淆类的成员名称来增加混淆 
    -flattenpackagehierarchy {package_name}    重新包装所有重命名的包并放在给定的单一包中 
    -repackageclass {package_name}    重新包装所有重命名的类文件中放在给定的单一包中 
    -dontusemixedcaseclassnames    混淆时不会产生形形色色的类名 
    -keepattributes {attribute_name,...}    保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses. 
    -renamesourcefileattribute {string}    设置源文件中给定的字符串常量

    展开全文
  • ProGuard详解

    万次阅读 多人点赞 2016-05-03 23:46:35
     对于ProGuard工具想必我们都不陌生,它能够通过移除无用代码,使用简短无意义的名称来重命名类,字段和方法。从而能够达到压缩、优化和混淆代码的目的。最终我们会获取一个较小的apk文件,并且我们这个通过...

    综述

      对于ProGuard工具想必我们都不陌生,它能够通过移除无用代码,使用简短无意义的名称来重命名类,字段和方法。从而能够达到压缩、优化和混淆代码的目的。最终我们会获取一个较小的apk文件,并且我们这个通过ProGuard处理的apk文件更难于进行逆向工程。

    ProGuard工作原理简介

      ProGuard能够对Java类中的代码进行压缩(Shrink),优化(Optimize),混淆(Obfuscate),预检(Preveirfy)。
      1. 压缩(Shrink):在压缩处理这一步中,用于检测和删除没有使用的类,字段,方法和属性。
      2. 优化(Optimize):在优化处理这一步中,对字节码进行优化,并且移除无用指令。
      3. 混淆(Obfuscate):在混淆处理这一步中,使用a,b,c等无意义的名称,对类,字段和方法进行重命名。
      4. 预检(Preveirfy):在预检这一步中,主要是在Java平台上对处理后的代码进行预检。
      对于ProGuard执行流程图如下图所示。
      这里写图片描述
      对于ProGuard的原理更详细的介绍可以参考Proguard手册,在这里就不在进行更详细的介绍。

    ProGuard使用

      ProGuard已集成到Android构建系统中,所以我们不用手动调用这个工具。我们可以选择在只发布模式下构建系统的时候再去运行ProGuard。
      在AndroidStudio中我们需要将Proguard添加到gradle.build文件的构建类型当中。不过在我们创建一个Android工程的时候,系统已经自动为我们添加到了gradle.build中。

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    minifyEnabled:开启混淆,我们新建的工程默认为false,因此,如果我们需要开启混淆的话就需要手动设为true。
    proguardFiles:这部分有两段,前一段代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,免去了我们很多事,这个文件的目录在/tools/proguard/proguard-android.txt , 后一部分是我们项目里的自定义的混淆文件,目录就在 app/proguard-rules.pro,在这个文件里我们可以声明一些我们所需要的定制的混淆规则。
      下面我们就来看一下这个默认的android程序混淆文件proguard-android.txt。对于下面一些指令与代码的含义在后面会进行说明。

    # This is a configuration file for ProGuard.
    # http://proguard.sourceforge.net/index.html#manual/usage.html
    
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -verbose
    
    # Optimization is turned off by default. Dex does not like code run
    # through the ProGuard optimize and preverify steps (and performs some
    # of these optimizations on its own).
    -dontoptimize
    -dontpreverify
    # Note that if you want to enable optimization, you cannot just
    # include optimization flags in your own project configuration file;
    # instead you will need to point to the
    # "proguard-android-optimize.txt" file instead of this one from your
    # project.properties file.
    
    -keepattributes *Annotation*
    -keep public class com.google.vending.licensing.ILicensingService
    -keep public class com.android.vending.licensing.ILicensingService
    
    # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    # keep setters in Views so that animations can still work.
    # see http://proguard.sourceforge.net/manual/examples.html#beans
    -keepclassmembers public class * extends android.view.View {
       void set*(***);
       *** get*();
    }
    
    # We want to keep methods in Activity that could be used in the XML attribute onClick
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    
    # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    -keepclassmembers class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator CREATOR;
    }
    
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    # The support library contains references to newer platform versions.
    # Don't warn about those in case this app is linking against an older
    # platform version.  We know about them, and they are safe.
    -dontwarn android.support.**
    
    # Understand the @Keep support annotation.
    -keep class android.support.annotation.Keep
    
    -keep @android.support.annotation.Keep class * {*;}
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <methods>;
    }
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <fields>;
    }
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <init>(...);
    }

    proguard-rules.pro配置

    ProGuard基本指令

      下面列举了我们开发中需要使用的一些指令。

    #代码混淆压缩比,在0~7之间,默认为5,一般不做修改
    -optimizationpasses 5
    
    #混合时不使用大小写混合,混合后的类名为小写
    -dontusemixedcaseclassnames
    
    #指定不去忽略非公共库的类
    -dontskipnonpubliclibraryclasses
    
    #这句话能够使我们的项目混淆后产生映射文件
    #包含有类名->混淆后类名的映射关系
    -verbose
    
    #指定不去忽略非公共库的类
    -dontskipnonpubliclibraryclassmembers
    
    #不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
    -dontpreverify
    
    #保留Annotation不混淆
    -keepattributes *Annotation*,InnerClasses
    
    #避免混淆泛型
    -keepattributes Signature
    
    #抛出异常时保留代码行号
    -keepattributes SourceFile,LineNumberTable
    
    #指定混淆是采用的算法,后面的参数是一个过滤器
    #这个过滤器是谷歌推荐的算法,一般不做更改
    -optimizations !code/simplification/cast,!field/*,!class/merging/*

    需要保留的代码

      下面列举了一些在我们的app开发中需要保留的内容。

    #保留我们使用的四大组件,自定义的Application等等这些类不被混淆
    #因为这些子类都有可能被外部调用
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Appliction
    -keep public class * extends android.app.Service
    -keep public class * extends android.content.BroadcastReceiver
    -keep public class * extends android.content.ContentProvider
    -keep public class * extends android.app.backup.BackupAgentHelper
    -keep public class * extends android.preference.Preference
    -keep public class * extends android.view.View
    -keep public class com.android.vending.licensing.ILicensingService
    
    #保留support下的所有类及其内部类
    -keep class android.support.** {*;}
    
    #保留R下面的资源
    -keep class **.R$* {*;}
    
    #保留本地native方法不被混淆
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    #保留在Activity中的方法参数是view的方法,
    #这样以来我们在layout中写的onClick就不会被影响
    -keepclassmembers class * extends android.app.Activity{
        public void *(android.view.View);
    }
    
    #保留枚举类不被混淆
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    #保留我们自定义控件(继承自View)不被混淆
    -keep public class * extends android.view.View{
        *** get*();
        void set*(***);
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);
    }
    
    #保留Parcelable序列化类不被混淆
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    
    #保留Serializable序列化的类不被混淆
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    
    #对于带有回调函数的onXXEvent的,不能被混淆
    -keepclassmembers class * {
        void *(**On*Event);
    }
    

    针对我们的App进行配置

    1. 对于实体类我们不能混淆
      对于实力类我们不能进行混淆,我们需要保留他们的set和get方法。对于boolean类型的get方法为isXXX,不能够遗漏。在开发的时候我们可以将所有的实体类放在一个包内,这样我们写一次混淆就行了。

    -keep public class com.ljd.example.entity.** {
        public void set*(***);
        public *** get*();
        public *** is*();
    }

    2. 在我们的app中使用了webView需要进行特殊处理
      在我们的项目中经常会嵌入一些webview做一些复杂的操作,这时候我们能够添加如下代码。

    -keepclassmembers class fqcn.of.javascript.interface.for.webview {
       public *;
    }
    -keepclassmembers class * extends android.webkit.webViewClient {
        public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
        public boolean *(android.webkit.WebView, java.lang.String);
    }
    -keepclassmembers class * extends android.webkit.webViewClient {
        public void *(android.webkit.webView, jav.lang.String);
    }

    3. 在app中与HTML5的JavaScript的交互进行特殊处理
      在我们的App中有时候需要与Html5中的JavaScript进行交互。例如:

    package com.ljd.example;
    
    public class JSInterface {
        @JavascriptInterface
        public void callAndroidMethod(){
            // do something
        }
    }

      我们需要确保这些js要调用的原生方法不能够被混淆,于是我们需要做如下处理:

    -keepclassmembers class com.ljd.example.JSInterface {
        <methods>;
    }

    4. 对含有反射类的处理

    -keep class 类所在的包.** { *; }

    5.对于第三方依赖库的处理
      这个取决于第三方的混淆策略。下面列举一些第三方依赖库的混淆策略。具体还以官方给出的为准。

    #支付宝
    -libraryjars libs/alipaysdk.jar
    -dontwarn com.alipay.android.app.**
    -keep public class com.alipay.**  { *; }
    
    # Retrolambda
    -dontwarn java.lang.invoke.*
    
    #realm
    -keep class io.realm.annotations.RealmModule
    -keep @io.realm.annotations.RealmModule class *
    -keep class io.realm.internal.Keep
    -keep @io.realm.internal.Keep class * { *; }
    -dontwarn javax.**
    -dontwarn io.realm.**
    
    # OrmLite
    -keep class com.j256.**
    -keepclassmembers class com.j256.** { *; }
    -keep enum com.j256.**
    -keepclassmembers enum com.j256.** { *; }
    -keep interface com.j256.**
    -keepclassmembers interface com.j256.** { *; }
    
    #极光推送
    -dontoptimize
    -dontpreverify
    
    -dontwarn cn.jpush.**
    -keep class cn.jpush.** { *; }
    
    #EventBus
    -keepattributes *Annotation*
    -keepclassmembers class ** {
        @org.greenrobot.eventbus.Subscribe <methods>;
    }
    -keep enum org.greenrobot.eventbus.ThreadMode { *; }
    
    # Only required if you use AsyncExecutor
    -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
        <init>(java.lang.Throwable);
    }
    
    #retroift
    -dontwarn retrofit2.**
    -keep class retrofit2.** { *; }
    -keepattributes Signature
    -keepattributes Exceptions
    
    #ButterKnife
    -keep class butterknife.** { *; }
    -dontwarn butterknife.internal.**
    -keep class **$$ViewBinder { *; }
    
    -keepclasseswithmembernames class * {
        @butterknife.* <fields>;
    }
    
    -keepclasseswithmembernames class * {
        @butterknife.* <methods>;
    }
    
    #fastjson
    -dontwarn com.alibaba.fastjson.**
    -keep class com.alibaba.fastjson.** { *; }
    
    #rxjava
    -dontwarn sun.misc.**
    -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
     long producerIndex;
     long consumerIndex;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
     rx.internal.util.atomic.LinkedQueueNode producerNode;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
     rx.internal.util.atomic.LinkedQueueNode consumerNode;
    }
    
    #jackson
    -dontwarn org.codehaus.jackson.**
    -dontwarn com.fasterxml.jackson.databind.**
    -keep class org.codehaus.jackson.** { *;}
    -keep class com.fasterxml.jackson.** { *; }
    
    #Facebook
    -keep class com.facebook.** {*;}
    -keep interface com.facebook.** {*;}
    -keep enum com.facebook.** {*;}
    
    #Fresco
    -keep class com.facebook.fresco.** {*;}
    -keep interface com.facebook.fresco.** {*;}
    -keep enum com.facebook.fresco.** {*;}

    在Android中配置ProGuard模板代码

      对于ProGuard的配置在下面给出代码的通用部分,在使用的时候直接复制即可,之后根据自己的项目进行添加一些自己项目中所需要保留的内容,以及所依赖第三方库的处理即可。在下面代码中对于在proguard-android.txt中已经添加过得代码在这里可以选择忽略。

    #############################################
    #
    # 对于一些基本指令的添加
    #
    #############################################
    -optimizationpasses 5
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -verbose
    -dontskipnonpubliclibraryclassmembers
    -dontpreverify
    -keepattributes *Annotation*,InnerClasses
    -keepattributes Signature
    -keepattributes SourceFile,LineNumberTable,Exceptions
    -optimizations !code/simplification/cast,!field/*,!class/merging/*
    
    
    #############################################
    #
    # Android开发中一些需要保留的公共部分
    #
    #############################################
    
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Appliction
    -keep public class * extends android.app.Service
    -keep public class * extends android.content.BroadcastReceiver
    -keep public class * extends android.content.ContentProvider
    -keep public class * extends android.app.backup.BackupAgentHelper
    -keep public class * extends android.preference.Preference
    -keep public class * extends android.view.View
    -keep public class com.android.vending.licensing.ILicensingService
    -keep class android.support.** {*;}
    -keep class **.R$* {*;}
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    -keepclassmembers class * extends android.app.Activity{
        public void *(android.view.View);
    }
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    -keep public class * extends android.view.View{
        *** get*();
        void set*(***);
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);
    }
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    -keepclassmembers class * {
        void *(**On*Event);
    }
    
    #webView处理,项目中没有使用到webView忽略即可
    -keepclassmembers class fqcn.of.javascript.interface.for.webview {
       public *;
    }
    -keepclassmembers class * extends android.webkit.webViewClient {
        public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
        public boolean *(android.webkit.WebView, java.lang.String);
    }
    -keepclassmembers class * extends android.webkit.webViewClient {
        public void *(android.webkit.webView, jav.lang.String);
    }
    
    #############################################
    #
    # 项目中特殊处理部分
    #
    #############################################
    
    #-----------处理反射类---------------
    
    ......
    
    #-----------处理js交互---------------
    
    ......
    
    #-----------处理实体类---------------
    
    ......
    
    #-----------处理第三方依赖库---------
    
    ......
    

    注意事项

    1. 确保混淆不会对项目产生影响
      对于我们的Android项目最好是能够在一开始就是用ProGuard进行处理。并且在debug模式下也进行ProGuard处理,这样就能够在我们的开发中进行处理ProGuard所造成的影响。
    2. 打包时忽略警告
      在我们打包的时候,会发现很多could not reference class之类的warning信息。如果我们能够确认App在运行中和那些引用没有什么关系,可以添加-dontwarn标签。如-dontwarn org.apache.harmony.**。
      我们不要使用-ignorewarnings语句,这个会忽略所有警告,会有很多潜在的风险。

    总结

      对于ProGuard的使用不是很复杂,但是在我们的项目中使用ProGuard是必不可少的,它不仅仅能够对代码进行混淆,还能够优化我们的代码,减少我们apk文件的体积。从而优化我们的代码

    附录

    Proguard手册
    ProGuard ReTrace 手册

    展开全文
  • ProGuard简介

    千次阅读 2018-11-19 16:14:05
    深入学习ProGuard之:ProGuard简介与android的应用 什么是ProGuardProGuard的官网中,关于ProGuard的描述是这样的: ProGuard is a Java class file shrinker, optimizer, obfuscator, and preverifier. ...
  • 1.业务需求 公司有块核心代码不希望...3.下载了proguard6.2.2这个版本,解压缩后执行proguard6.2.2\bin\proguardgui.bat这个文件就可以打开软件,标红框的地方是需要特别设置的,其他地方都可以默认 4.设置Input.
  • ProGuard技术详解

    千次阅读 2018-01-17 16:02:08
    ProGuard是一个开源的Java代码混淆器,在Android中一提起ProGuard,我们通常第一想到的是用来混淆代码的,其实它的功能并不仅限于此,有以下四个功能: (1)压缩(Shrink):侦测并移除代码中无用的类、字段、方法和...
  • ProGuard 最全混淆规则说明

    万次阅读 2018-08-01 10:19:59
    说明:本文参考(翻译)自Android SDK根目录下的proguard目录下的说明文档,是其中的一篇。,文中除了翻译外加了一些作者的实际验证。文章对Android混淆规则做一个解释说明。作者才疏学浅,如有错误,请谅解!&...
  • ProGuard

    2012-09-28 19:03:33
    http://developer.android.com/tools/help/proguard.html ...ProGuard In this document Enabling ProGuard Configuring ProGuard Decoding Obfuscated Stack Traces Debugging considerati
  • ProGuard的实例

    千次阅读 2015-03-05 15:29:16
    android google 使用 ProGuard 混淆,优化,压缩代码。翻译ProGuard实例。
  • ProGuard是一款免费的Java类文件的压缩、优化、混肴器。它删除没有用的类,字段,方法与属性。使字节码最大程度地优化,使用简短且无意义的名字来重命名类、字段和方法,截至2016-11-28号,5.3.1是最新版本 新的...
  • Android ProGuard技术详解

    千次阅读 2015-11-27 15:16:27
    ProGuard概述 ProGuard规则 语法 常用规则 ProGuard概述 ProGuard工具通过移除无用的代码以及使用语义隐晦的名称来重命名类、字段和方法,从而达到压缩、优化和混淆代码的目的。由于ProGuard会使应用更...
  • ProGuard 详解

    千次阅读 2017-03-12 16:17:49
    Android开发中的Proguard 本文为转载,原文链接:http://blog.csdn.net/ccpat/article/details/52059344 Proguard是Android开发时经常会用到的一个工具,在Android SDK中已经集成了一个免费的Proguard版本,...
  • proguard-proguard6.2.2.zip

    2020-08-16 10:58:52
    1.支持ant 使用proguard标签 2.支持windows环境混淆代码 3.支持Java8+ 新版本6x系列不再提供编译好的jar包 需要自己手动编译,7系列使用的gradle编译管理 国内不太好用,6x系列基本满足Java8+ 的代码混淆,具体可以...
  • Proguard

    2016-01-24 00:51:37
    启用Proguard(使用Gradle编译) 在build.gradle文件中使用minifyEnabled属性来启用或禁用Proguard.如:  android {  ...    buildTypes {  release {  minifyEnabled true  proguardFiles get
  • Android开发中的Proguard

    2018-05-30 15:10:24
    转自:https://blog.csdn.net/ccpat/article/details/52059344Proguard是Android开发时经常会用到的一个工具,在Android SDK中已经集成了一个免费的Proguard版本,位于&lt;sdk&gt;/tools/proguard目录中。在...
  • Android:混淆文件proguard.cfg详解

    千次阅读 2015-09-19 14:36:42
    下面给出proguard.cfg文件的内容:#指定代码的压缩级别 -optimizationpasses 5 #混淆时不会产生形形色色的类名 是否使用大小写混合 -dontusemixedcaseclassnames #指定不去忽略非公共的类库 是否混淆第三方jar -...
  • Android Studio:ProGuard 混淆配置

    万次阅读 2016-09-22 10:04:46
    Android Studio 创建Module后,会自动生成 proguard-rules.pro 文件,在其中添加需要的规则即可对apk或jar进行混淆。
  • Android Proguard工具使用和配置详解

    万次阅读 2016-07-28 23:51:34
    介绍Android Proguard工具的使用和配置方法
1 2 3 4 5 ... 20
收藏数 35,808
精华内容 14,323
关键字:

proguard