https://www.cnblogs.com/CharlesGrant/p/7544311.html
代码混淆
一般情况下,Android 的 gradle 中都会默认写着:
1 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
默认 Proguard 文件:官方自带的混淆规则文件路径:proguard-android.txt。
这个默认文件中帮我们声明了许多混淆规则内容,包括:keep 所有继承自 View 的类,keep 所有继承自 Activity 的类,keep 所有 JavascriptInterface、native 方法声明,以及 keep 一些注解了 @Keep 的内容。
所以默认情况下,即使一条规则都没有加入,自定义 View 和 Activity 都被保留下来,至少类名都没有被混淆。
那么为什么官方默认会帮我们写下这些?为什么 View 和 Activity 默认情况下应该被保留呢?
简单来说,因为 Proguard 原本是为 Java 打造的,它无法搜索到我们 AndroidManifest、布局等文件中引用了哪些 Java 类,因此如果 Java 代码变了而 XML 文件中的引用没变,就会造成反射失败。所以这些被 XML 使用到的类需要 keep 住。
(1)对于View 和 Activity混淆问题:
饿了么 的团队提供了一个鲜为人知的 gradle 插件 用来无伤混淆 Activity 和 View,这个项目叫 Mess:https://github.com/eleme/Mess
具体内容各位可以稍后自行去阅读其文档和教程,链接最后都还会附于末尾。简单来说,Mess 弥补了 Proguard 不能检索 XML 文件的缺点,帮 Proguard 完成了 Activity 和 View 的改名及 mapping。
(2)资源文件的混淆问题:
Proguard 完全不会管我们的资源文件,因此如果资源文件名没有做保护的话,很容易被顺藤摸瓜找到关联的 Java 代码,对此,微信团队提供了一个好用的资源混淆工具,它不仅能帮你全面混淆资源文件,还能帮你缩减资源文件的整体体积,工具叫 AndResGuard,开源地址:https://github.com/shwenzhang/AndResGuard
开启混淆:
![复制代码](https://img-blog.csdnimg.cn/img_convert/901fcd2cd35d7219cfb89d9e0e8287ca.gif)
1 release {
2 debuggable false
3 //对齐
4 zipAlignEnabled true
5 //移除无用的resource 文件
6 shrinkResources true
7 // 混淆
8 minifyEnabled true
9 signingConfig signingConfigs.release
10 proguardFile getDefaultProguardFile('proguard-android.txt')
11 proguardFile 'proguard-rules.pro'
12 }
![复制代码](https://img-blog.csdnimg.cn/img_convert/5627ab4730cdb0862164fd3782f3c5ea.gif)
(3)Proguard rules
-repackageclasses
-repackageclasses + 包名 这种做法存在混淆 bug,而默认 -repackageclasses 不加包名不会出现 bug,所以初次使用此法需要进行测试。
-obfuscationdictionary
-obfuscationdictionary 后面加一个纯文本文件路径,它的作用是指定一个字典文件作为混淆字典。默认情况下我们的代码命名会被混淆成 abcdefg... 字母组合的内容,需要修改可以使用这个配置项将字典修改成更加可怕的内容,乱花渐欲迷人眼的效果。
Android 混淆字典文件
-assumenosideeffects
在 release 混淆过程中删除 Log 代码,使用 -assumenosideeffects 这个配置项可以帮我们在编译成 APK 之前把日志代码全部删掉,这么做有助于提升性能,而且日志代码往往会保留很多我们的意图和许多可被反编译的字符串:
![复制代码](https://img-blog.csdnimg.cn/img_convert/1fc317780ca3dc1152e69bfad21c2b47.gif)
1 -assumenosideeffects class android.util.Log {
2 public static boolean isLoggable(java.lang.String, int);
3 public static int d(...);
4 public static int w(...);
5 public static int v(...);
6 public static int i(...);
7 }
![复制代码](https://img-blog.csdnimg.cn/img_convert/7f13e857c21fba2def7ca8ca6b772a32.gif)
注:assumenosideeffects 需要启用代码优化才能生效
Proguard File:
![复制代码](https://img-blog.csdnimg.cn/img_convert/65f55d4f23e912f9555ed20a316d598f.gif)
1 # 代码混淆压缩比,在0~7之间,默认为5,一般不下需要修改
2 -optimizationpasses 5
3
4 # 混淆时不使用大小写混合,混淆后的类名为小写
5 # windows下的同学还是加入这个选项吧(windows大小写不敏感)
6 -dontusemixedcaseclassnames
7
8 # 指定不去忽略非公共的库的类
9 # 默认跳过,有些情况下编写的代码与类库中的类在同一个包下,并且持有包中内容的引用,此时就需要加入此条声明
10 -dontskipnonpubliclibraryclasses
11
12 # 指定不去忽略非公共的库的类的成员
13 -dontskipnonpubliclibraryclassmembers
14
15 # 不做预检验,preverify是proguard的四个步骤之一
16 # Android不需要preverify,去掉这一步可以加快混淆速度
17 -dontpreverify
18
19 # 有了verbose这句话,混淆后就会生成映射文件
20 # 包含有类名->混淆后类名的映射关系
21 # 然后使用printmapping指定映射文件的名称
22 -verbose
23 -printmapping priguardMapping.txt
24
25 # 指定混淆时采用的算法,后面的参数是一个过滤器
26 # 这个过滤器是谷歌推荐的算法,一般不改变
27 -optimizations !code/simplification/artithmetic,!field/*,!class/merging/*
28
29 # 保护代码中的Annotation不被混淆
30 # 这在JSON实体映射时非常重要,比如fastJson
31 -keepattributes *Annotation*
32
33 # 避免混淆泛型
34 # 这在JSON实体映射时非常重要,比如fastJson
35 -keepattributes Signature
36
37 # 抛出异常时保留代码行号
38 -keepattributes SourceFile,LineNumberTable
![复制代码](https://img-blog.csdnimg.cn/img_convert/b430589ffc20dfd0944394615e6f56f4.gif)
要Keep的:
![复制代码](https://img-blog.csdnimg.cn/img_convert/5dc78dff4f0999f6e0f9e8a4248a25de.gif)
1 # 保留所有的本地native方法不被混淆
2 -keepclasseswithmembernames class * {
3 native ;
4 }
5
6 # 保留了继承自Activity、Application这些类的子类
7 # 因为这些子类有可能被外部调用
8 # 比如第一行就保证了所有Activity的子类不要被混淆
9 -keep public class * extends android.app.Activity
10 -keep public class * extends android.app.Application
11 -keep public class * extends android.app.Service
12 -keep public class * extends android.content.BroadcastReceiver
13 -keep public class * extends android.content.ContentProvider
14 -keep public class * extends android.app.backup.BackupAgentHelper
15 -keep public class * extends android.preference.Preference
16 -keep public class * extends android.view.View
17 -keep public class com.android.vending.licensing.ILicensingService
18
19 # 如果有引用android-support-v4.jar包,可以添加下面这行
20 -keep public class com.null.test.ui.fragment.** {*;}
21
22 # 保留Activity中的方法参数是view的方法,
23 # 从而我们在layout里面编写onClick就不会影响
24 -keepclassmembers class * extends android.app.Activity {
25 public void * (android.view.View);
26 }
27
28 # 枚举类不能被混淆
29 -keepclassmembers enum * {
30 public static **[] values();
31 public static ** valueOf(java.lang.String);
32 }
33
34 # 保留自定义控件(继承自View)不能被混淆
35 -keep public class * extends android.view.View {
36 public (android.content.Context);
37 public (android.content.Context, android.util.AttributeSet);
38 public (android.content.Context, android.util.AttributeSet, int);
39 public void set*(***);
40 *** get* ();
41 }
42
43 # 保留Parcelable序列化的类不能被混淆
44 -keep class * implements android.os.Parcelable{
45 public static final android.os.Parcelable$Creator *;
46 }
47
48 # 保留Serializable 序列化的类不被混淆
49 -keepclassmembers class * implements java.io.Serializable {
50 static final long serialVersionUID;
51 private static final java.io.ObjectStreamField[] serialPersistentFields;
52 !static !transient ;
53 private void writeObject(java.io.ObjectOutputStream);
54 private void readObject(java.io.ObjectInputStream);
55 java.lang.Object writeReplace();
56 java.lang.Object readResolve();
57 }
58
59 # 对R文件下的所有类及其方法,都不能被混淆
60 -keepclassmembers class **.R$* {
61 *;
62 }
63
64 # 对于带有回调函数onXXEvent的,不能混淆
65 -keepclassmembers class * {
66 void *(**On*Event);
67 }
![复制代码](https://img-blog.csdnimg.cn/img_convert/65abb080ddf676617e4dd84bd7b23f5b.gif)
针对App的量身定制
1.保留实体类和成员不被混淆 对于实体,要保留它们的get和set方法,对于boolean型get方法有的命名是isXXX类型,不要遗漏
![复制代码](https://img-blog.csdnimg.cn/img_convert/f82d1db053017b26349b8f62a448c40e.gif)
1 -keep class com.null.test.entities.** {
2 //全部忽略
3 *;
4 }
5 -keep class com.null.test.entities.** {
6 //忽略get和set方法
7 public void set*(***);
8 public *** get*();
9 public *** is*();
10 }
11 //以上两种任意一种都行
![复制代码](https://img-blog.csdnimg.cn/img_convert/b19acd5ab93136cc889ffe3ec7c213be.gif)
2.内嵌类 内嵌类经常容易被混淆,结果调用的时候为空就崩溃了。最好的办法就是不用内嵌类(有点扯淡),如果MainActivity中使用了,就用如下代码
1 -keep class com.null.test.MainActivity$* {
2 *;
3 }
注:$这个符号就是用来分割内嵌类与其母体的标志
3.对于自定义类库的混淆处理 对于自定义的类库,我们一般是保留类和类的成员。
4.对WebView的处理 如果项目中用到了WebView的复杂操作,请加入以下代码:
![复制代码](https://img-blog.csdnimg.cn/img_convert/5627ab4730cdb0862164fd3782f3c5ea.gif)
1 -keepclassmembers class * extends android.webkit.WebViewClient {
2 public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
3 public boolean *(android.webkit.WebView, java.lang.String);
4 }
5 -keepclassmembers class * extends android.webkit.WebViewClient {
6 public void *(android.webkit.WebView, java.lang.String);
7 }
![复制代码](https://img-blog.csdnimg.cn/img_convert/332dc67a05ef1b66829a0c981c2bf88b.gif)
5.对JavaScript的处理
1 -keepclassmembers class com.null.test.MainActivity$JSInterfacel {
2 ;
3 }
|