Android性能調(diào)優(yōu);如何讓你的APK瘦身88%

原文鏈接:http://www.reibang.com/p/4cead9e545b9

前言

隨著業(yè)務(wù)復(fù)雜度的逐漸增加裁替,代碼、資源也在不斷的增加貌笨,此時(shí)你的APP大小也在增加弱判。從用戶層面來說,面對動(dòng)輒幾十兆的APP來說在非WIFI情況下還是會(huì)猶豫要不要下載锥惋,不下載你就可能因此失去了一個(gè)用戶昌腰。從公司層面來講,流量就是錢膀跌,減少APP的大小就顯得尤為重要遭商。從開發(fā)者層面上來講,你掌握了這個(gè)手藝也會(huì)略顯逼格滿滿捅伤。

廢話不多說了劫流,開始正題。

1.APK結(jié)構(gòu)的那些事

知己知彼,方能百戰(zhàn)不殆困介。了解應(yīng)用程序APK的結(jié)構(gòu)對于我們來說很有幫助大审。APK文件由一個(gè)ZIP存檔組成,其中包含組成應(yīng)用程序的所有文件座哩。這些文件包括Java類文件徒扶,資源文件和包含編譯資源的文件。

APK包含以下目錄:

  • META-INF/:包含CERT.SF和 CERT.RSA簽名文件以及MANIFEST.MF 清單文件根穷。
  • assets/:包含應(yīng)用可以使用AssetManager對象檢索的應(yīng)用資源姜骡。
  • res/:包含未編譯到的資源 resources.arsc。
  • lib/:包含特定于處理器軟件層的編譯代碼屿良。該目錄包含了每種平臺(tái)的子目錄圈澈,像armeabi,armeabi-v7a尘惧, arm64-v8a康栈,x86,x86_64喷橙,和mips啥么。
  • resources.arsc:包含已編譯的資源。該文件包含res/values/ 文件夾所有配置中的XML內(nèi)容贰逾。打包工具提取此XML內(nèi)容悬荣,將其編譯為二進(jìn)制格式,并將內(nèi)容歸檔疙剑。此內(nèi)容包括語言字符串和樣式氯迂,以及直接包含在resources.arsc文件中的內(nèi)容路徑 ,例如布局文件和圖像言缤。
  • classes.dex:包含以Dalvik / ART虛擬機(jī)可理解的DEX文件格式編譯的類嚼蚀。
  • AndroidManifest.xml:包含核心Android清單文件。該文件列出應(yīng)用程序的名稱轧简,版本驰坊,訪問權(quán)限和引用的庫文件。該文件使用Android的二進(jìn)制XML格式哮独。
  • 來看看淘寶APP的unzip之后的文件目錄

一般來講APK結(jié)構(gòu)中比較大的部分一般是classes.dex拳芙、lib、res皮璧、assets這些文件或者目錄舟扎。所以接下來將會(huì)針對這四種情況進(jìn)行講解。

另外悴务,我們通過APK Analyser 可以分析 APK

2.減小 classes.dex

classes.dex 包含了所有 Java 代碼睹限。當(dāng)你編譯你的應(yīng)用時(shí)譬猫,gradle 會(huì)將你的所有模塊里的 .class 文件轉(zhuǎn)換成 .dex 文件并將這些文件合成一個(gè) classes.dex 文件。

單個(gè)的 classes.dex 文件可以容納大約 64K 方法羡疗。如果你達(dá)到了這個(gè)限制染服,你必須要在你的工程中啟用 multidexing。這將會(huì)創(chuàng)建另一個(gè) classes1.dex 文件去存儲(chǔ)剩下的方法叨恨。所以 classes.dex 文件數(shù)目由你的方法數(shù)而定柳刮。

減少第三庫的使用

隨著業(yè)務(wù)的頻繁變更以及復(fù)雜度的增加,我們往往會(huì)使用第三方Libaray痒钝,有時(shí)候我們可能僅僅用到了很少一部分的功能秉颗,這個(gè)時(shí)候就需要慎重考慮完全引用。從我的開發(fā)經(jīng)驗(yàn)上來講送矩,寧愿參照自己去實(shí)現(xiàn)蚕甥,也不愿意多引入一個(gè)第三方庫。

避免枚舉

一個(gè)枚舉可以為您的應(yīng)用程序的classes.dex文件添加大約1.0到1.4 KB的大小 栋荸。這些添加可以快速累積到復(fù)雜系統(tǒng)或共享庫菇怀。如果可能,請考慮使用@IntDef注釋蒸其,這種類型轉(zhuǎn)換保留了枚舉的所有類型安全優(yōu)勢敏释。

使用ProGuard

下面這段來自 build.gradle 文件的代碼用于為發(fā)布構(gòu)建啟用代碼壓縮:

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

除了 minifyEnabled 屬性外,還有用于定義 ProGuard 規(guī)則的 proguardFiles 屬性:

