平时在build.gradle中看到
release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' }
其中minifyEnabled true是设置代码混淆,而下面那句话就是说明代码混淆所使用的属性的文件,在proguard-rules.pro中,这个文件在module目录下,
那什么是代码混淆?如果你的module是application的话,打包出来的是apk,如果你的module是android library的话,打包出来的是aar,如果别人反编译你的apk或者aar的时候,是可以看到你的源代码的,而设置了代码混淆,就可以让别人看不懂你的代码,举个例子,下面这张图是我反编译自己设置混淆的代码,左边那栏的a,b,c,d,e,f,g都不是原来的类名,右边的代码也都是abcd的字母,让人家难以看懂我的代码。
如果你有两个module,一个是app另一个是library,app依赖library,如果你设置library设置混淆的话,要注意几点:
1.要向app暴露app会调用library的代码,举个例子就是如果library中包含activity,而且这个activity要被app调用,那么要暴露这些activity,否则app调用时会说找不到该activity。
如果你还写了一些工具类的话,是需要暴露给app的话,都要暴露出来。
2.如果你的library中包含了一些libs/jar包的话,也需要暴露出来,否则会说找不到native method。
那么如何暴露呢
#暴露MyClass类,包括属性和方法 -keep class com.think.example.MyClass { *; } #暴露com.think.example.others包下所有的类,包括他们的属性和方法 -keep class com.think.example.others.** { *; } #在libs下面的jar包中的类,如果该包已经被混淆过,则不需要再次混淆,否则会出错。 -keep class com.example.mylibrary.** { *; } #暴露你自定义的view,这些自定义的view在layout.xml中会用到,如果你不暴露的话,也会报错 -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); }
google默认下
-optimizationpasses 5 # 指定代码的压缩级别 -dontusemixedcaseclassnames # 是否使用大小写混合 -dontskipnonpubliclibraryclasses # 是否混淆第三方jar -dontpreverify # 混淆时是否做预校验 -verbose # 混淆时是否记录日志 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法 -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 com.android.vending.licensing.ILicensingService # 保持哪些类不被混淆 -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 *; } -keep class MyClass; # 保持自己定义的类不被混淆
如果你的library中包含了一些本地的jar包,那么需要在混淆中加入
-dontoptmize
就是在混淆时不要优化,proguard内部如何混淆的机制还不是很清楚,只是知道他会对你的代码进行优化,缩短变量的名字等等,如果你的项目未包含-dontoptimize,且又有本地jar包的话,会导致其他app接入你library打出的aar包会出现错误。
aar被混淆了,再接入app后,如果app也想混淆的话,则需要在app的proguard-rule.pro中将aar中已经被混淆过的类keep在外,否则对同一代码(library)进行多次混淆(aar中混淆,app中混淆)会出错。
另外,在混淆的时候碰到过一个坑,待我细细讲来:
我有一个类
public class SDKConstants{
public static final String TAG="SDKConstants";
public static final int code = 1;
}
现在我想在混淆的时候不要混淆SDKConstants.TAG这个属性,也就是不要混淆SDKConstants这个类名,也不要混淆TAG这个属性。
原来我在proguard-rules.pro是这么写的
-keep class com.think.example.SDKConstants{
public static final String TAG;
public static final int code;
}
在build的时候不出错,但是在工程中引用混淆的aar包时,却发现这个tag属性被混淆了,这和我刚才的代码不符啊,但是code这个变量却没有被混淆,不科学啊。
后来我仔细一想,int是基本类型,但是String却不是,是对象类型,我就去网上查,看到人家的代码都是这么写的
看到了么,java.lang.String来指明类型,于是我修改了我混淆的代码,如下:
-keep class com.think.example.SDKConstants{
public static final java.lang.String TAG;
public static final int code;
}
卧槽槽,成功了,真是坑爹,要mark下,防止以后出错。
那么如何反编译别人的代码呢?请看这篇博客
Android反编译
下篇文章中会讲如何在混淆中再混淆 混淆中再混淆