Android ProGuard混淆总结

目录
一、前言
二、ProGuard简介
三、ProGuard原理分析
四、ProGuard注意事项
五、Android中的混淆
Android开启混淆的设置
ProGuard基本命令
Android混淆方案实例

参考

一、前言

  • 编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。C、C++、Delphi、Pascal、Fortran

  • 解释型语言:不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。Java、Basic、javascript、python

java文件先编译成与平台无关的.class的字节码文件,然后.class文件在java虚拟机(JVM)上进行解释运行。由于跨平台的特性,Java字节码中包含许多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法。这些信息很容易被反编译成Java源代码,所以我们使用混淆器对Java字节码进行混淆。

使用混淆的原因:

  1. 混淆后的代码很难被反编译,即使被反编译了也很难看懂真正语义。
  2. 混淆后的代码保留原来的档案格式和指令集,执行结果与混淆前一样。

二、ProGuard简介

ProGuard是一个压缩、优化和混淆Java字节码文件的免费的工具,它可以删除无用的类、字段、方法和属性。可以删除没用的注释,最大限度地优化字节码文件。它还可以使用简短的无意义的名称来重命名已经存在的类、字段、方法和属性。常常用于Android开发用于混淆最终的项目,增加项目被反编译的难度。__来自百度百科

ProGuard的四个功能:

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

三、ProGuard原理分析

编译过程图来自ProGuard官网。Entry Point是在ProGuard过程中不会被处理的类或方法。在压缩的步骤中,ProGuard会从上述的Entry Point开始递归遍历,搜索哪些类和类的成员在使用,对于没有被使用的类和类的成员,就会在压缩段丢弃,在接下来的优化过程中,那些非Entry Point的类、方法都会被设置为private、static或final,不使用的参数会被移除,此外,有些方法会被标记为内联的,在混淆的步骤中,ProGuard会对非Entry Point的类和方法进行重命名。
编译过程图

四、ProGuard注意事项

不能混淆的情况:

  1. Java的反射:代码混淆,类名、方法名、属性名都改变了,而反射是按照原来的名字去反射,所以会反射错误。
  2. 注解:注解用了反射,所以不能混淆。
  3. native:不混淆任何包含native方法的类的类名以及native方法名,否则找不到本地方法。
  4. Activity:Activity不能混淆,因为AndroidManifest.xml文件中是完整的名字。
  5. 自定义view:自定义view也是带了包名写在xml布局中,不能混淆。

五、Android中的混淆

Android开启混淆的设置

app混淆的开启:

android{
	buildTypes {
	        release {
	            minifyEnabled true   //开启混淆
	            zipAlignEnabled true  //压缩优化
	            shrinkResources true  //移出无用资源
	            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
	            signingConfig signingConfigs.config
	            }
	        }
}

module混淆的开启(子模块是否混淆受app的build.gradle的控制;子模块混淆使用consumerProguardFiles关键字):

android{
	buildTypes {
	        release {
	            consumerProguardFiles 'proguard-rules.pro'
	            }
	        }
}

ProGuard基本命令

通配符      描述
<field>     匹配类中的所有字段
<method>    匹配类中所有的方法
<init>      匹配类中所有的构造函数
*           匹配任意长度字符,不包含包名分隔符(.)
**          匹配任意长度字符,包含包名分隔符(.)
***         匹配任意参数类型

系统配置:

  • dontusemixedcaseclassnames 混淆时不使用大小写混合类名
  • dontskipnonpubliclibraryclasses 不跳过library中的非public的类
  • verbose 打印混淆的详细信息
  • dontoptimize 不进行优化,建议使用此选项,
  • dontpreverify 不进行预校验,Android不需要,可加快混淆速度。
  • ignorewarnings 忽略警告
  • optimizationpasses 5 指定代码的压缩级别

