语法基础——Proguard语法基础

启用混淆

通过工程下的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*();
}

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 *;
}

猜你喜欢

转载自blog.csdn.net/qq_30379689/article/details/81589428
今日推荐