混淆
1.簡(jiǎn)單介紹
代碼混淆(Obfuscated code)亦稱花指令模捂,是將計(jì)算機(jī)程序的代碼捶朵,轉(zhuǎn)換成一種功能上等價(jià),但是難于閱讀和理解的形式的行為狂男。
目的增加反編譯的難度
2.集成過(guò)程
2.1 代碼集成
Android Studio本身集成了ProGuard混淆工具综看,我們可以通過(guò)編輯app->build.gradle文件來(lái)開(kāi)啟混淆并且對(duì)代碼進(jìn)行壓縮,對(duì)資源進(jìn)行優(yōu)化等并淋。如下圖
buildTypes {
debug {
minifyEnabled true //是否進(jìn)行混淆
zipAlignEnabled true // 是否支持zip 壓縮優(yōu)化
shrinkResources true // 移除無(wú)用資源
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
添加一個(gè)模版
#
#-------------------------------------------基本不用動(dòng)區(qū)域----------------------------------------------
#
#
# -----------------------------基本 -----------------------------
#
# 指定代碼的壓縮級(jí)別 0 - 7(指定代碼進(jìn)行迭代優(yōu)化的次數(shù)寓搬,在Android里面默認(rèn)是5,這條指令也只有在可以優(yōu)化時(shí)起作用县耽。)
-optimizationpasses 5
# 混淆時(shí)不會(huì)產(chǎn)生形形色色的類名(混淆時(shí)不使用大小寫(xiě)混合類名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的庫(kù)類(不跳過(guò)library中的非public的類)
-dontskipnonpubliclibraryclasses
# 指定不去忽略包可見(jiàn)的庫(kù)類的成員
-dontskipnonpubliclibraryclassmembers
#不進(jìn)行優(yōu)化句喷,建議使用此選項(xiàng),
-dontoptimize
# 不進(jìn)行預(yù)校驗(yàn),Android不需要,可加快混淆速度兔毙。
-dontpreverify
# 屏蔽警告
-ignorewarnings
# 指定混淆是采用的算法唾琼,后面的參數(shù)是一個(gè)過(guò)濾器
# 這個(gè)過(guò)濾器是谷歌推薦的算法,一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保護(hù)代碼中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 這在JSON實(shí)體映射時(shí)非常重要
-keepattributes Signature
# 拋出異常時(shí)保留代碼行號(hào)
-keepattributes SourceFile,LineNumberTable
#優(yōu)化時(shí)允許訪問(wèn)并修改有修飾符的類和類的成員澎剥,這可以提高優(yōu)化步驟的結(jié)果锡溯。
# 比如,當(dāng)內(nèi)聯(lián)一個(gè)公共的getter方法時(shí),這也可能需要外地公共訪問(wèn)祭饭。
# 雖然java二進(jìn)制規(guī)范不需要這個(gè)芜茵,要不然有的虛擬機(jī)處理這些代碼會(huì)有問(wèn)題。當(dāng)有優(yōu)化和使用-repackageclasses時(shí)才適用倡蝙。
#指示語(yǔ):不能用這個(gè)指令處理庫(kù)中的代碼九串,因?yàn)橛械念惡皖惓蓡T沒(méi)有設(shè)計(jì)成public ,而在api中可能變成public
-allowaccessmodification
#當(dāng)有優(yōu)化和使用-repackageclasses時(shí)才適用。
-repackageclasses ''
# 混淆時(shí)記錄日志(打印混淆的詳細(xì)信息)
# 這句話能夠使我們的項(xiàng)目混淆后產(chǎn)生映射文件
# 包含有類名->混淆后類名的映射關(guān)系
-verbose
-printmapping proguardMapping.txt
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
#
# ----------------------------- 默認(rèn)保留 -----------------------------
#
#----------------------------------------------------
# 保持哪些類不被混淆
#繼承activity,application,service,broadcastReceiver,contentprovider....不進(jìn)行混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-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.view.View
-keep class android.support.** {*;}## 保留support下的所有類及其內(nèi)部類
-keep interface android.support.** { *; }
-dontwarn android.support.**
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#表示不混淆上面聲明的類寺鸥,最后這兩個(gè)類我們基本也用不上猪钮,是接入Google原生的一些服務(wù)時(shí)使用的。
#----------------------------------------------------
# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 不混淆使用了 @Keep 注解相關(guān)的類
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
#表示不混淆任何包含native方法的類的類名以及native方法名胆建,這個(gè)和我們剛才驗(yàn)證的結(jié)果是一致
-keepclasseswithmembernames class * {
native <methods>;
}
#這個(gè)主要是在layout 中寫(xiě)的onclick方法android:onclick="onClick"烤低,不進(jìn)行混淆
#表示不混淆Activity中參數(shù)是View的方法,因?yàn)橛羞@樣一種用法笆载,在XML中配置android:onClick=”buttonClick”屬性扑馁,
#當(dāng)用戶點(diǎn)擊該按鈕時(shí)就會(huì)調(diào)用Activity中的buttonClick(View view)方法,如果這個(gè)方法被混淆的話就找不到了
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#表示不混淆枚舉中的values()和valueOf()方法凉驻,枚舉我用的非常少檐蚜,這個(gè)就不評(píng)論了
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#表示不混淆任何一個(gè)View中的setXxx()和getXxx()方法,
#因?yàn)閷傩詣?dòng)畫(huà)需要有相應(yīng)的setter和getter的方法實(shí)現(xiàn)沿侈,混淆了就無(wú)法工作了。
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Context
-keepclassmembers class * extends android.content.Context {
public void *(android.view.View);
public void *(android.view.MenuItem);
}
#表示不混淆Parcelable實(shí)現(xiàn)類中的CREATOR字段市栗,
#毫無(wú)疑問(wèn)缀拭,CREATOR字段是絕對(duì)不能改變的,包括大小寫(xiě)都不能變填帽,不然整個(gè)Parcelable工作機(jī)制都會(huì)失敗蛛淋。
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 這指定了繼承Serizalizable的類的如下成員不被移除混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保留R下面的資源
-keep class **.R$* {
*;
}
#不混淆資源類下static的
-keepclassmembers class **.R$* {
public static <fields>;
}
# 對(duì)于帶有回調(diào)函數(shù)的onXXEvent、**On*Listener的篡腌,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# 保留我們自定義控件(繼承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#
#----------------------------- WebView(項(xiàng)目中沒(méi)有可以忽略) -----------------------------
#
#webView需要進(jìn)行特殊處理
-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);
}
#在app中與HTML5的JavaScript的交互進(jìn)行特殊處理
#我們需要確保這些js要調(diào)用的原生方法不能夠被混淆褐荷,于是我們需要做如下處理:
-keepclassmembers class fm.qingting.customize.huaweireader.ui.JSInterface {
<methods>;
}
#
#---------------------------------實(shí)體類---------------------------------
# 不混淆使用了 @Keep 注解相關(guān)的類
-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>(...);
}
#--------(實(shí)體Model不能混淆,否則找不到對(duì)應(yīng)的屬性獲取不到值)-----
#
-dontwarn huican.commlibrary.bean.**
#對(duì)含有反射類的處理
-keep class huican.commlibrary.bean.** { *; }
#
# ----------------------------- 其他的 -----------------------------
#
# 刪除代碼中 Log 相關(guān)的代碼嘹悼,如果刪除了一些預(yù)料之外的代碼叛甫,很容易就會(huì)導(dǎo)致代碼崩潰,謹(jǐn)慎使用
# 刪除代碼中Log相關(guān)的代碼
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
# 保持測(cè)試相關(guān)的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
#
# ----------------------------- 第三方 -----------------------------
#
-dontwarn com.orhanobut.logger.**
-keep class com.orhanobut.logger.**{*;}
-keep interface com.orhanobut.logger.**{*;}
#gson混淆配置
-keep public class com.google.gson.**
-keep public class com.google.gson.** {public private protected *;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.gson.** { *;}
#Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
#如果你的 target API 低于 Android API 27杨伙,請(qǐng)?zhí)砑樱?#```pro
#-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder
#VideoDecoder 使用 API 27 的一些接口其监,這可能導(dǎo)致 proguard 發(fā)出警告,盡管這些 API 在舊版 Android 設(shè)備上根本不會(huì)被調(diào)用限匣。
#如果你使用 DexGuard 你可能還需要添加:
# for DexGuard only
#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.-KotlinExtensions
# OkHttp3
-dontwarn okio.**
-dontwarn okhttp3.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
#retrofit2
-keep class retrofit2.** { *; }
-dontwarn retrofit2.**
-keepattributes Signature
-keepattributes Exceptions
# ButterKnife
-keep public class * implements butterknife.Unbinder {
public <init>(**, android.view.View);
}
-keep class butterknife.*
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
# AndroidEventBus
-keep class org.simple.** { *; }
-keep interface org.simple.** { *; }
-keepclassmembers class * {
@org.simple.eventbus.Subscriber <methods>;
}
# 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;
}
-dontnote rx.internal.util.PlatformDependent
# RxLifeCycle
#-keep class com.trello.rxlifecycle2.** { *; }
#-keep interface com.trello.rxlifecycle2.** { *; }
# Canary
#-dontwarn com.squareup.haha.guava.**
#-dontwarn com.squareup.haha.perflib.**
#-dontwarn com.squareup.haha.trove.**
#-dontwarn com.squareup.leakcanary.**
#-keep class com.squareup.haha.** { *; }
#-keep class com.squareup.leakcanary.** { *; }
# 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
# Bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# BaseRecyclerViewAdapterHelper
-keep class com.chad.library.adapter.** {
*;
}
-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
-keepclassmembers class **$** extends com.chad.library.adapter.base.BaseViewHolder {
<init>(...);
}
# reactivex
-keep class io.reactivex.** { *; }
-keep interface io.reactivex.** { *; }
-keep class com.squareup.okhttp.** { *; }
-dontwarn okio.**
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**
-dontwarn io.reactivex.**
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepclasseswithmembers class * {
@retrofit.http.* <methods>;
}
-keep class sun.misc.Unsafe { *; }
-dontwarn java.lang.invoke.*
-keep class io.reactivex.schedulers.Schedulers {
public static <methods>;
}
-keep class io.reactivex.schedulers.ImmediateScheduler {
public <methods>;
}
-keep class io.reactivex.schedulers.TestScheduler {
public <methods>;
}
-keep class io.reactivex.schedulers.Schedulers {
public static ** test();
}
-keepclassmembers class io.reactivex.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
long producerNode;
long consumerNode;
}
-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
io.reactivex.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class io.reactivex.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
io.reactivex.internal.util.atomic.LinkedQueueNode consumerNode;
}
-dontwarn io.reactivex.internal.util.unsafe.**
# Espresso
-keep class android.support.test.espresso.** { *; }
-keep interface android.support.test.espresso.** { *; }
# Annotation
#-keep class android.support.annotation.** { *; }
#-keep interface android.support.annotation.** { *; }
#權(quán)限
#-dontwarn com.yanzhenjie.permission.**
#-keep com.yanzhenjie.permission.**
# RxPermissions
-keep class com.tbruyelle.rxpermissions2.** { *; }
-keep interface com.tbruyelle.rxpermissions2.** { *; }
# RxCache
-dontwarn io.rx_cache2.internal.**
-keep class io.rx_cache2.internal.Record { *; }
-keep class io.rx_cache2.Source { *; }
-keep class io.victoralbertos.jolyglot.** { *; }
-keep interface io.victoralbertos.jolyglot.** { *; }
# Marshmallow removed Notification.setLatestEventInfo()
-dontwarn android.app.Notification
# Greendao
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-dontwarn org.greenrobot.greendao.database.**
# If you do not use Rx:
#-dontwarn rx.**
# 百度地圖
#-keep class com.baidu.** {*;}
#-keep class vi.com.** {*;}
#-dontwarn com.baidu.**
# 高德地圖
#-keep class com.amap.api.maps.**{*;}
#-keep class com.autonavi.**{*;}
#-keep class com.amap.api.trace.**{*;}
#-keep class com.amap.api.location.**{*;}
#-keep class com.amap.api.fence.**{*;}
#-keep class com.autonavi.aps.amapapi.model.**{*;}
#-keep class com.amap.api.services.**{*;}
#-keep class com.amap.api.maps2d.**{*;}
#-keep class com.amap.api.mapcore2d.**{*;}
#-keep class com.amap.api.navi.**{*;}
#-keep class com.autonavi.**{*;}
##沒(méi)有說(shuō)明
# bga-banner
-dontwarn cn.bingoogolapple.**
-keep class cn.bingoogolapple.**{ *;}
# smartrefresh
-dontwarn com.scwang.smartrefresh.**
-keep class com.scwang.smartrefresh.**{ *;}
# brvah
-dontwarn com.github.CymChad.**
-keep class com.github.CymChad.**{ *;}
# swipelayout
-dontwarn com.daimajia.swipelayout.**
-keep class com.daimajia.swipelayout.**{ *;}
# room
-dontwarn android.arch.persistence.room.**
-keep class android.arch.persistence.room.**{ *;}
# room
-dontwarn androidx.room.**
-keep class androidx.room.**{ *;}
# lifecycle
-dontwarn android.arch.lifecycle.**
-keep class android.arch.lifecycle.**{ *;}
webview ,實(shí)體類抖苦,第三方 需要根據(jù)項(xiàng)目添加,項(xiàng)目中沒(méi)有可以忽略
實(shí)體類需要用@Keep注解,沒(méi)有用@keep注解的實(shí)體類類需要額外添加
比如
#
-dontwarn huican.commlibrary.bean.**
#對(duì)含有反射類的處理
-keep class huican.commlibrary.bean.** { *; }
如果集成引入了一個(gè)第三方庫(kù) 锌历,沒(méi)有官方文檔混淆說(shuō)明贮庞,怎么添加混淆?
比如 implementation "com.daimajia.swipelayout:library:1.2.0@aar"
可以這樣添加
# swipelayout
-dontwarn com.daimajia.swipelayout.**
-keep class com.daimajia.swipelayout.**{ *;}
查看當(dāng)前module 下的依賴 比如(module 為app)
./gradlew :app:dependencies
2.2 插件集成-androidproguard pro
會(huì)生成上面-基本不用動(dòng)區(qū)域 究西,動(dòng)態(tài)改變區(qū)域需要我們補(bǔ)充窗慎,
3.多module注意事項(xiàng)
多module的混淆方式一般兩種方式
1.在app module中統(tǒng)一配置混淆規(guī)則
我們可以直接在app module中build.gradle文件配置所有module需要混淆的規(guī)則。這樣怔揩,其他module中就無(wú)需開(kāi)啟混淆捉邢。但是并不推薦使用這種方法,缺點(diǎn)是:當(dāng)我們?nèi)∠蕾嚹承﹎odule的時(shí)候商膊,還需要?jiǎng)h除該module相關(guān)的混淆配置伏伐,相對(duì)麻煩。
2.各個(gè)module單獨(dú)配置混淆規(guī)則(推薦)
我們也可以單獨(dú)為module配置混淆規(guī)則晕拆,比較推薦這種做法藐翎。每個(gè)module管理自己的混淆文件,當(dāng)我們不依賴該module的時(shí)候实幕,就不會(huì)發(fā)生第一種方法出現(xiàn)的問(wèn)題了吝镣。
我們把a(bǔ)pp module稱作為主模塊,其依賴的其他module稱作為子模塊
子模塊混淆文件的指定是通過(guò)consumerProguardFiles這個(gè)屬性來(lái)指定的昆庇,并不是proguardFiles 屬性
如下
buildTypes {
release {
//minifyEnabled false
//proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
consumerProguardFiles 'proguard-rules.pro'
}
debug {
// minifyEnabled false
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
consumerProguardFiles 'proguard-rules.pro'
}
}
參考文獻(xiàn)
Android混淆
Android多模塊混淆末贾、多module混淆、多l(xiāng)ibrary混淆的正確姿勢(shì)