混淆代码能有效提高项目反编译难度,同时还可以适当减少apk的大小,在实际开发过程中尤为重要,经过长时间的摸索,对代码混淆有了一定的了解,下面写下个人心得:
1. 代码混淆的重要文件:proguard-rules.pro,如果你不小心删掉了,从其他地方复制一个或自己创建一个。
2. 开启混淆:
将build.gradle下的buildTypes->release->minifyEnabled设置为true,即可开启代码混淆
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
3. proguard-rules.pro文件中各项配置的含义
在配置之前先说明下一些含义
- -keep 保留目标不被混淆
- * 通配符,表示所有,扩展:set*表示以set开头,*onEvent* 表示含有onEvent关键字
- <init> 表示构造方法
- <methods> 类里面的方法
- <fields> 类里面的属性
- $ 分隔符,标识内部类
- -keepclasseswithmembers 保留类的成员
(配置项前加了#号表示注释)
-optimizationpasses 5 # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar(建议注释掉)
-dontpreverify # 混淆时是否做预校验
-verbose # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法
-keep public class * extends **** # 保持哪些类不被混淆
-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
native <methods>;
}
-keepclasseswithmembers class * { # 保持自定义控件类不被混淆
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int); # 保持自定义控件类不被混淆
}
-keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆
public void *(android.view.View);
}
-keepclassmembers enum * { # 保持枚举 enum 类不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
public static final android.os.Parcelable$Creator *;
}
#使用WebView时JavascriptInterface不被混淆,同时需要保证自定义的JS与原生交互的接口对象不被混淆
-keepattributes *JavascriptInterface*
#保证R文件不混淆
-keep public class [你的应用包名].R$*{ public static final int *;}
-keep class MyClass; # 保持自己定义的类不被混淆
4. 在proguard-rules.pro添加不需要混淆的代码的申明:
a.将你不需要混淆的部分申明进来,有些类经过混淆会导致程序编译不通过
-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
-keep public class * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService
以上都是android基本组件和依赖包
b. Model层(实体)的类建议不混淆
-keep class com.test.model.** { *; }
-keep class com.test.domain.** { *; } # 具体看实际项目包名和类
c.第三方的包都不建议混淆
第三方的library库一般都已经混淆过,因此不必再次混淆
#示例:百度地图SDK
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
#其他第三方lib混淆规则请参照它们的官方文档
总结来说就是用-keep加上你想要保留的东西。
下面介绍另一种快速配置混淆的方法,使用注解@Keep
1.在使用@Keep注解之前我们需要先导入(在AndroidX依赖已经内置,无需引入下列依赖)
compile 'com.android.support:support-annotations:{version}'
2.在proguard-rules.pro添加以下配置
-dontwarn android.support.annotation.Keep
#保留注解
-keepattributes *Annotation*
-keep @android.support.annotation.Keep class ** #保留@Keep注解的类以及它的属性方法不被混淆
3.在我们想要保留的东西上面使用@Keep注解
@Keep
public class Test {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在上面的代码中,我们设置保留了Test这个类,那么它在打包时就不会被混淆
如果我们只想保留它的属性或者方法,类名混淆掉,那该怎么办呢?如下
在proguard-rules.pro修改如下配置:
-keep @android.support.annotation.Keep class **{
@android.support.annotation.Keep <fields>; #保留类里面被@Keep注解的属性
@android.support.annotation.Keep <methods>; #保留类里面被@Keep注解的方法
}
然后在代码中
public class Test {
@Keep
private String name;
@Keep
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
上面代码中,保留了name这个属性和getName()这个方法不被混淆,类名Test和方法名setName()依然会被混淆。
好了,代码混淆总结差不多就这样了,希望对大家有帮助!