Android 代码混淆 选项说明

转载请注明出处:

   Android 代码混淆 选项说明

http://blog.csdn.net/jjwwmlp456/article/details/44977721  ----------------- 匆忙拥挤repeat



语法规范说明地址:https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/usage.html

sdk目录:  /sdk/tools/proguard


Input/Output Options   输入/输出 选项

@filename  
Short for '-include filename'.
-include filename  
递归读取目录中(如果有)文件的 配置:configuration options
-basedirectory directoryname
配置文件的目录    directoryname规则见 filename
-injars class_path
输入(即使用的) jar文件路径。作用: 对配置的jar文件,要进行混淆

        例:-injars "my program.jar":"/your directory/your program.jar"引号可以不要
-outjars class_path
输出 jar 路径
-libraryjars class_path
指定的jar将不被混淆,just run-time jar;注意这里在编译时会进行一次依赖,如果由gradle依赖过了,再配置该项,会造成重复依赖。
-skipnonpubliclibraryclasses
跳过(不混淆) jars中的 非public classes 
-dontskipnonpubliclibraryclasses
不跳过(混淆) jars中的 非public classes   默认选项
-dontskipnonpubliclibraryclassmembers
不跳过 jars中的非public classes的members
-keepdirectories [directory_filter]
指定目录 keep 在 out jars中    directory_filter规则见file filter
-target version
java版本  1.0, 1.1, 1.2, 1.3, 1.4, 1.5 (or just 5), 1.6 (or just 6), or 1.7 (or just 7).
-forceprocessing
指定input处理,即使output seems up to date


Keep Options  保持不变的选项

-keep [,modifier,...] class_specification

保持class_specification规则若有[,modifier,...],则先启用它的规则

-keepclassmembers [,modifier,...]class_specification

保持类的成员:属性(可以是成员属性、类属性)、方法(可以是成员方法、类方法)

-keepclasseswithmembers [,modifier,...] class_specification

与-keep功能基本一致(经测试)

-keepnames class_specification
Short for -keep,allowshrinking class_specification

-keepclassmembernames class_specification
Short for -keepclassmembers,allowshrinking class_specification

-keepclasseswithmembernames class_specification
Short for -keepclasseswithmembers,allowshrinking class_specification

-printseeds [filename]

打印匹配的-keep家族处理的 类和类成员列表,到标准输出。

用Proguard 命令行,能看到输出效果(未测试)


Shrinking Options 压缩选项

shrink,测试后发现会将一些无效代码给移除,即没有被显示调用的代码

-dontshrink

shrink操作默认启用,每个optimization步骤后,都会执行一步shrink。

该选项 表示 不启用 shrink。

测试后发现是全局性的,且即便使用了-keep 开启shrink,也无效

-printusage [filename]

打印被移除的代码,在标准输出
-whyareyoukeeping class_specification

打印 在shrink过程中 为什么有些代码被 keep


Optimization Options 优化选项

基于控制流、数据流分析后,删除、合并一些代码
-dontoptimize

optimization,默认启用

该选项表示 不启用

当不使用该选项时,下面的才有效
-optimizations optimization_filter

根据optimization_filter指定要优化的文件
-optimizationpasses n

优化数量 n  
-assumenosideeffects class_specification

如果一个方法有返回值,在调用的时候没使用到它的返回值,那么可能被忽略。

-allowaccessmodification

优化时允许访问并修改类和类的成员的 访问修饰符,可能作用域会变大。
-mergeinterfacesaggressively

竭力合并接口,即使它们的实现类未实现合并后接口的所有方法。


Obfuscation Options 混淆选项

混淆类名、属性名、方法名、变量名等,变成无意义的类似a,b,c,d...的名字

-dontobfuscate
不混淆
-printmapping [filename]
打印 映射旧名到新名
-applymapping filename
打印相关
-obfuscationdictionary filename
指定外部模糊字典
-classobfuscationdictionary filename
指定class模糊字典
-packageobfuscationdictionary filename
指定package模糊字典
-overloadaggressively
过度加载,多个属性和方法使用相同的名字,只是参数和返回类型不同 可能各种异常
-useuniqueclassmembernames
类和类成员都使用唯一的名字
-dontusemixedcaseclassnames
不使用大小写混合类名
-keeppackagenames [package_filter]
保持packagename 不混淆
-flattenpackagehierarchy [package_name]
指定重新打包,所有包重命名,这个选项会进一步模糊包名 好东西
将包里的类混淆成n个再重新打包到一个个的package中
-repackageclasses [package_name]
将包里的类混淆成n个再重新打包到一个统一的package中  会覆盖flattenpackagehierarchy选项
-keepattributes [attribute_filter]
# 混淆时可能被移除下面这些东西,如果想保留,需要用该选项。对于一般注解处理如 -keepattributes *Annotation*
# attribute_filter : Exceptions, Signature, Deprecated, SourceFile, SourceDir, LineNumberTable,
#LocalVariableTable, LocalVariableTypeTable, Synthetic,
#EnclosingMethod, RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations,
#RuntimeInvisibleParameterAnnotations, and AnnotationDefault.

