縮減代碼和資源(Shrink Your Code and Resources)

原文鏈接:https://developer.android.com/studio/build/shrink-code.html

一冻晤、代碼縮減和資源縮減概述

為盡可能縮減apk包的大小,我們應(yīng)該在release版本中移除未使用的代碼和資源右冻。這篇文檔描述如何在構(gòu)建過程中指定保留和移除的代碼與資源。
代碼縮減(Code shrinking)利用ProGuard 累颂,它可以檢測和移除app中沒有使用的類侣集、字段、方法和屬性建椰,包括來自代碼庫的那些。ProGuard還可以優(yōu)化class文件岛马,刪除未使用的代碼指令棉姐,并使用短名稱來混淆類字段和方法。
資源縮減(Resource shrinking)可利用Gradle配置蛛枚,它可以移除app中未使用的資源谅海,包括代碼庫中未使用的資源。它與代碼縮減一起工作蹦浦,使得一旦未使用的代碼被移除扭吁,任何不再被引用的資源也可以被安全地移除。
本文檔中的功能依賴于:

二盲镶、代碼縮減(Shrink Your Code)

1.啟用代碼縮減

要使用ProGuard啟用代碼縮減侥袜,請將minifyEnabled true添加到build.gradle文件中的相應(yīng)build type。
注意溉贿,代碼縮減會減慢構(gòu)建時間枫吧,因此,盡量避免在dbeug版本上使用它宇色。不過重要的是九杂,必須在在啟用代碼縮減的apk上進行測試颁湖,因為如果沒有足夠自定義要保留的代碼,它可能會引入錯誤例隆。
代碼縮減gradle配置示例:

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

除了指定minifyEnabled屬性甥捺,proguardFiles屬性還定義了ProGuard規(guī)則:

  • getDefaultProguardFile('proguard-android.txt')從SDK tools /proguard /下的proguard-android.txt設(shè)置默認的ProGuard設(shè)置。
    (備注:為更好地代碼縮減镀层,可以利用位于相同位置的proguard-android-optimize.txt文件镰禾。 它包括相同的ProGuard規(guī)則,但在執(zhí)行分析字節(jié)碼級別等方面進一步優(yōu)化唱逢,可以更好地減少apk大小吴侦,并幫助它運行更快。)
  • proguard-rules.pro中可以添加自定義ProGuard規(guī)則坞古。默認情況下备韧,此文件位于module的根目錄(在build.gradle文件旁邊)。

我們也可以為不同的Variant指定不同的ProGuard規(guī)則:

android {
...
  buildTypes {
    release {
      minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
    }
  }
  productFlavors {
    flavor1 {
    }
    flavor2 {
      proguardFile 'flavor2-rules.pro'
    }
  }
}

項目構(gòu)建后绸贡,在/build/outputs/mapping/release/下會生成幾個文件:

  • dump.txt:apk文件中所有類文件間的內(nèi)部結(jié)構(gòu)
  • mapping.txt:混淆前后代碼間的映射
  • seeds.txt:未被混淆的類和成員
  • usage.txt:未使用的盯蝴、被apk刪除的代碼

2.定義保留哪些代碼

大多數(shù)情況下,默認的ProGuard配置文件(proguard-android.txt)就足夠了听怕,ProGuard刪除所有未使用的代碼。然而虑绵,有些情況下尿瞭,ProGuard很難正確分析,它可能會刪除您的應(yīng)用程序?qū)嶋H需要的代碼翅睛。比如:

  • 當僅在AndroidManifest.xml文件中引用的類
  • 當從JNI調(diào)用方法時
  • 當在字節(jié)碼中操作代碼時(如使用反射)
    為修復(fù)錯誤并強制ProGuard保留某些代碼声搁,需要在ProGuard配置文件中添加一個-keep標記,比如:

-keep public class MyClass

或者捕发,您可以將@Keep注釋添加到要保留的代碼疏旨。請注意,此注釋僅在使用注釋支持庫時可用扎酷。
使用-keep選項時檐涝,您應(yīng)該考慮許多因素;有關(guān)自定義配置文件的更多信息,請閱讀 ProGuard手冊法挨。

