为什么要代码混淆?
Java 是一种跨平台的、解释型语言,Java 源码编译成中间”字节码”存储于 class 文件里。因为跨平台的须要,Java 字节码中包括了非常多源码信息,如变量名、方法名,而且通过这些名称来訪问变量和方法,这些符号带有很多语义信息,非常easy被反编译成 Java 源码。
为了防止这样的现象,我们能够使用 Java 混淆器对 Java 字节码进行混淆。混淆就是对公布出去的程序进行又一次组织和处理,使得处理后的代码与处理前代码完毕同样的功能,而混淆后的代码非常难被反编译,即使反编译成功也非常难得出程序的真正语义。
ProGuard
ProGuard 是一个免费的 Java 类文件的压缩,优化,混肴器。它删除没有用的类,字段,方法与属性。使字节码最大程度地优化,使用简短且无意义的名字来重命名类、字段和方法 。
压缩:检测以及删除没有用到的类字段属性
优化:分析以及优化方法的字节码
混淆:使用无意义的短变量,对类、方法等进行重命名
Android SDK自带了混淆工具Proguard,SDK的 ‘\sdk\tools\proguard’ 文件夹下。
项目中如果含有多个module时,在主app中设置了混淆其他module都会混淆。
在App module build.gradle中:
android {
...
buildTypes {
release {
minifyEnabled true // 开启代码混淆
zipAlignEnabled true // 开启Zip压缩优化
shrinkResources true // 移除未被使用的资源
//混淆文件列表,混淆规则配置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
...
}
取消混淆规则配置的三种类型
1 不能混淆的 2 第三方的jar包 3 混淆过程中肯定会有警告,有问题,根据提示解决问题,我遇到的问题就是有的jar包不能混淆,而我给混淆了,所以我加了第三部分的代码:
#压缩等级,一般选择中间级别5
-optimizationpasses 5
#包名不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
-dontoptimize
#预校验
-dontpreverify
#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
#保持下面的类不被混淆(没有用到的可以删除掉,比如没有用到service则可以把service行删除)
-keep public class * extends android.app.Fragment
-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.preference.Preference
-keep public class * extends android.support.v4.app.FragmentActivity
-keep public class * extends android.support.** { *;}
#如果引用了v4或者v7包
-dontwarn android.support.*
#忽略警告(开始应该注释掉,让他报错误解决,最后再打开,警告要尽量少)
-ignorewarnings
#####################记录生成的日志数据,gradle build时在本项目根目录输出################
#混淆时是否记录日志
-verbose
#apk 包内所有class 的内部结构
-dump class_files.txt
#为混淆的类和成员
-printseeds seeds.txt
#列粗从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
#####################记录生成的日志数据,gradle build时在本项目根目录输出结束################
#本地的R类不要被混淆,不然就找不到相应的资源
-keep class **.R$*{ public static final int *; }
#保持内部类,异常类
-keepattributes Exceptions, InnerClasses
#保持泛型、注解、源代码之类的不被混淆
-keepattributes Signature, Deprecated, SourceFile
-keepattributes LineNumberTable, *Annotation*, EnclosingMethod
#保持自定义控件不被混淆(没有就不需要)
-keepclasseswithmembers class * extends android.app.Activity{
public void *(android.view.View);
}
-keepclasseswithmembers class * extends android.supprot.v4.app.Fragment{
public void *(android.view.View);
}
#保持 Parcelable 不被混淆(没有就不需要)
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆(没有就不需要)
-keepnames class * implements java.io.Serializable
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# gson工具不需要混淆
-dontwarn com.google.gson**
-keep class com.google.gson.**{*;}
# volley
-dontwarn com.android.volley.jar.**
-keep class com.android.volley.**{*;}
#友盟混淆配置start
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
-keep public class com.hawk.android.hicamera.R$*{
*;
}
#友盟混淆配置end
#极光推送混淆配置
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-dontwarn com.tencent.**
-keep class com.tencent.**{*;}
# apache
-dontwarn org.apache.http.**
-keep class org.apache.http.** { *;}
Android Studio中自定义的混淆规则:
常见语法:
-include {filename} 从给定的文件里读取配置參数 -basedirectory {directoryname} 指定基础文件夹为以后相对的档案名称 -injars {class_path} 指定要处理的应用程序jar,war,ear和文件夹 -outjars {class_path} 指定处理完后要输出的jar,war,ear和文件夹的名称 -libraryjars {classpath} 指定要处理的应用程序jar,war,ear和文件夹所须要的程序库文件 -dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。 -dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。 保留选项 -keep {Modifier} {class_specification} 保护指定的类文件和类的成员 -keepclassmembers {modifier} {class_specification} 保护指定类的成员。假设此类受到保护他们会保护的更好 -keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是全部指定的类和类成员是要存在。 -keepnames {class_specification} 保护指定的类和类的成员的名称(假设他们不会压缩步骤中删除) -keepclassmembernames {class_specification} 保护指定的类的成员的名称(假设他们不会压缩步骤中删除) -keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,假设全部指定的类成员出席(在压缩步骤之后) -printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件 -keep public class * extends com.example.test.BaseActivity 保持继承了的BaseActivity 的public修饰类名不被混淆 压缩 -dontshrink 不压缩输入的类文件 -printusage {filename} -dontwarn 假设有警告也不终止 -whyareyoukeeping {class_specification} 优化 -dontoptimize 不优化输入的类文件 -assumenosideeffects {class_specification} 优化时假设指定的方法。没有不论什么副作用 -allowaccessmodification 优化时同意訪问并改动有修饰符的类和类的成员 混淆 -dontobfuscate 不混淆输入的类文件 -printmapping {filename} -applymapping {filename} 重用映射添加混淆 -obfuscationdictionary {filename} 使用给定文件里的keyword作为要混淆方法的名称 -overloadaggressively 混淆时应用侵入式重载 -useuniqueclassmembernames 确定统一的混淆类的成员名称来添加混淆 -flattenpackagehierarchy {package_name} 又一次包装全部重命名的包并放在给定的单一包中 -repackageclass {package_name} 又一次包装全部重命名的类文件里放在给定的单一包中 -dontusemixedcaseclassnames 混淆时不会产生形形色色的类名 -keepattributes {attribute_name,...} 保护给定的可选属性,比如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses. -renamesourcefileattribute {string} 设置源文件里给定的字符串常量
<init> # 匹配所有构造函数
<fields> # 匹配所有成员变量
<methods> # 匹配所有的方法
可以在它们前面添加 private ,public 进行进一步更精细的限制范围,比如保持 User 类中 所有 public 方法不被混淆:
-keep class com.xing.weijian.bean.User {
public <methods>;
}
也可以在方法中加入参数进行限定:比如 保持 User 类的 public 修饰,参数是 String 类型的方法不被混淆:
-keep class com.xing.weijian.bean.User {
public <methods>(String);
}
内部类使用 $ 号,保持 TabFragment 中 内部类 OnFragmentData的所有 public 修饰的都不被混淆掉
-keepclassmembers class com.xing.weijian.TabFragment$OnFragmentData{
public *;
}
jni 方法不能混淆,因为这个方法需要和 native 方法保持一致
-keepclasseswithmembernames class * { # 保持native方法不被混淆
native <methods>;
}
不混淆某个类
-keep public class com.android.proguard.example.Test { *; }
不混淆某个包所有的类
-keep class com.android.proguard.example.** { *; }
不混淆某个类的子类
-keep public class * extends com.android.proguard.example.Test { *; }
不混淆所有类名中包含了“model”的类及其成员
-keep public class **.*model*.** {*;}
不混淆某个接口的实现
-keep class * implements com.android.proguard.example.TestInterface { *; }
不混淆某个类的构造方法
-keepclassmembers class com.android.proguard.example.Test {
public <init>();
}
不混淆某个类的特定的方法
-keepclassmembers class com.android.proguard.example.Test {
public void test(java.lang.String);
}
不混淆某个类的内部类
-keep class com.android.proguard.example.Test$* {
*;
}
keep 与 keepclassmembers , keepclasseswithmembers在这里插入图片描述
-ignorewarning # 是否忽略警告
-optimizationpasses 5 # 指定代码的压缩级别(在0~7之间,默认为5)
-dontusemixedcaseclassnames # 是否使用大小写混合(windows大小写不敏感,建议加入)
-dontskipnonpubliclibraryclasses # 是否混淆非公共的库的类
-dontskipnonpubliclibraryclassmembers # 是否混淆非公共的库的类的成员
-dontpreverify # 混淆时是否做预校验(Android不需要预校验,去掉可以加快混淆速度)
-verbose # 混淆时是否记录日志(混淆后会生成映射文件)
#指定外部模糊字典
-obfuscationdictionary dictionary1.txt
#指定class模糊字典
-classobfuscationdictionary dictionary1.txt
#指定package模糊字典
-packageobfuscationdictionary dictionary2.txt
#混淆时所采用的算法(谷歌推荐算法)
-optimizations !code/simplification/arithmetic,!field,!class/merging,!code/allocation/variable
#添加支持的jar(引入libs下的所有jar包)
-libraryjars libs(*.jar;)
#将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile
#保持注解不被混淆
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation {*;}
#保持泛型不被混淆
-keepattributes Signature
#保持反射不被混淆
-keepattributes EnclosingMethod
#保持异常不被混淆
-keepattributes Exceptions
#保持内部类不被混淆
-keepattributes Exceptions,InnerClasses
#抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#------------------------------------默认保留区--------------------------------------#
#保持基本组件不被混淆
-keep public class * extends android.app.Fragment
-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
#保持 Google 原生服务需要的类不被混淆
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#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.**
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保留自定义控件(继承自View)不被混淆
-keep public class * extends 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);
}
#保留指定格式的构造方法不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#保留在Activity中的方法参数是view的方法(避免布局文件里面onClick被影响)
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
#保持枚举 enum 类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保持R(资源)下的所有类及其方法不能被混淆
-keep class **.R$* { *; }
#保持 Parcelable 序列化的类不被混淆(注:aidl文件不能去混淆)
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepnames class * implements java.io.Serializable
#持 Serializable 序列化的类成员不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持 BaseAdapter 类不被混淆
-keep public class * extends android.widget.BaseAdapter { *; }
#保持 CusorAdapter 类不被混淆
-keep public class * extends android.widget.CusorAdapter{ *; }
#-------------------------------------webView区---------------------------------------#
#WebView处理,项目中没有使用到webView忽略即可
#保持Android与JavaScript进行交互的类不被混淆
-keep class **.AndroidJavaScript { *; }
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);
public boolean *(android.webkit.WebView,java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void *(android.webkit.WebView,java.lang.String);
}
#网络请求相关
-keep public class android.net.http.SslError
#-------------------------------------删除代码区--------------------------------------#
删除代码中Log相关的代码
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}