-keepparameternames

-renamesourcefileattribute [string]

-adaptclassstrings [class_filter]

-adaptresourcefilenames [file_filter]

-adaptresourcefilecontents [file_filter]


Preverification Options 预校验选项

-dontpreverify
-microedition


General Options 通用选项

-verbose

打印详细
-dontnote [class_filter]

不打印某些错误
-dontwarn [class_filter]

不打印警告信息
-ignorewarnings

忽略警告,继续执行
-printconfiguration [filename]

打印配置文件
-dump [filename]

指定打印类结构


其他说明

Class Paths : class_path

类路径,unix分隔符为冒号(:),windows分隔符为分号(;)
可以表示的文件类型有:
· a class file or resource file
· a jar file
· a war file
· an ear file
· a zip file
· a directory(structure)

File Names : filename

文件或目录名,可以使用相对或绝对路径
可以使用Java system properties,表示法:<...>
如:<java.home>、<user.home>、<user.dir> 等

File Filters : file_filter

文件过滤。
通配符:
?  匹配任意一个单个字符
*  匹配任意多个字符,不含目录分隔符:unix下为(/),windows下为(\)
** 匹配任意多个字符,含目录分隔符
还可以使用一个逻辑符号:!
! 表示 求反,除...之外

Filters : package_filter、attribute_filter、class_filter

可以过滤的有:names of files, directories, classes, packages, attributes, optimizations(见下文)
通配符:
?  匹配任意一个单个字符
*  匹配任意多个字符,不含目录分隔符和package分隔符: .  
** 匹配任意多个字符,含目录分隔符和package分隔符:. 
还可以使用一个逻辑符号:!
! 表示 求反,除...之外

Overview of Keep Options 

keep 选项,表示保持 类或类成员(方法和属性) 不变。各选项间的关系:

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

每个keep选项 后面都跟一个 class_specification 
注意:
· 只指定class时,那么类的成员还是可以被移除、优化、混淆
· 指定了类的某些成员时,那么除这些之外的其它的成员 还是可以被 移除、优化、混淆

Keep Option Modifiers : modifiers

 allowshrinking   启用压缩

压缩默认启用

如果 上一条keep 了(即不压缩),而下一条allowshrinking,则还是会压缩,即:会覆盖上面的配置
 allowoptimization启用优化

优化默认启用

会覆盖上面的配置
 allowobfuscation启用混淆

混淆默认启用

会覆盖上面的配置

例:

-keep public class com.stone.*Activity    保护任意com.stone包下的*Activity

-keep ,allowshrinking public class com.stone.*Activity  启用压缩    


Class Specifications  类规范

完整语法
[ @ annotationtype ] [[ ! ] public | final | abstract | @ ... ] [!] interface | class | enum classname [ extends | implements [ @ annotationtype ] classname ]
[{
    [
@ annotationtype ] [[!] public | private | protected | static | volatile | transient ... ] <fields> | (fieldtype fieldname);
    [
@ annotationtype ] [[!]public|private|protected|static| synchronized | native | abstract
           | strictfp  ...] <methods> | <init> (argumenttype,...) |classname(argumenttype,...) |(returntype methodname(argumenttype,...));
    [ @ annotationtype ] [[!] public | private | protected | static ... ] * ;                                                
    
...
}]
蓝色的java关键字
[ ] 表示里面的内容是可选的。  
@ 表示是一个注解类型  annotationtype的规范与classname类似
...
    [[!]public|final|abstract|@ ...] : ...表示可以写上前面选项中的任意一种或多种。不参与语法
    (argumenttype,...)  :... 参与语法,表示0个或多个任意参数类型