3.解析混淆后的堆棧跟蹤(Stack trace)

ProGuard縮減代碼后谁榜,讀取堆棧跟蹤是很困難的,因為方法名都被混淆處理了凡纳。幸運的是窃植,ProGuard在構(gòu)建過程中創(chuàng)建了mapping.txt作為混淆前后代碼的映射。
由于mapping.txt在每次構(gòu)建過程中會被重寫荐糜,所以需要在每個版本對應(yīng)的mapping.txt保存到對應(yīng)的目錄下巷怜。如果用戶從舊版本app提交混淆的堆棧跟蹤葛超,我們就可以通過每個版本對應(yīng)的mapping.txt,來調(diào)試問題延塑。
當我們在應(yīng)用商店發(fā)布app時绣张,也可以將對應(yīng)的mapping.txt提交上去,這樣應(yīng)用商店就可以將用戶報告的問題中直接進行解析页畦。
要將混淆的堆棧跟蹤轉(zhuǎn)換為可讀的堆棧跟蹤胖替,請使用回溯腳本(Windows上為retrace.bat;Mac上為retrace.sh)。 它位于 / tools / proguard /目錄中豫缨。該腳本采用mapping.txt文件和堆棧跟蹤独令,產(chǎn)生一個新的、可讀的堆棧跟蹤好芭。
使用retrace.bat的語法:

retrace.bat|retrace.sh [-verbose] mapping.txt []

例如:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

三燃箭、資源縮減(Shrink Your Resources)

1.啟用資源縮減

資源縮減必須與代碼縮減相結(jié)合。代碼縮減移除所有未使用的代碼后舍败,資源縮減器可以識別應(yīng)用程序仍在使用哪些資源招狸。 未被使用的資源,將會被資源縮減器移除邻薯。
為使用資源縮減裙戏,需要在gradle文件中設(shè)置shrinkResources屬性,例如:

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

注意厕诡,資源縮減不會移除value文件下的資源(比如strings, dimensions, styles, and colors)累榜,aapt不允許gradle這樣做。

2.指定保留哪些資源

對于一些你希望保留或移除的資源灵嫌,可以創(chuàng)建一個xml文件壹罚,以resource為標簽,通過tools:keeptools:discard指定要保留和要移除的資源寿羞,多個資源之間以逗號分隔猖凛。例如:

tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
tools:discard="@layout/unused2" />

將此文件保存在項目資源中,比如res/raw/keep.xml绪穆,構(gòu)建時不會將該文件打包到apk中辨泳。
指定要移除的資源,比起來直接刪除掉霞幅,似乎有些傻漠吻。但是,對于構(gòu)建多個Variant司恳,卻是很有用的途乃。我們可以為不同的變體指定不同的keep.xml。

3.啟用嚴格引用檢查

通常扔傅,資源縮減器能夠判斷出指定資源是否被使用耍共。但是烫饼,如果你的代碼調(diào)用了Resources.getIdentifier()(或者你的庫中的任何一個,比如AppCompat庫)试读,這意味著你的代碼是基于動態(tài)生成的字符串查找資源名稱杠纵。這樣操作時,資源縮小器默認情況下會防御性地運行钩骇,并將匹配名稱格式的所有資源標記為可能已使用而不會去移除比藻。
例如,以下代碼會將所有帶有img_前綴的資源標記為已使用倘屹。

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

資源縮小器還查看代碼中的所有字符串常量以及各種res / raw /資源银亲,以類似于file:///android_res/drawable//ic_plus_anim_016.png的格式查找資源url。如果它發(fā)現(xiàn)類似這樣的字符串或其他纽匙,也不會移除它們务蝠。
這些是默認情況下啟用的安全縮減模式的示例。但是烛缔,當不關(guān)注#“better safe than sorry”#時馏段,可以指定資源縮減器僅保留其確定使用的資源。為此践瓷,請在keep.xml文件中將shrinkMode設(shè)置為strict院喜,如下所示:

tools:shrinkMode="strict" />

如果您啟用了嚴格縮減模式,并且您的代碼還引用了具有動態(tài)生成的字符串的資源晕翠,那么您必須使通過tools:keep手動保留這些資源够坐。

