ProGuard原理
ProGuard能够对Java类中的代码进行压缩(Shrink),优化(Optimize),混淆(Obfuscate),预检(Preveirfy)。
- Shrink: 压缩,在这一步中,用于检测和删除无用的类,字段,方法和属性。
- Optimize: 优化,在这一步中,对字节码进行分析优化,并且移除无用指令。
- Obfuscate: 混淆,在这一步中,使用无意义的名称(a,b,c),对类、字段和方法进行重命名。
- Preveirfy: 预检,在这一步中,主要是在Java平台上对处理后的代码进行预检。
引用ProGuard混淆
在应用的app module 下的build.gradle文件中进行如下配置:
buildTypes {
release {
//混淆
minifyEnabled true
//加载默认混淆配置文件
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
}
由上述配置可知引入了两个进行混淆的文件,proguard-android.txt与proguard-rules.pro。proguard-android.txt为官方推荐的默认混淆文件,proguard-rules.pro为根据应用情况,自己配置的混淆文件。
混淆原则:
- 实体类、enum类型、使用GSON、fastjson等框架时,所写的JSON对象类不能进行混淆
- WEBView的JS调用也需要保证写的接口方法不混淆
- 反射用到的类不混淆
- JNI方法,本地方法不混淆
- 序列化的类不混淆,包括Parcelable和Serializable。序列化的时候会找不到对应的名字
- AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类不进行混淆
- 第三方开源库或第三方sdk包,加官方提供的混淆方法
- 自定义view
官方混淆文件
混淆文件选择
proguard_android.txt 位置
a、当前工程名/build/intermediates/proguard-files
b、~/Library/Android/sdk/tools/proguard/
Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and will be ignored by new version of the Android plugin for Gradle。
到底哪一个proguard_android.txt 是有效的呢? 根据如上描述可知根据Gradle的Android plugin版本来区分,2.2版本之前时使用的sdk中的(上述b),2.2版本及其以后,使用的是当前Application工程下的(上述a)。
无论上述哪种情况,我们均可发现在文件夹中同时存在有proguard_android.txt 和proguard-android-optimize.txt 两种,一种是带optimize的,一种是不带optimize的,对比发现两种的区别就是 proguard-android-optimize.txt多了一下几项配置:
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification
-dontpreverify
并且有说明,如果不想优化,就使用proguard-android.txt (默认使用配置文件),如果想进行优化,就可以使用proguard-android-optimize.txt ,代码优化并不是只有配置proguard时进行优化,android本身生成dex文件是同样会进行优化。由于ProGuard优化并非在所有版本的Dalvik中能够正常工作,因此在ProGuard中进行优化会有一定风险。而上述的四项配置是至今为止能够解决由ProGuard优化产生的问题,但不保证能够解决所有由ProGuard优化产生的问题。因此官方文档提示如果使用proguard-android-optimize.txt 则必须保证在自己的应用中经过反复测试通过。因此默认的配置也就是使用proguard-android.txt。
官方配置文件详解(proguard-android.txt)
#混淆时不区分大小写,混淆后统一为小写
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# 不做优化(proguard过程之二)
-dontoptimize
# 不做预检(proguard过程之四)
-dontpreverify
# 保存反射可能需要的某些属性
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
# 不混淆如下三个谷歌服务类
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
-keep public class com.google.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
-dontnote com.google.vending.licensing.ILicensingService
-dontnote com.google.android.vending.licensing.ILicensingService
# native方法不被混淆(混淆原则之4)
-keepclasseswithmembernames class * {
native <methods>;
}
# 自定义view (混淆原则之9)
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# 保留在Activity中的方法参数是view的方法,这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# enum类型(混淆原则之1)
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 序列化类(混淆原则之5)
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
#保留R下面的资源
-keepclassmembers class **.R$* {
public static <fields>;
}
# WebView (混淆原则之2)
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# 排除support的警告
-dontnote android.support.**
-dontwarn android.support.**
# 保留keep注解
-keep class android.support.annotation.Keep
# 不混淆指定的类及其类成员
-keep @android.support.annotation.Keep class * {*;}
# 不混淆所有类及其类成员中的使用注解的方法
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
#不混淆所有类及其类成员中的使用注解的字段
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
# 不混淆所有类及其类成员中的使用注解的初始化方法
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
官方配置文件只进行了基础的部分配置,无法满足实际项目中所需要的所有配置,需要我们对其他个性配置在proguard-rules.pro进行配置。
个人配置混淆文件
常用第三方库混淆配置
如下为常用的第三方库混淆配置,每个配置后均配有官方地址,实际使用时,可根据具体的地址进行查询,便于随时更新混淆配置。
#ARouter路由混淆
#https://github.com/alibaba/ARouter
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
#Retrofit2 混淆
#http://square.github.io/retrofit/
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
#okhttp
#https://github.com/square/okhttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
#Gson
#https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.examples.android.model.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
#ButterKnife
#https://github.com/JakeWharton/butterknife/blob/master/butterknife/proguard-rules.txt
-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
-keep class butterknife.*
-keepclasseswithmembernames class * { @butterknife.* <methods>; }
-keepclasseswithmembernames class * { @butterknife.* <fields>; }
#百度地图
#http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
#umeng
#http://dev.umeng.com/analytics/android-doc/integration
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
#RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
如上第三方库,在实际项目使用的过程中随时添加与更新。
其他配置
如上仅为部分基础设置,其他还需要根据自己项目实际使用过程中进行配置,由于部分配置已经在proguard_android.txt中进行了配置,现提供个人项目中所引用的配置,目前暂未发现问题。
#apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
# 混淆时所采用的算法
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#保留我们使用的四大组件,自定义的Application等等这些类不被混淆# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-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
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; !private <fields>; !private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve();}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * { void *(**On*Event); void *(**On*Listener);}
# webView处理,项目中没有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, jav.lang.String);
}
注意
确保混淆不会对项目产生影响
建议从一开始就进行ProGuard混淆处理,并随时维护proguard-rules.pro文件,在debug模式下也进行ProGuard处理,这样就能够在我们的开发中进行处理ProGuard所造成的影响。
附
个人开源项目 “知趣” 及其“ProGuard配置”
网友评论