| 表示或
! 表示非 
()在表示方法时,才是语法的一部份;其它时候,只是用来分组
classname 需要使用完全限定类名(即含包名的类名)
    可以使用如下通配符匹配类名:
      ? 匹配一个任意字符
      *  匹配多个任意字符,不含package分隔符.
     ** 匹配多个任意字符,含package分隔符.

属性(fields)和方法(methods):
   它们的规范与java中的规范类似,只是方法中不需要写上参数名,有参数类型即可
   <init> matches any constructor.  
   <fields> matches any field.
   <methods> matches any method.
   * matches any field or method.   注意这四个通配符,本身不含 访问修饰符
   属性或方法后面都要以分号(;)结尾
   属性名或方法名可以使用的通配符:
       ?匹配任意一个字符
       *  匹配任意多个字符
   属性或方法类型(类型可以直接写,如果是一个class,则写上class的完全限定名)可以使用的通配符:
       %  表示任意基本数据类型,不含void
       ?   表示匹配用作类型的 class name的任意一个字符
       *    任意多个字符,不含package分隔符(.)
       **   任意多个字符,含package分隔符(.)    匹配非基本数据类型和非数组类型
             例:  ** get*()  可匹配com.stone.User getCurUser(),
               但不匹配String getName(),也不匹配com.stone.User[ ] getCurUser()。
       ***  匹配任意类型
       ...   表示任意数量的任意参数类型
  构造方法中的class name,可以用短类名或含包名的类名
 

 Optimizations : optimization_filter

当不使用-dontobfuscate选项时,则-optimizationsoptimization_filter才有效

optimization_filter 可以使用的通配符:

  ?任意一个字符 (没啥用)

  *  任意多个字符

可以用 ! 表示 非

For example, "code/simplification/variable,code/simplification/arithmetic" only performs the two specified peephole optimizations.

For example, "!method/propagation/*" performs all optimizations, except the ones that propagate values between methods.

For example, "!code/simplification/advanced,code/simplification/*" only performs all peephole optimizations.


optimization_filter 表示的有:

class/marking/final
Marks classes as final, whenever possible.

在任何可能的时候,将类标志为final class
class/merging/vertical
Merges classes vertically in the class hierarchy, whenever possible.

垂直合并类(上下层级的类 进行合并)
class/merging/horizontal
Merges classes horizontally in the class hierarchy, whenever possible.

水平合并类(同一层级的类 进行合并)
(⇒ code/removal/advanced)   表示当前选项是=>后的  前置选项

field/removal/writeonly
Removes write-only fields.

删除只写 属性
field/marking/private
Marks fields as private, whenever possible.

标记属性为private
(⇒ code/simplification/advanced)

field/propagation/value
Propagates the values of fields across methods.

在方法中传播属性值
method/marking/private
Marks methods as private, whenever possible (devirtualization).

标记属性为private(具体化)
(⇒ code/removal/advanced)

method/marking/static
Marks methods as static, whenever possible (devirtualization).

标记方法为static(具体化)
method/marking/final
Marks methods as final, whenever possible.

标记方法为final
(⇒ code/removal/advanced)

method/removal/parameter
Removes unused method parameters.

删除未使用的方法参数
(⇒ code/simplification/advanced)

method/propagation/parameter
Propagates the values of method parameters from method invocations to the invoked methods.

从方法的invocations传递方法参数值到 实际调用方法的地方invoked methods
(⇒ code/simplification/advanced)

method/propagation/returnvalue
Propagates the values of method return values from methods to their invocations.

传递方法的返回值 从方法到它们被调用的地方
method/inlining/short
Inlines short methods.

内联短方法
method/inlining/unique
Inlines methods that are only called once.

内联 仅被调用一次(或者说只被一个地方调用)的短方法
method/inlining/tailrecursion
Simplifies tail recursion calls, whenever possible.

简化尾递归 (尾递归转循环)
code/merging
Merges identical blocks of code by modifying branch targets.

合并相同的代码块
code/simplification/variable
Performs peephole optimizations for variable loading and storing.

变量加载和存储时 使用peephole optimization(窥孔优化)技术
code/simplification/arithmetic
Performs peephole optimizations for arithmetic instructions.

计算指令 用 窥孔优化
code/simplification/cast
Performs peephole optimizations for casting operations.

类型转换 用 窥孔优化
code/simplification/field
Performs peephole optimizations for field loading and storing.

属性加载和存储 用 窥孔优化
(⇒ code/removal/simple)

code/simplification/branch
Performs peephole optimizations for branch instructions.

分支指令 用 窥孔优化
code/simplification/string
Performs peephole optimizations for constant strings.

常量字符串 用 窥孔优化
(best used with code/removal/advanced)

code/simplification/advanced
Simplifies code based on control flow analysis and data flow analysis.

简化代码 基于控制流分析和数据流分析 
(⇒ code/removal/exception)

code/removal/advanced
Removes dead code based on control flow analysis and data flow analysis.

删除死代码 基于控制流分析和数据流分析
(⇒ code/removal/exception)

code/removal/simple
Removes dead code based on a simple control flow analysis.

删除死代码 基于一个简单的控制流分析
code/removal/variable
Removes unused variables from the local variable frame.

从本地变量框架中,删除 未使用的变量
code/removal/exception
Removes exceptions with empty try blocks.

当try-catch中,try块内为空时,删除exceptions
code/allocation/variable
Optimizes variable allocation on the local variable frame.

在本地变量框架中 优化变量分配

注意

· 上一句保护,下一句启用modifers, 启用无效; 上一句启用modifiers,下一句保护,保护有效。 重在保护

· 使用了-dontshrink|dontoptimize|dontobfuscate 这些全局选项后,那么再使用相应的kepp modifiers 无效

· 当不使用-dontoptimize选项时,则-optimizations optimization_filter才有效

· 测试发现jdk中就有优化不通过的地方,并且这个优化时间很长时间,还可能造成优化程序不结束(一直在运行,结束不了)

   所以一般还是直接使用 -dontoptimize。sdk中的proguard的配置文件也是这么写的。如果你想专业点,自行调试吧~


示例

-dontoptimize  #不优化
-dontpreverify #不预校验

#保持源文件和行号的信息,用于混淆后定位错误位置
-keepattributes SourceFile,LineNumberTable

-libraryjars class_path  #不处理 class_path指定的文件

-dontusemixedcaseclassnames  #不使用大小写混合类名
-dontskipnonpubliclibraryclasses #不跳过jars中的非public classes。在proguard4.5时,是默认选项
-verbose

-flattenpackagehierarchy com.stone.myapplication.interfaces # 将包里的类混淆成n个再重新打包到一个一个的package中
-repackageclasses com.stone.myapplication.interfaces #将包里的类混淆成n个再重新打包到一个统一的package中 会覆盖flattenpackagehierarchy选项

-keepattributes *Annotation* #保持含有Annotation字符串的 attributes
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

#保持 本化方法及其类声明
-keepclasseswithmembernames class * { 
    native <methods>;
}
#保持view的子类成员: getter setter
-keepclassmembers public class * extends android.view.View { 
   void set*(***);
   *** get*();
}
#保持Activity的子类成员:参数为一个View类型的方法   如setContentView(View v)
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
#保持枚举类的成员:values方法和valueOf  (每个enum 类都默认有这两个方法)
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
#保持Parcelable的实现类和它的成员:类型为android.os.Parcelable$Creator 名字任意的 属性
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
#保持 任意包名.R类的类成员属性。  即保护R文件中的属性名不变
-keepclassmembers class **.R$* {
    public static <fields>;
}
#不警告 support包
-dontwarn android.support.**

-keepattributes Signature   #保持签名
#下面三个gson相关
-keep class sun.misc.Unsafe {*;}
-keep class com.google.gson.examples.android.model.**{*;}
-keep class com.tv.kuaisou.bean.* {*;}

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider



后记:

  边翻译,边测试了三四天,头痛,有些什么打印、重命名及不怎么用的选项,实在翻译不下去了。

  有些官方上也没有看到示例,比如 外部的混淆字典...

  如有失误,请指正。


———————————————————————update  2017-06-30 ——————————————————————————

在使用AndroidStudio时遇到一些其它问题:

1. 当有多个library-module时,如果将混淆配置,放在它们每个之中,以为会像manifest一样,会进行合并,但是它并没有...

这就需要手动的在application-moudle中的build.gradle中加入其它混淆文件的的地址

buildTypes {
        debug {
            minifyEnabled false
        }

        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', "../submodule/proguard-rules.pro"
            signingConfig signingConfigs.release
        }
    }

2. 当不想混淆的jar文件,在其它module中时,一样的,也是要指定其具体的目录,即可

在混淆配置中,指定jar位置:<module-path>/libs/...jar

-libraryjars ../baiduPush/libs/pushservice-5.7.0.5.jar


猜你喜欢

转载自blog.csdn.net/jjwwmlp456/article/details/44977721