4.移除帶有選擇性的資源

資源縮減器只會移除沒有在代碼中被引用的資源,這也意味著崖面,它不會移除那些為不同設(shè)備配置的帶有選擇性質(zhì)的資源。必要的情況下梯影,可以利用resConfigs屬性移除這些資源巫员。
例如,如果您使用的庫包含語言資源甲棍,則apk會包含這些庫中的所有翻譯語言字符串简识。如果您只想保留指定的語言,可以使用resConfig屬性進行指定感猛,并將刪除未指定語言的任何資源七扰。
以下代碼段顯示了如何將語言資源僅限英語和法語:

android {
  defaultConfig {
  ... ...
    resConfigs“en”,“fr”
  }
}

同樣陪白,您可以自定義要在apk中包含哪些屏幕密度或ABI資源颈走,并為不同設(shè)備構(gòu)建不同的apk。

5.合并重復(fù)的資源

這里的合并英文為merge咱士,帶有解決沖突的意思立由。
默認情況下轧钓,gradle會合并相同名稱的資源,例如可能在不同資源文件夾中具有相同名稱的drawable锐膜。 此行為不受shrinkResources屬性控制毕箍,不能禁用,因為必須避免在多個資源與代碼查找的名稱匹配時出現(xiàn)錯誤道盏。
僅當兩個或多個文件共享相同的資源名稱時而柑,才會進行資源合并。gradle選擇哪個文件被認為是重復(fù)項中的最佳選擇(基于下面描述的優(yōu)先級順序)荷逞,并且僅將那個資源傳遞給aapt以在apk中分發(fā)媒咳。
gradle在以下位置查找重復(fù)的資源:

  • main resources,與主源集相關(guān)颅围,一般位于src / main / res /肩碟。
  • 變體覆蓋尘颓,從the build type和build flavors。
  • 庫項目依賴項。
    gradle在以下優(yōu)先級順序中合并重復(fù)資源:

Dependencies→Main→Build flavor→Build type

例如丧慈,如果重復(fù)資源出現(xiàn)在main resources和build flavor,gradle會選擇build flavor中的。

6.資源合并描述文件

當縮減資源時颈嚼,Gradle Console會顯示從應(yīng)用程序包中刪除的資源的摘要怜械。例如:

:android:shrinkDebugResources
Removed unused resources: Binary resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

gradle還會在/build/outputs/mapping/release/創(chuàng)建一個文件resources.txt,來描述哪些資源被引用和被移除弄抬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茎辐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掂恕,更是在濱河造成了極大的恐慌拖陆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懊亡,死亡現(xiàn)場離奇詭異依啰,居然都是意外死亡,警方通過查閱死者的電腦和手機店枣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門速警,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鸯两,你說我怎么就攤上這事闷旧。” “怎么了钧唐?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵忙灼,是天一觀的道長。 經(jīng)常有香客問我逾柿,道長缀棍,這世上最難降的妖魔是什么宅此? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮爬范,結(jié)果婚禮上父腕,老公的妹妹穿的比我還像新娘。我一直安慰自己青瀑,他們只是感情好璧亮,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著斥难,像睡著了一般枝嘶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哑诊,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天群扶,我揣著相機與錄音,去河邊找鬼镀裤。 笑死竞阐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的暑劝。 我是一名探鬼主播骆莹,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼担猛!你這毒婦竟也來了幕垦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤傅联,失蹤者是張志新(化名)和其女友劉穎先改,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒸走,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡盏道,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了载碌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡衅枫,死狀恐怖嫁艇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弦撩,我是刑警寧澤步咪,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站益楼,受9級特大地震影響猾漫,放射性物質(zhì)發(fā)生泄漏点晴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一悯周、第九天 我趴在偏房一處隱蔽的房頂上張望粒督。 院中可真熱鬧,春花似錦禽翼、人聲如沸屠橄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锐墙。三九已至,卻和暖如春长酗,著一層夾襖步出監(jiān)牢的瞬間溪北,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工夺脾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留之拨,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓劳翰,卻偏偏與公主長得像敦锌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佳簸,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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