0
点赞
收藏
分享

微信扫一扫

Android Studio如何做混淆


概述

ProGuard是一个Java类文件压缩器、优化器、混淆器、预校验器:

  • 压缩阶段会检测和移除未使用的类、字段、方法、属性。ProGuard以递归的方式检查并决定哪些类和类成员是被用到的,而其他没有用到的类和类成员就会被丢弃。
  • 优化阶段会分析并优化方法的字节码。ProGuard会进一步优化代码。其他优化包括不是入口点的类或方法可能会变成private、final、static,而没有使用的参数可能会被移除等。
  • 混淆阶段会用简短的无意义的名称来重命名剩下的类名、字段名、方法名。ProGuard会重命名那些不是入口点(说白了入口点就是公开的,public的)的类和类成员,会保留那些入口点(public的),保证他们能够正确地访问。

进行完以上三个段后,我们的apk包会更小、更高效,并且更难进行反向工程。

  • 预校验阶段会将预验证信息添加到类中,这是Java Micro Edition所必需的,或者可以缩短Java 6的启动时间。只有这一阶段不需要知道入口点的。
  • Android Studio如何做混淆_类名

ProGuard读取Jar包(或者是wars、ears、zips或者目录。然后开始压缩资源、优化代码、混淆代码和预校验它们。

前面这四个步骤都是可选的。

proguard-rules.pro文件配置

为了决定哪些代码要保留、哪些代码要丢弃或混淆,我们必须在配置文件中指明。proguard-rules.pro文件可以配置的选项:

  1. 输入输出选项

-include {filename} 
@filename '-include filename'
-basedirectory {directoryname}
-injars {class_path} jar,war,ear
-outjars {class_path} jar,war,ear使jar
-libraryjars {classpath} jar,war,earjars
-dontskipnonpubliclibraryclasses jarProGuard使ProGuard
-dontskipnonpubliclibraryclassmembers
-skipnonpubliclibraryclasses publicProGuardProGuardpublicpublicpublicpublic使使
-keepdirectories [directory_filter]jarsjar
-target version
-forceprocessing 使

  1. 压缩选项

-dontshrink -keep使使
-printusage {filename}
-whyareyoukeeping {class_specification}

  1. 保留选项

-keep {Modifier} {class_specification} 
-keepclassmembers {modifier} {class_specification}
-keepclasseswithmembers {class_specification}
-keepnames {class_specification} -keep,allowshrinking class_specificationSerializable
-keepclassmembernames {class_specification} -keepclassmembers,allowshrinking class_specification
-keepclasseswithmembernames {class_specification} -keepclasseswithmembers,allowshrinking class_specification
-printseeds {filename} -keep

  1. 优化选项

-dontoptimize 
-optimizationpasses n
-assumenosideeffects {class_specification} ProGuard使ProGuardProGuard
-allowaccessmodification 访
-mergeinterfacesaggressively

  1. 混淆选项

-dontobfuscate keep
-printmapping {filename}
-applymapping {filename} -printmapping
-obfuscationdictionary {filename} 使使'a', 'b'
-classobfuscationdictionary filename
-packageobfuscationdictionary filename
-overloadaggressively
-useuniqueclassmembernames
-flattenpackagehierarchy {package_name}
-repackageclass {package_name}
-repackageclasses [package_name]
-dontusemixedcaseclassnames
-keeppackagenames [package_filter]
-keepattributes {attribute_name,...} Exceptions, Signature, Deprecated, SourceFile, SourceDir, LineNumberTable, LocalVariableTable, LocalVariableTypeTable, Synthetic, EnclosingMethod, RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, and AnnotationDefaultInnerClasses
-keepparameternames
-renamesourcefileattribute {string}

  1. 预验证选项

-dontpreverify 
-microedition Java Micro Edition

  1. 通用选项

-verbose 
-dontnote [class_filter]
-dontwarn [class_filter]
-ignorewarnings
-printconfiguration [filename]
-dump [filename]

至此,Proguard.pro文件里可以的配置的东西都在上面有说明了,接下来我们看看如何用。

例子

压缩、优化、混淆的关闭

  • 压缩(Shrinking):默认开启

-dontshrink #关闭压缩

  • 优化(Optimization):默认开启

-dontoptimize  #关闭优化

  • 混淆(Obfuscation):默认开启

-dontobfuscate  #关闭混淆

星号通配符:*代表当前包下的类,**代表当前包及子包下的类

  • 保持某个类名不被混淆

-keep class com.wong.BaseDaoImpl

  • 一颗星表示只是保持该包下的类名,而子包下的类名还是会被混淆

-keep class com.wong.demo.*

  • 两颗星表示把本包和所含子包下的类名都保持;

-keep class com.wong.demo.**

注意:上面三种方式,类名虽然未混淆,但里面的类成员名称还是被混淆了

  • 保持某个类的类名及内部的所有内容不会混淆

-keep class com.wong.BaseDaoImpl{*;}

  • 既可以保持该包下的类名,又可以保持类里面的内容不被混淆;

-keep class com.wong.demo.*{*;}

  • 既可以保持该包及子包下的类名,又可以保持类里面的内容不被混淆;

-keep class com.wong.demo.**{*;}

  • 保持类中特定内容,而不是所有的内容可以使用如下:

-keep class com.wong.bean.MyBean{
<init>; #匹配所有构造器
<fields>;#匹配所有域
<methods>;#匹配所有方法
}

上面就保护了MyBean这个类中的所有的构造方法、变量、和方法不被混淆。
可以在<fields>或<methods>前面加上private 、public、native等来进一步指定不被混淆的内容,如:

-keep class com.wong.BaseDaoImpl{
public <methods>;#保护该类下所有的公有方法不被混淆
public *;#保护该类下所有的公有内容不被混淆
private <methods>;#保护该类下所有的私有方法不被混淆
private *;#保护该类下所有的私有内容不被混淆
public <init>(java.lang.String);#保护该类的有String类型参数的构造方法不被混淆
}

  • 要保护一个类的内部类不被混淆用 $ 符号,如保护BaseDaoImpl类的内部MyInnerClass不被混淆

-keep class com.wong.BaseDaoImpl$MyInnerClass{*;}

  • extends、implement:保护Android底层组件和类不要混淆

-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
-keep public class * extends android.view.View

  • 不需要保持类名,只需保持该类下的特定方法保持不被混淆,如保持MyProguardTest类下test(String)方法不被混淆

-keepclassmembernames class com.wong.MyProguardTest{
public void test(java.lang.String);
}

  • 保留类和类成员,类和类成员都不会被混淆

-keepclasseswithmembernames class com.wong.MyProguardTest1

重要注意事项

  • jni方法不可混淆,因为native方法是用完整的包名类名方法名来定义的,不能修改,否则找不到

-keepclasseswithmembernames class * {    
native <methods>;
}

  • AndroidMainfest中的类不混淆,所以四大组件和Application的子类和Framework层下所有的类默认不要进行混淆
  • 用GSON、FastJson等框架解析服务端数据时,所写的JSON对象类(实体类)不要混淆,否则无法将JSON解析成对应的对象。
  • 使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则
  • WebView的JS调用Android写的接口需要保证接口方法不混淆,否则js找不到对应的方法调用
  • 自定义的View默认也不会被混淆
  • 反射用到的类混淆时需要注意:只保持反射用到的类名和方法即可,否则也会找不到,并不需要将整个被反射到的类都进行保持
  • 使用enum时,不要混淆以下两个方法,它们会被反射调用到,如果混淆了,反射就会失效,找不到方法。

-keepclassmembers enum * {  
public static **[] values();
public static ** valueOf(java.lang.String);
}

  • Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;

-keep class * implements Android.os.Parcelable {            
public static final Android.os.Parcelable$Creator *;
}

Android Studio启用混淆

1、开启混淆
Android Studio自身集成Java语言的ProGuard作为压缩、优化、混淆的工具,配合Gradle构建工具使用。只需要在工程应用目录的gradle文件中设置minifyEnabled为true即可:

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

2、在proguard-rules.pro文件中加入混淆规则

# 代码混淆压缩比,在0~7之间,默认为5,一般不下需要修改
-optimizationpasses 5

# 混淆时不使用大小写混合,混淆后的类名为小写
# windows下的同学还是加入这个选项吧(windows大小写不敏感)
-dontusemixedcaseclassnames

# 指定不去忽略非公共的库的类
# 默认跳过,有些情况下编写的代码与类库中的类在同一个包下,并且持有包中内容的引用,此时就需要加入此条声明
-dontskipnonpubliclibraryclasses

# 指定不去忽略非公共的库的类的成员
-dontskipnonpubliclibraryclassmembers

# 不做预检验,preverify是proguard的四个步骤之一
# Android不需要preverify,去掉这一步可以加快混淆速度
-dontpreverify

# 有了verbose这句话,混淆后就会生成映射文件
# 包含有类名->混淆后类名的映射关系
# 然后使用printmapping指定映射文件的名称
-verbose
# 有了verbose这句话,混淆后就会生成映射文件
# 包含有类名->混淆后类名的映射关系
# 然后使用printmapping指定映射文件的名称
-verbose
#混淆前后的映射
-printmapping proguardMapping.txt
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt

# 指定混淆时采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不改变
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

# 保护代码中的Annotation不被混淆
# 这在JSON实体映射时非常重要
-keepattributes *Annotation*

# 避免混淆泛型
# 这在JSON实体映射时非常重要
-keepattributes Signature

# Gson specific classes
-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.gson.** { *;}

# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

# 保留所有的本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}

# 保留了继承自Activity、Application这些类的子类
# 因为这些子类有可能被外部调用
# 比如第一行就保证了所有Activity的子类不要被混淆
-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
-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.v4/v7包不混淆
-keep class android.support.** { *; }
-keep class android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.** { *; }
-keep public class * extends android.support.v7.**
-keep interface android.support.v7.app.** { *; }
-dontwarn android.support.** # 忽略警告

# 保留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 {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(***);
*** get* ();
}

# 保留Parcelable序列化的类不能被混淆
-keep class * implements android.os.Parcelable{
public static final android.os.Parcelable$Creator *;
}

# 不混淆实体类
-keep class com.jxty.app.garden.model.** { *; }

# 保留Serializable 序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}

# 对R文件下的所有类及其方法,都不能被混淆
-keepclassmembers class **.R$* {
*;
}

# 对于带有回调函数onXXEvent的,不能混淆
-keepclassmembers class * {
void *(**on*Event);
}

执行ProGuard后会生成的文件:

1)dump.txt 描述apk文件里的所以类的内部结构

2)mapping.txt 列出了原始的和混淆后的类、方法和属性的对应关系

3)seeds.txt 列出了没有被混淆的类和属性

4)usage.txt 列出了没有被打到apk文件中的代码

路径:项目目录/module名称/build/outputs/mapping/release

也可以直接在Android studio中查看:

Android Studio如何做混淆_android_02


谢谢阅读


举报

相关推荐

0 条评论