getDefaultProguardFile('proguard-android.txt') 方法可從 Android SDK tools/proguard/ 文件夾獲取默認(rèn)的 ProGuard 設(shè)置摸袁。

提示:要想做進(jìn)一步的代碼壓縮,請嘗試使用位于同一位置的 proguard-android-optimize.txt 文件义屏。它包括相同的 ProGuard 規(guī)則靠汁,但還包括其他在字節(jié)碼一級(方法內(nèi)和方法間)執(zhí)行分析的優(yōu)化,以進(jìn)一步減小 APK 大小和幫助提高其運(yùn)行速度闽铐。

proguard-rules.pro 文件用于添加自定義 ProGuard 規(guī)則蝶怔。默認(rèn)情況下,該文件位于模塊根目錄(build.gradle 文件旁)兄墅。

3.優(yōu)化assets和res中的資源文件

題外話

res/raw和assets的相同點(diǎn):

兩者目錄下的文件在打包后會(huì)原封不動(dòng)的保存在apk包中踢星,不會(huì)被編譯成二進(jìn)制。

res/raw和assets的不同點(diǎn):

  1. res/raw中的文件會(huì)被映射到R.java文件中隙咸,訪問的時(shí)候直接使用資源ID即R.id.filename沐悦;assets文件夾下的文件不會(huì)被映射到R.java中,訪問的時(shí)候需要AssetManager類五督。
  2. res/raw不可以有目錄結(jié)構(gòu)藏否,而assets則可以有目錄結(jié)構(gòu),也就是assets目錄下可以再建立文件夾充包。
  3. 針對不同的情況副签,對于資源文件有不同的優(yōu)化策略。一般來講,對于res/drawable-**ddpi中的png資源可以進(jìn)行壓縮淆储。

3.1 圖片資源優(yōu)化策略

格式壓縮

使用TinyPng或者Guetzli進(jìn)行壓縮冠场。

使用WebP文件格式

定位Android 3.2(API級別13)或更高級別時(shí) ,您也可以使用WebP文件格式來制作圖像本砰,而不是使用PNG或JPEG文件慈鸠。WebP格式提供有損壓縮(如JPEG)以及透明度(如PNG),但可以提供比JPEG或PNG更好的壓縮灌具。

Android 4.0 (API level 14) 支持有損壓縮的WebP格式青团,Android 4.3 (API level 18) 開始支持無損透明WebP圖像。

看下圖:

壓縮效率極高咖楣,僅為PNG格式的12%督笆。驚喜不驚喜。诱贿。娃肿。

使用矢量圖形

您可以使用矢量圖形來創(chuàng)建與分辨率無關(guān)的圖標(biāo)和其他可伸縮媒體。使用這些圖形可以大大減少您的APK足跡珠十。矢量圖像在Android中表示為VectorDrawable對象料扰。通過一個(gè)VectorDrawable對象,一個(gè)100字節(jié)的文件可以生成一個(gè)與屏幕尺寸一致的清晰圖像焙蹭。

但是晒杈,系統(tǒng)渲染每個(gè) VectorDrawable對象需要很長時(shí)間,而較大的圖像需要更長的時(shí)間才能顯示在屏幕上孔厉。因此拯钻,只有在顯示小圖像時(shí)才考慮使用這些矢量圖形。

其它策略

有時(shí)候我們可能對一張圖片進(jìn)行重復(fù)利用,比如一張圖片僅僅是整體顏色的變換可以使用setColorFilter或者tint撰豺。盡量減少使用幀動(dòng)畫粪般,那可是一堆圖片呀。

3.2 壓縮資源

要啟用資源壓縮污桦,請?jiān)?build.gradle 文件中將 shrinkResources 屬性設(shè)置為 true亩歹。

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

資源壓縮器目前不會(huì)移除 values/ 文件夾中定義的資源(例如字符串、尺寸凡橱、樣式和顏色)小作。這是因?yàn)?Android 資源打包工具 (AAPT) 不允許 Gradle 插件為資源指定預(yù)定義版本。

同時(shí)梭纹,我們也可以指定哪些資源可以保留下來躲惰。

例如,將下邊的代碼保存在 res/raw/keep.xml变抽。構(gòu)建不會(huì)將該文件打包到 APK 之中础拨。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
 tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
 tools:discard="@layout/unused2" />

resources有以下屬性:

  • tools:keep 指出哪些資源會(huì)保留
  • tools:discard 指定哪些資源需要剔除
  • tools:shrinkMode 資源壓縮模式,有兩種取值strict和safe,默認(rèn)為safe

safe和strict的優(yōu)化策略:

safe可以簡單理解為安全模式氮块,它會(huì)盡最大努力檢查代碼中可能會(huì)使用到的資源進(jìn)行保留,避免運(yùn)行時(shí)錯(cuò)誤诡宗。

