目录
概念:
简单的来说就是将源代码变成难以看懂的,如果不想app上架之后被人反编译拿到源代码直接CV的话建议看一看,哈哈
- 好处:
增加反编译只会源代码的阅读难度
自动优化代码 用以减小应用体积,移除未被使用的类和成员
在字节码级别执行优化,让应用运行的更快。
废话不多说,对比两张图片比较一下:
混淆之前:
混淆之后 :
从这两张图的对比很容易发现,这里的很多包名以及类名都被混淆了,还有代码的优化
使用:
在Android主工程build.gradle添加代码
android{
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
这样就可以了,是不是很简单呢
minifyEnabled 就是混淆的开关
在对应的模块当中会有proguard-rules.pro文件,如果需要自己定制混淆规则,可以在这个文件当中去更改
基本的混淆规则:
偷懒扔个链接:
常用的混淆规则:
懒人可以直接CV大法到项目当中使用
# This is a configuration file for ProGuard. # http://proguard.sourceforge.net/index.html#manual/usage.html # # Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with # the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and # will be ignored by new version of the Android plugin for Gradle. # Optimizations can be turned on and off in the 'postProcessing' DSL block. # The configuration below is applied if optimizations are enabled. # Adding optimization introduces certain risks, since for example not all optimizations performed by # ProGuard works on all versions of Dalvik. The following flags turn off various optimizations # known to have issues, but the list may not be complete or up to date. (The "arithmetic" # optimization can be used if you are only targeting Android 2.0 or later.) Make sure you test # thoroughly if you go this route. # --------------------------------------------基本指令区-------------------------------------------# 指定代码的压缩级别(在0~7之间,默认为5) -optimizationpasses 5 # 是否使用大小写混合(windows大小写不敏感,建议加入) -dontusemixedcaseclassnames # 是否混淆非公共的库的类 -dontskipnonpubliclibraryclasses # 是否混淆非公共的库的类的成员 -dontskipnonpubliclibraryclassmembers # 混淆时是否做预校验(Android不需要预校验,去掉可以加快混淆速度) # 混淆时是否记录日志(混淆后会生成映射文件) -verbose # 混淆时所采用的算法(谷歌推荐算法) -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable -useuniqueclassmembernames -allowaccessmodification # 将文件来源重命名为“SourceFile”字符串 -renamesourcefileattribute SBFile # 保持注解不被混淆 -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 # 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 { *; } # --------------------------------------------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 ################retrofit############### -dontwarn retrofit2.** -keep class retrofit2.** { *; } -keepattributes Signature -keepattributes Exceptions ################butterknife############### -keep class butterknife.** { *; } -dontwarn butterknife.internal.** -keep class **$$ViewBinder { *; } -keepclasseswithmembernames class * { @butterknife.* <fields>; } -keepclasseswithmembernames class * { @butterknife.* <methods>; } ################gson############### -keepattributes Signature -keepattributes *Annotation* -keep class com.google.gson.stream.** { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.sunloto.shandong.bean.** { *; } ################okhttp############### -keepattributes Signature -keepattributes *Annotation* -keep class com.squareup.okhttp.** { *; } -keep interface com.squareup.okhttp.** { *; } -keep class okhttp3.** { *; } -keep interface okhttp3.** { *; } -dontwarn com.squareup.okhttp.** -keep class com.facebook.** { *; } ################autolayout############### -keep class com.zhy.autolayout.** { *; } -keep interface com.zhy.autolayout.** { *; } ################RxJava and RxAndroid############### -dontwarn org.mockito.** -dontwarn org.junit.** -dontwarn org.robolectric.** -keep class io.reactivex.** { *; } -keep interface io.reactivex.** { *; } -keepattributes Signature -keepattributes *Annotation* -keep class com.squareup.okhttp.** { *; } -dontwarn okio.** -keep interface com.squareup.okhttp.** { *; } -dontwarn com.squareup.okhttp.** -dontwarn io.reactivex.** -dontwarn retrofit.** -keep class retrofit.** { *; } -keepclasseswithmembers class * { @retrofit.http.* <methods>; } -dontwarn java.lang.invoke.* -keepclassmembers class io.reactivex.internal.util.unsafe.*ArrayQueue*Field* { long producerIndex; long consumerIndex; }
自定义混淆规则:
从最开始的两张图片可以看到混淆后的名字都是a,b,c之类的,但是如果想自定义这么处理,这个也很简单需要在proguard-rules.pro文件当中加入
#指定外部模糊字典 -obfuscationdictionary filename.txt #指定class模糊字典 -classobfuscationdictionary filename.txt #指定package模糊字典 -packageobfuscationdictionary filename.txt
filename.txt文件我放在了demo当中,位置在..app/filename.txt,直接copy下来就可以,
当然如果想要自己控制filename.txt内容请按照以下步骤:
- 下载demo
- 将proguardcreater包拷贝到自己的工程,或者再接在demo当中运行Main类当中的main方法(记得自己更改规则)(ps:可以是中文哈哈哈,玩一玩就好,因为打印出来的日志无法通过mapping去查看)
- 将生成好的文件拷贝到自己的项目当中即可
通过自定义混淆字典生成的apk目录:
可以看到已经变成了我自己定义的规则,由0,o,O组成的包名,当然类名和方法是一样的
混淆四大组件:
有点小基础的都应该知道,一般情况下是不允许混淆四大组件的,会导致程序找不到组件报错,但是这里的混淆四大组件是通过增量混淆来实现的,无意间逛GitHub的时候发现一个大佬写的开源项目,由此记录一下。
GitHub地址:点我 GGG~~
注意事项:
有些类是不能被混淆的,特此记录:
- 使用了自定义View要保证不能被混淆
- 使用了枚举要保证枚举不被混淆
- 对第三方库中的类不进行混淆
- 运用了反射的类也不进行混淆
- 使用了 Gson 之类的工具要使 JavaBean 类即实体类不被混淆
- 在引用第三方库的时候,一般会标明库的混淆规则的,建议在使用的时候就把混淆规则添加上去,免得到最后才去找
- 有用到 WebView 的 JS 调用也需要保证写的接口方法不混淆,原因和第一条一样
- Parcelable 的子类和 Creator 静态成员变量不混淆,否则会产生 Android.os.BadParcelableException 异常
- 使用的四大组件,自定义的Application* 实体类
- JNI中调用的类
- Layout布局使用的View构造函数(自定义控件)、android:onClick等。
Demo地址: