Android代碼混淆&組件化混淆方案

前言

最近在整理項目中的混淆,踩了很多坑走趋,如果不打開混淆衅金,項目上線了等于裸奔,風(fēng)險很大簿煌,混淆如果打開了處理不好氮唯,會出現(xiàn)很多莫名其妙的問題,所以我整理了比較全面的代碼混淆方法姨伟,包括組件化的代碼混淆方案惩琉,比較實用,希望對大家有幫助夺荒。

開啟混淆

打開app模塊下的build.gradle文件瞒渠,把minifyEnabled設(shè)置為true,代碼如下

minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

proguard-android.txt是Android提供的默認(rèn)混淆配置文件技扼,在配置的Android sdk /tools/proguard目錄下伍玖,感興趣的可以打開看下,proguard-rules.pro是我們自定義的混淆配置文件,我們可以將我們自定義的混淆規(guī)則放在里面剿吻。

自定義混淆規(guī)則

混淆常見命令

命令 簡介
dontwarn dontwarn基本會和keep同時出現(xiàn)窍箍,尤其是在引入library的時候,是為了忽略library的警告丽旅,保證build的正常進(jìn)行
keep 保留類和類中的成員椰棘,防止被重命名或移除
keepnames 保留類和類中的成員,防止被重命名魔招,成員沒有被引用會被移除
keepclassmembers 只保留類中的成員晰搀,防止被重命名或移除
keepclassmembernames 只保留類中的成員,防止被重命名办斑,成員沒有引用會被移除
keepclasseswithmembers 保留擁有該成員的類和成員外恕,防止被重命名或移除
keepclasseswithmembernames 保留擁有該成員的類和成員杆逗,防止被重命名

keep的規(guī)則

[keep命令] [類] {
        [成員]
}
  • “類”代表類相關(guān)的限定條件,它將最終定位到某些符合該限定條件的類鳞疲。它的內(nèi)容可以使用:
    • 具體的類
    • 訪問修飾符(public罪郊、protected、private)
    • 通配符*尚洽,匹配任意長度字符悔橄,但不含包名分隔符(.)
    • 通配符**,匹配任意長度字符腺毫,并且包含包名分隔符(.)
    • extends癣疟,即可以指定類的基類
    • implement,匹配實現(xiàn)了某接口的類
    • $潮酒,內(nèi)部類
  • “成員”代表類成員相關(guān)的限定條件睛挚,它將最終定位到某些符合該限定條件的類成員。它的內(nèi)容可以使用:
    • <init> 匹配所有構(gòu)造器
    • <fields> 匹配所有域
    • <methods> 匹配所有方法
    • 通配符*急黎,匹配任意長度字符扎狱,但不含包名分隔符(.)
    • 通配符**,匹配任意長度字符勃教,并且包含包名分隔符(.)
    • 通配符***淤击,匹配任意參數(shù)類型
    • …,匹配任意長度的任意類型參數(shù)故源。比如void test(…)就能匹配任意 void test(String a) 或者是 void test(int a, String b) 這些方法污抬。
    • 訪問修飾符(public、protected绳军、private)

常用混淆規(guī)則

#關(guān)閉bugly sdk的警告
-dontwarn com.tencent.bugly.**

#不混淆某個類
-keep public class com.jesse.example.Test { *; }

#不混淆某個類的子類
-keep public class * extends com.jesse.example.Test { *; }

#不混淆某個包所有的類
-keep class com.jesse.example.bean.** { *; }

#不混淆所有類名中包含了“model”的類及其成員
-keep public class **.*model*.** {*;}

#不混淆某個接口的實現(xiàn)
-keep class * implements com.jesse.example.TestInterface { *; }

#不混淆某個類的構(gòu)造方法
-keepclassmembers class com.jesse.example.Test {
    public <init>();
}
#不混淆某個類的特定的方法
-keepclassmembers class com.jesse.example.Test {
    public void test(java.lang.String);
}
#不混淆某個類的內(nèi)部類
-keep class com.jesse.example.Test$* {
        *;
}

更多proguard規(guī)則壕吹,可以去官網(wǎng)查看

組件化代碼混淆方案

首先我們在創(chuàng)建一個Android Module的時候,在Module的build.gradle中都會自動生成兩個proguard的配置删铃,如下:

defaultConfig {
    ...
    consumerProguardFiles 'consumer-rules.pro'
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

關(guān)于consumerProguardFilesproguardFiles的區(qū)別,網(wǎng)上查了下踏堡,沒有一個說的清楚點的猎唁,求人不如求己,在經(jīng)過我的實踐之后顷蟆,我總結(jié)了有以下幾個區(qū)別诫隅,感興趣的也可以自己實踐下,看看我說的對不對:

  • consumerProguardFiles配置的proguard會被打進(jìn)aar包中帐偎,而proguardFiles配置的proguard不會被打進(jìn)aar中
  • proguardFiles配置的proguard文件只作用于庫文件代碼逐纬,只在編譯發(fā)布aar的時候有效,在你將庫文件作為一個模塊添加到App模塊中后削樊,庫文件中consumerProguardFiles配置的proguard文件則會追加到app模塊的Proguard配置文件中豁生,作用于整個app代碼兔毒。

了解了他們的區(qū)別后,我們來看組件化代碼混淆方案甸箱。

方案一:在app模塊中管理所有的混淆規(guī)則

優(yōu)點:所有混淆規(guī)則在app模塊的proguard-rule.pro文件中統(tǒng)一管理

缺點:移除某些模塊后育叁,需手動移除app模塊中的混淆規(guī)則。理論上混淆規(guī)則添加多了不會造成崩潰或者編譯不通過芍殖,但是會影響編譯效率

方案二:組件模塊管理各自的混淆規(guī)則

優(yōu)點:將混淆文件解耦到每個模塊中豪嗽,并且不會影響編譯效率

那么我們應(yīng)該如何解耦呢?我們可以通過consumerProguardFiles在各個組件模塊中配置各自的混淆規(guī)則豌骏,因為這種方式配置的混淆規(guī)則最終都會追加到app模塊的混淆規(guī)則中龟梦,并最終統(tǒng)一混淆

組件化代碼混淆總結(jié)

我們可以將固定的第三方混淆放到common模塊的consumer-rules.pro文件中窃躲,每個模塊獨(dú)有的第三方引用庫混淆放到各自的consumer-rules.pro文件中计贰,在app模塊的proguard-rule.pro文件中放入Android通用的混淆聲明,如四大組件和全局的混淆等配置框舔。這樣可以最大限度的完成混淆解耦操作蹦玫。

最后附上app中通用的混淆配置

#---------------------------------基本指令區(qū)----------------------------------

# 指定代碼的壓縮級別 0 - 7(指定代碼進(jìn)行迭代優(yōu)化的次數(shù),在Android里面默認(rèn)是5刘绣,這條指令也只有在可以優(yōu)化時起作用樱溉。)
-optimizationpasses 5
# 混淆時不會產(chǎn)生形形色色的類名(混淆時不使用大小寫混合類名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的庫類(不跳過library中的非public的類)
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共的的庫類的成員
-dontskipnonpubliclibraryclassmembers
#不進(jìn)行預(yù)校驗,Android不需要,可加快混淆速度。
-dontpreverify
# 混淆時記錄日志(打印混淆的詳細(xì)信息)
# 這句話能夠使我們的項目混淆后產(chǎn)生映射文件
# 包含有類名->混淆后類名的映射關(guān)系
-verbose
-printmapping proguardMapping.txt
# 指定混淆是采用的算法纬凤,后面的參數(shù)是一個過濾器
# 這個過濾器是谷歌推薦的算法福贞,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#保護(hù)代碼中的 Annotation 內(nèi)部類不被混淆
-keepattributes *Annotation*,InnerClasses
-ignorewarning
# 避免混淆泛型,這在 JSON 實體映射時非常重要停士,比如 fastJson
-keepattributes Signature
# 拋出異常時保留代碼行號挖帘,在異常分析中可以方便定位
-keepattributes SourceFile,LineNumberTable
#----------------------------------------------------------------------------

#---------------------------------默認(rèn)保留區(qū)---------------------------------
-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.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}

# 保留所有的本地 native 方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
# 保留在 Activity 中的方法參數(shù)是 view 的方法,
# 從而我們在 layout 里面編寫 onClick 就不會被影響
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
# 枚舉類不能被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# 保留自定義控件(繼承自 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);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保留 Parcelable 序列化的類不被混淆
-keep class * implements android.os.Parcelable {
  *;
}
# 保留 Serializable 序列化的類不被混淆
-keep class * implements java.io.Serializable { *;}
-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$* {
 *;
}
# 對于帶有回調(diào)函數(shù) onXXEvent 的拇舀,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
}

-keepclassmembers class * {
   public <init>(org.json.JSONObject);
}

-keepattributes *JavascriptInterface*

#----------------------------------------------------------------------------

#---------------------------------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);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜻底,隨后出現(xiàn)的幾起案子骄崩,更是在濱河造成了極大的恐慌,老刑警劉巖薄辅,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件要拂,死亡現(xiàn)場離奇詭異,居然都是意外死亡站楚,警方通過查閱死者的電腦和手機(jī)脱惰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窿春,“玉大人拉一,你說我怎么就攤上這事采盒。” “怎么了舅踪?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵纽甘,是天一觀的道長。 經(jīng)常有香客問我抽碌,道長悍赢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任货徙,我火速辦了婚禮左权,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘痴颊。我一直安慰自己主之,他們只是感情好务冕,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布贝攒。 她就那樣靜靜地躺著答捕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泻仙。 梳的紋絲不亂的頭發(fā)上糕再,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音玉转,去河邊找鬼突想。 笑死,一個胖子當(dāng)著我的面吹牛究抓,可吹牛的內(nèi)容都是我干的猾担。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼刺下,長吁一口氣:“原來是場噩夢啊……” “哼绑嘹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橘茉,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤圾叼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捺癞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡构挤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年髓介,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筋现。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唐础,死狀恐怖箱歧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情一膨,我是刑警寧澤呀邢,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站豹绪,受9級特大地震影響价淌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞒津,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一蝉衣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧巷蚪,春花似錦病毡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至淌喻,卻和暖如春僧家,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背似嗤。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工啸臀, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烁落。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓乘粒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伤塌。 傳聞我的和親對象是個殘疾皇子灯萍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本篇文章:自己在混淆的時候整理出比較全面的混淆方法,比較實用每聪,自己走過的坑旦棉,淌出來的路。請大家不要再走回頭路药薯,可能...
    Zane_Samuel閱讀 55,363評論 8 93
  • 前言 代碼混淆對于每個入門的 Android 工程師來說都不會太陌生童本,因為在編譯正式版本時真屯,這是一個必不可少的過程...
    彭旭銳閱讀 5,169評論 2 45
  • Android知識總結(jié)[http://www.reibang.com/p/01b1de0504d2] 一、配置(...
    濤濤123759閱讀 457評論 0 1
  • 什么是混淆 代碼壓縮通過 ProGuard 提供穷娱,ProGuard 會檢測和移除封裝應(yīng)用中未使用的類绑蔫、字段运沦、方法和...
    6He閱讀 2,878評論 0 0
  • 久違的晴天,家長會配深。 家長大會開好到教室時携添,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗篓叶。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評論 16 22