混淆
混淆包括四个功能,shrinker(压缩),optimizer(优化),obfuscator(混淆),preverifier(预校验,在android无效)。
压缩:检测并移除没有用到的类,变量,方法和属性;
优化:非入口节点类会加上private/static/final, 没有用到的参数会被删除,一些方法可能会变成内联代码;
混淆:依靠 ProGuard,将非入口类、类成员、方法重命名为无意义的简短名称,增加了逆向工程的难度;
预校验:预校验代码是否符合Java1.6或者更高的规范(唯一一个与入口类不相关的步骤)。
混淆规则
1.不应混淆的内容
- 出现在xml里内容不能混淆,如四大组件,自定义的Application类,自定义View等
- 第三方库所需的混淆规则。第三方库一般都会在接入文档中写好所需混淆规则,使用时注意添加
- 运用了反射的类不进行混淆
- 与 json 相互转换的实体类不混淆
- JNI中调用的类不进行混淆
- WebView中JavaScript调用的类和方法不混淆
- Layout布局使用的View构造函数、android:onClick等。
- 使用了枚举要保证枚举不被混淆
- 实现Parcelable 的类 和 其Creator 静态成员变量不混淆
- 实现Serializable 的类
2.混淆部分语法命令
- -keep 命令:keep 命令指的是一系列以 -keep 开头的命令,它主要用来保留不需要进行混淆的元素。如
# 保留继承自android.support.v4包下的所有类以及类成员
-keep public class * extends android.support.v4.**
# 保留类:PopupUtil
-keep public class com.hao.demo.push.PopupUtil{*;}
- -keepclassmembers 命令:保留指定的类的成员(变量/方法)。如
# 保留枚举类下的成员
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
- -keepclasseswithmembers 命令:保留指定的类和其成员(变量/方法),与 -keep命令相似 。如
# 保留native方法和其类
-keepclasseswithmembernames class * {
native <methods>;
}
- -keepattributes 命令:保留指定属性。如
# 保留异常和内部类
-keepattributes Exceptions,InnerClasses,...
# 保留泛型
-keepattributes Signature
其他命令根据英文本意大概可以看懂,参考网上搜索到的一些资料,得到如下常用的混淆规则:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:使用Webview加JS混淆时打开这个注释
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify
#指定压缩级别
-optimizationpasses 5
# 重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#不跳过非公共的库的类成员
-dontskipnonpubliclibraryclassmembers
#混淆时采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#把混淆类中的方法名也混淆了
-useuniqueclassmembernames
#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#保持泛型
-keepattributes Signature
# 不标记不警告support包
-dontnote android.support.**
-dontwarn android.support.**
# 保留support包下继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
#2.默认保留区(四大组件)
-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
-keep class android.support.** {*;}
# 保留native方法和其类
-keepclasseswithmembernames class * {
native <methods>;
}
#保留实现Parcelable的类
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持所有实现 Serializable 接口的类成员
-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();
}
#Fragment不需要在AndroidManifest.xml中注册,需要额外保护下
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
# 保持测试相关的代码
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
#保留annotation, 例如 @JavascriptInterface 等 annotation
-keepattributes Annotation
#保留跟 javascript相关的属性
-keepattributes JavascriptInterface
#保留JavascriptInterface中的方法
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
#保留枚举
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#保留R文件的静态成员
-keepclassmembers class **.R$* {
public static <fields>;
}
参考文档
https://www.jianshu.com/p/158aa484da13
https://www.jianshu.com/p/dbe98916a21c
https://mp.weixin.qq.com/s/Rr0atgupgoeHOEV3-20WqQ
https://juejin.im/post/5e23ed08f265da3e51531458