转自:https://blog.csdn.net/qq_30379689/article/details/81589428
启用混淆
通过工程下的build.gradle文件中的开启混淆开关和配置混淆规则文件
minifyEnabled:混淆开关
proguard-android.txt:SDK中默认proguard的配置规则
proguard-rules.pro:自定义proguard的配置规则
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
工作流程
Proguard的工作流程由Shrink、Optimize、Obfuscate、Preverify四个步骤组成,每个步骤都是可选的,我们可以通过配置脚本决定执行其中的哪几个步骤。这里引入一个EntryPoint概念,EntryPoint是在ProGuard过程中保存不会被处理的类或方法。在压缩过程中,Proguard从EntryPoint出发,递归检索,删除那些没有使用到的类和类的成员。在优化过程中,那些非EntryPoint的类和方法会被设置成private,static或final,没有使用到的参数会被移除,有些方法可能会被标记为内联的。在混淆过程中,会对非EntryPoint的类和类的成员进行重命名,也就是用其它无意义的名称代替。我们在配置文件中用-keep保留的部分属于EntryPoint,所以不会被重命名
1、压缩
压缩会移除未被使用的类和成员,并且会在优化动作执行之后再次执行
# 关闭压缩,默认打开
-dontshrink
2、优化
优化会在字节码级别上做优化,让应用运行的更快
# 关闭优化,默认打开
-dontoptimize
# 表示对代码优化的次数,一般为5
-optimizationpasses n
# 指定更精细级别的优化
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
3、混淆
混淆会将简短的无意义的名称,对类,字段和方法进行重命名
# 关闭混淆,默认打开
-dontobfuscate
4、预验证
预验证将对Java class进行预验证,Android中没有预验证过程
# 关闭预验证,默认关闭
-dontpreverify
混淆基础
1、类名
对类名进行keep操作只是将类名keep住,但方法和变量仍然会被混淆
# 一颗星表示keep当前本包下的类名,子包下的类名是会被混淆的
-keep class com.example.hensen.*
# 两颗星表示keep当前本包下的类名和子包下的类名
-keep class com.example.hensen.**
# 表示keep当前类名
-keep class com.example.hensen.net.NetWorkCache
# 表示keep当前类的内部类的类名
-keep class com.example.hensen.net.NetWorkCache$NetWorkBean
2、内容
对内容进行keep操作不仅可以将类名keep住,还可以对方法和变量keep住
# 一颗星表示keep当前本包下的类名、类的内容
-keep class com.example.hensen.*{*;}
# 两颗星表示keep当前本包下的类名、类的内容和子包下的类名、类的内容
-keep class com.example.hensen.**{*;}
# 表示keep当前类名、类的内容
-keep class com.example.hensen.net.NetWorkCache{*;}
# 表示keep当前类的内部类的类名、内部类的内容
-keep class com.example.hensen.net.NetWorkCache$NetWorkBean{*;}
3、特定内容
对特定的内容进行keep操作
-keep class com.example.hensen.net.NetWorkCache{
<init>;# 匹配所有构造器
<fields>;# 匹配所有变量
<methods>;# 匹配所有方法
public <methods>;# 匹配所有共有的方法
private <methods>;# 匹配所有私有的方法
public *;# 匹配所有共有的内容
private *;# 匹配所有私有的内容
public <init>(java.lang.String);# 匹配特定参数的构造函数
public void getCache(...);# 匹配任意长度类型参数的方法
}
4、类成员
对类名不需要keep,只需要对类下的方法进行keep操作
# 表示keep特定类下的特定参数的方法,但类名不会被keep
-keepclassmembernames class com.example.hensen.net.NetWorkCache{
public void getCache(java.lang.String);
}
5、类和类成员
作用范围 keep所指定类、成员 keep所指定类、成员(前提是在压缩阶段没有被删除)
类和类成员 -keep -keepnames
仅类成员 -keepclassmembers -keepclassmembernames
类和类成员(前提是成员都存在) -keepclasseswithmembers -keepclasseswithmembernames
应用场景
1、安卓底层组件和类名不可混淆
将底层的keep住,插件化才能准确的hook到底层组件
-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.ContentProvider
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.view.View
-keep public class * extends android.preference.Preference
2、jni方法不可混淆
native方法要完整的包名类名方法来定义,不可修改,否则找不到
-keepclasswithmembernames class *{
native <methods>;
}
3、反射用到的类名和方法不可混淆
反射要根据类名才能拿到反射的实体
-keep public class com.example.hensen.** {
public void set*(***);
public *** get*();
public *** is*();
}
1
2
3
4
5
4、自定义View不可混淆
只要是继承自系统组件,都要keep住
-keep public class * extend 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);
}
5、第三方框架不可混淆
将第三方框架当作为系统组件即可
-keep class android.support.** { *; }
-keep class android.support.v4.** { *; }
-keep class android.support.v7.** { *; }
-keep class * extends android.support.v4.**
-keep class * extends android.support.v7.**
-keep class * extends android.support.annotation.**
6、WebView和Js互调接口不可混淆
-keepclassmembers class ** {
@android.webkit.JavascriptInterface public *;
}
7、序列化的类不可混淆
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
<fields>;
<methods>;
}
-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();
}
8、enum类的特殊性
以下方法会被发射调用
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
public static ** valueOf(int);
}
9、其他场景
# 指定文件为映射文件,包括类和类成员的混淆名称,文件未提及的类和类成员将生成新的名称
-applymapping mapping.txt
# 指定一个文本文件,其中所有有效字词都用作混淆字段和方法名称
-obfuscationdictionary obfuscationdictionary.txt
# 指定一个文本文件,其中所有有效词都用作混淆类名
-classobfuscationdictionary obfuscationdictionary.txt
# 混淆时不生成大小写混合的类名
-dontusemixedcaseclassnames
# 不忽略指定jars中的非public calsses
-dontskipnonpubliclibraryclasses
# 不忽略指定类库的public类成员(变量和方法)
-dontskipnonpubliclibraryclassmembers
# 混淆过程中打印详细信息,如果异常终止则打印整个堆栈信息
-verbose
# 忽略警告继续处理
-ignorewarnings
# 不对指定的类、包中的不完整的引用发出警告
-dontwarn android.support.v4.**
-dontwarn All
# 避免混淆内部类、泛型、匿名类
-keepattributes InnerClasses,Signature,EnclosingMethod
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
# 保留注释成员变量,如Activity被@Override注释的方法onCreate、onDestroy方法
-keepattributes *Annotation*
# 资源类变量需要保留
-keep public class **.R$*{
public static final int *;
}