保留选项:

  • keep{Modifier}{class_specification}: 保护指定的类文件(类名)和类成员, 防止被混淆或移除
  • keepclassmembers{Modifier}{class_specification}: 通过成员来指定来只保护指定类的某些成员, 防止被混淆或移除, 注意类名还是会被混淆
  • keepclasswithmembers{class_specification}: 通过成员来指定哪些类不被混淆处理。保持匹配到的类的类名和指定的方法不被混淆,其他未指定的方法仍然会被混淆
  • keepnames{class_specification}: 等于-keep,allowshrinking class_specification的别名,允许该类被压缩,未被使用的元素将会在压缩阶段被移除,此选项会保持对应的类名和指定的成员不被混淆(未指定的成员依然会被混淆)
  • keepclassmembernames{class_specification}: -keepclasseswithmembers,allowshrinking class_specification的别名,但是未使用的类和成员可能会在压缩阶段被移除
  • keepclasseswithmembernames {class_specification}: -keepclasseswithmembers,allowshrinking class_specification的别名,未使用的类和成员可能会在压缩阶段被移除

压缩:

  • dontshrink: 不压缩输入的类文件
  • printusage{filename}: 输出无用文件

优化:

  • dontoptimize: 不优化输入的类文件
  • assumenosideeffects{class_specification}: 在优化阶段移除相关方法的调用
  • allowaccessmodification: 优化时允许访问并修改有修饰符的类和类成员变量

混淆:

  • dontobfuscate不混淆输入的类文件
  • printmapping proguardMapping.txt : 输出映射表
  • applymapping{filename}:重用映射增加混淆。
  • obfuscationdictionary{filename}: 使用给的文件中的关键作为要混淆方法的名称。
  • overloadaggressively:混淆时应用侵入式重载。混淆的时候大量使用重载,多个方法名使用同一个混淆名(慎用)
  • useuniqueclassmembernames:确定统一的混淆类的成员名称来增加混淆。
  • renamesourcefileattribute{string}:设置源文件中给定的字符串常量。

预检:

  • dontpreverify

Android混淆方案实例

# 代码混淆压缩比,在0~7之间
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify
-verbose
# 避免混淆泛型
-keepattributes Signature

#保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
#google推荐算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# 避免混淆Annotation、内部类、泛型、匿名类
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod
# 重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
# 处理support包
-dontnote android.support.**
-dontwarn android.support.**
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# 保留R下面的资源
-keep class **.R$* {*;}
# 保留四大组件,自定义的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.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

# 保留枚举类不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 保留Parcelable序列化类不被混淆
-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();
}
#assume no side effects:删除android.util.Log输出的日志
-assumenosideeffects class android.util.Log {
    public static *** v(...);
    public static *** d(...);
    public static *** i(...);
    public static *** w(...);
    public static *** e(...);
}
#保留Keep注解的类名和方法
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
    @android.support.annotation.Keep *;
}
#3D 地图 V5.0.0之前:

-dontwarn com.amap.api.**
-dontwarn com.autonavi.**
-keep class com.amap.api.**{*;}
-keep class com.autonavi.**{*;}

-keep   class com.amap.api.maps.**{*;}
-keep   class com.autonavi.amap.mapcore.*{*;}
-keep   class com.amap.api.trace.**{*;}

#3D 地图 V5.0.0之后:
-keep   class com.amap.api.maps.**{*;}
-keep   class com.autonavi.**{*;}
-keep   class com.amap.api.trace.**{*;}

#定位
-keep class com.amap.api.location.**{*;}
-keep class com.amap.api.fence.**{*;}
-keep class com.autonavi.aps.amapapi.model.**{*;}

#搜索
-keep   class com.amap.api.services.**{*;}

#2D地图
-keep class com.amap.api.maps2d.**{*;}
-keep class com.amap.api.mapcore2d.**{*;}

#导航
-keep class com.amap.api.navi.**{*;}
-keep class com.autonavi.**{*;}
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform

#fastjson混淆
-keepattributes Signature
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.**{*;}
-keep class com.alibaba.fastjson.**{*; }
-keep public class com.ninstarscf.ld.model.entity.**{*;}

参考:

[https://www.jianshu.com/p/6408fbc3adca ](https://www.jianshu.com/p/6408fbc3adca ) [https://www.jianshu.com/p/e9d3c57ab92f](https://www.jianshu.com/p/e9d3c57ab92f)
发布了82 篇原创文章 · 获赞 86 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/carter_yu/article/details/103521086