如果你的代碼調(diào)用 Resources.getIdentifier()滔蝉,這就表示你的代碼將根據(jù)動(dòng)態(tài)生成的字符串查詢資源名稱。當(dāng)你執(zhí)行這一調(diào)用時(shí)塔沃,默認(rèn)情況下資源壓縮器會(huì)采取防御性行為蝠引,將所有具有匹配名稱格式的資源標(biāo)記為可能已使用,無法移除蛀柴。

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

img_ 前綴的資源標(biāo)記為已使用螃概。

在strict模式下,img_前綴的資源會(huì)做未使用的處理鸽疾,因此你需要使用tools:keep手動(dòng)進(jìn)行已使用標(biāo)識(shí)吊洼。

移除未使用的備用資源

我們知道google給我們的apk提供了國際化支持,如適應(yīng)不同的屏幕分辨率的drawable資源制肮,還有適應(yīng)不同語言的字符串資源等等冒窍,但是在很多情況下我們只需要一些指定分辨率和語言的資源就可以了,這個(gè)時(shí)候我們可以使用resConfigs方法來配置豺鼻。

defaultConfig {
 // 對于國際化支持只打包中文資源综液,
 resConfigs "zh-rCN"
}

4.lib中資源優(yōu)化

這里我們主要講一下lib中動(dòng)態(tài)鏈接庫的優(yōu)化策略,也就是SO文件儒飒。如果你有NDK的開發(fā)經(jīng)驗(yàn)可能會(huì)更容易理解一些谬莹。

為了支持不同指令集的情況,應(yīng)用可能會(huì)包含armeabi约素、armeabi-v7a届良、x86的SO文件等。

目前主流的機(jī)型都是支持armeabi-v7a的圣猎,并且armeabi-v7a兼容armeabi。所以在一般的開發(fā)中我們只需要使用armeabi-v7a 進(jìn)行ABI支持乞而。

有些SO庫可以采用網(wǎng)絡(luò)下載送悔,把負(fù)擔(dān)放到用戶安裝完應(yīng)用之后。對于哪些SO文件可以放到網(wǎng)絡(luò)中加載爪模,還需要看具體業(yè)務(wù)情況欠啤。

題外話,如果運(yùn)行時(shí)找不到SO的話屋灌,會(huì)導(dǎo)致應(yīng)用崩潰洁段。

java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared
 from loader dalvik.system.PathClassLoader: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 63 more
Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found
at java.lang.Runtime.loadLibrary(Runtime.java:461)
at java.lang.System.loadLibrary(System.java:557)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 5 more

我們也是有辦法應(yīng)對的,可以參見這個(gè)開源項(xiàng)目ReLinker

最后

本文的Android安裝包大小優(yōu)化知識(shí)到此結(jié)束

需要Android系統(tǒng)進(jìn)階視頻資料的共郭,包括Android APP全方位調(diào)優(yōu)祠丝,前沿技術(shù)疾呻,NDK模塊,混合開發(fā)等全方面進(jìn)階視頻資料以及架構(gòu)大綱思維導(dǎo)圖的同學(xué)写半,可以加Android進(jìn)階交流群岸蜗;1005956838。進(jìn)群可免費(fèi)獲取一份最新技術(shù)大綱和Android進(jìn)階資料叠蝇。請備注簡書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末璃岳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子悔捶,更是在濱河造成了極大的恐慌铃慷,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜕该,死亡現(xiàn)場離奇詭異犁柜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蛇损,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門赁温,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淤齐,你說我怎么就攤上這事股囊。” “怎么了更啄?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵稚疹,是天一觀的道長。 經(jīng)常有香客問我祭务,道長内狗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任义锥,我火速辦了婚禮柳沙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拌倍。我一直安慰自己赂鲤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布柱恤。 她就那樣靜靜地躺著数初,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梗顺。 梳的紋絲不亂的頭發(fā)上泡孩,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機(jī)與錄音寺谤,去河邊找鬼仑鸥。 笑死吮播,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锈候。 我是一名探鬼主播薄料,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泵琳!你這毒婦竟也來了摄职?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤获列,失蹤者是張志新(化名)和其女友劉穎谷市,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體击孩,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迫悠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了巩梢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片创泄。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖括蝠,靈堂內(nèi)的尸體忽然破棺而出鞠抑,到底是詐尸還是另有隱情,我是刑警寧澤忌警,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布搁拙,位于F島的核電站,受9級特大地震影響法绵,放射性物質(zhì)發(fā)生泄漏箕速。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一朋譬、第九天 我趴在偏房一處隱蔽的房頂上張望盐茎。 院中可真熱鬧,春花似錦徙赢、人聲如沸庭呜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扶关,卻和暖如春阴汇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背节槐。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工搀庶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拐纱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓哥倔,卻偏偏與公主長得像秸架,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子咆蒿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

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