Android Studio的Proguard(代码混淆)

时间:2022-07-18 04:38:56

混淆误区

  • 在android studio中AndroidMainifest.xml文件,对于主APP工程和lib工程来说,在生成apk的时候是会自动合并的,这给我造成一个误区让我以为主工程里面配置的混淆和lib工程配置的混淆在生成apk的时候也会自动合并,经过测试发现,混淆配置是不会合并的
  • 如果APP主工程中开启了混淆而lib工程的混淆配置没有开启,那么编译出来的apk,对于lib工程来说,包名,类的路径,类名都是没有混淆的,但是类里面的字段是有混淆的,也就是说lib工程有混淆,但是混淆的并不彻底,仅仅是类里面的字段进行了混淆,之所以这样的原因是,lib工程本身没有开启混淆,所以lib工程的proguard-rules.pro混淆配置并没有生效,而app主工程开启了混淆,所以app主工程的proguard-rules.pro混淆配置生效了,而且app主工程的混淆配置还对lib工程生效了,由于app主工程中的proguard-rules.pro并没有配置lib工程的混淆内容,所以lib工程代码就会被混淆了
  • 如果APP主工程没有开启混淆,而lib工程开启了混淆,那么编译出来的apk中的lib工程代码的部分是会成功混淆的,所以的成功混淆是指包名,类路径,类名等这些在lib工程的proguard-rules.pro文件中配置了的都会生效,该混淆的就混淆,配置了keep等不混淆的类就不进行混淆,换句话说就是lib工程开启了混淆之后,它自己的proguard-rules.pro文件配置就生效了,而且仅仅是对它本工程有效
  • 如果lib工程的混淆是关闭的,那么打包生成的aar包的代码也是不混淆的,如果lib工程的混淆是打开的,那么aar包的代码会被混淆
  • 综上所述:lib工程的混淆开启与否都只是针对它本省生效,并不会影响APP的混淆;而APP工程的混淆开启后,会影响到lib工程的代码

混淆配置

  • 涉及到java反射的不能混淆
  • 涉及到json转换的不能混淆,因为json转换用到了java反射
  • 注解不能混淆,因为注解也用到了java反射
  • 泛型不能混淆
  • 调用jni的类和路径不能混淆
  • 对于Android APP来说,四大组件和Application不能混淆,因为这些会被APP以外的代码调用到(Android framework)
  • java内部类的混淆需要注意,如果会被外部调用到,那么也不能混淆
  • 对于库来说,对外提供出来的接口不能混淆
  • 会被外部调用到的代码就不能混淆,但是需要有个粒度,假如一个类只有方法暴露给外部,那么就把public的method不混淆就行了,其他的private的method或者内部变量依然可以混淆;对于APP所谓的外部调用就APP中定义的四大组建等,而对于APP中用到的库所谓的外部调用就是APP调用的库提供出来的接口等
  • Android app代码混淆配置的基础配置:
-optimizationpasses 5 # 指定代码的压缩级别
-dontusemixedcaseclassnames # 是否使用大小写混合
-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 * extends android.support.v4.**
-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 *;
}
#过滤注解
-keepattributes *Annotation*
-keep class * extends java.lang.annotation.Annotation { *; }
-keep interface * extends java.lang.annotation.Annotation { *; }
#过滤泛型
-keepattributes Signature

以上只是基础配置,剩下的需要按需配置,例如第三方库的混淆配置,app中的混淆配置等

Android Studio中的混淆配置

buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// consumerProguardFiles 'proguard-rules.pro'
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

minifyEnabled为true就是开启混淆,反之;如果在APP主工程和lib工程中都做了混淆的配置,lib工程的混淆配置只对它自己有效,不会影响APP主工程,而APP主工程的混淆配置则会影响到lib工程的代码,会导致lib工程的代码中的内部变量或者方法混淆,而类名或者类路径不会被混淆,这样是会出问题的,解决这个问题有以下几种方法(要么两个工程的混淆交给其中一个统一控制,要么两个工程的混淆配置进行“merge”):
1. lib工程的混淆配置都放到app主工程的proguard-rules.pro中,这样相当于把lib工程的混淆作废了,完全交给app主工程去控制
2. 在app主工程的proguard-rules.pro文件中加入-include xxx,把lib工程的混淆配置文件导入进来即可,但前提是要把lib工程的配置文件拷贝到app工程目录下(这种都是老方法了)
3. 在app的build.gradle配置中配置,类似:proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’,‘proguard-lib-rules.pro’,但是proguard-lib-rules.pro要在app工程目录下(1,2,3这三种都是把lib工程的混淆交给app工程去控制了)
4. 在lib工程中加入consumerProguardFiles ‘proguard-rules.pro’,这个配置会在lib工程被打包的时候让lib工程中的proguard-rules.pro生效,此时lib工程就会按照它自己的proguard-rules.pro文件配置被正确混淆(这种相当一对多个工程的混淆配置文件进行merge),可参考如何生成带混淆的aar
5. 所以当项目发布的时候最正确和高效的配置:app主工程开启混淆,配置好app自己的混淆配置文件,lib工程同时也开启混淆,并配置自己的混淆配置文件,并且记得在lib工程里面加上consumerProguardFiles ‘proguard-rules.pro’,这样app和lib最终都能得到正确的混淆代码

疑惑

  • 我在进行如上混淆测试实践的时候有一个奇怪的问题,我拿项目工程,和自己新建的测试工程进行对比,这两个工程都引用了我们开发的一个lib工程,然后项目工程混淆开启,测试工程混淆开启,lib工程混淆关闭并加上consumerProguardFiles ‘proguard-rules.pro’,结果是:lib工程生成的aar是不混淆的(正确),项目工程生成的apk反编译出来查看里面关于lib工程的代码,类路径和类名没有被混淆,但是类里面的字段以及方法被混淆了,测试工程生成的apk反编译出里面lib的代码是被混淆的,也就是说项目工程和测试工程对于lib工程的混淆不一致