Android App 之ProGuard混淆

ProGuard原理


ProGuard能够对Java类中的代码进行压缩(Shrink),优化(Optimize),混淆(Obfuscate),预检(Preveirfy)。

  1. Shrink: 压缩,在这一步中,用于检测和删除无用的类,字段,方法和属性。
  2. Optimize: 优化,在这一步中,对字节码进行分析优化,并且移除无用指令。
  3. Obfuscate: 混淆,在这一步中,使用无意义的名称(a,b,c),对类、字段和方法进行重命名。
  4. 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为根据应用情况,自己配置的混淆文件。

混淆原则:

  1. 实体类、enum类型、使用GSON、fastjson等框架时,所写的JSON对象类不能进行混淆
  2. WEBView的JS调用也需要保证写的接口方法不混淆
  3. 反射用到的类不混淆
  4. JNI方法,本地方法不混淆
  5. 序列化的类不混淆,包括Parcelable和Serializable。序列化的时候会找不到对应的名字
  6. AndroidMainfest中的类不混淆,四大组件和Application的子类和Framework层下所有的类不进行混淆
  7. 第三方开源库或第三方sdk包,加官方提供的混淆方法
  8. 自定义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配置”

ProGuard文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容