公司項(xiàng)目在不斷的改版迭代中构捡,代碼在不斷的累加液南,終于apk包不負(fù)重負(fù)了,已經(jīng)到了八十多M了勾徽』梗可能要換種方式表達(dá),到目前為止沒(méi)有正真的往外推過(guò)喘帚,一直在內(nèi)部執(zhí)行7天討論需求畅姊,5天代碼實(shí)現(xiàn)的階段。你在寫(xiě)上個(gè)版本的內(nèi)容吹由,好了若未,下個(gè)版本的更新內(nèi)容已經(jīng)定稿了∏泠辏基于這種快速開(kāi)發(fā)的現(xiàn)狀粗合,我們app優(yōu)化前已經(jīng)有87.1M了,包大了乌昔,運(yùn)營(yíng)說(shuō)這樣轉(zhuǎn)化不高隙疚,只能好好搞一下咯。優(yōu)化過(guò)后包大小為23.1M(優(yōu)化了73%,不要說(shuō)我標(biāo)題黨)磕道。好了好了供屉,我要闡述我的apk超級(jí)無(wú)敵魔鬼瘦身之心得了。
文章主要內(nèi)容從理論出發(fā),再做實(shí)際操作伶丐。分為下面幾個(gè)方面:1. 結(jié)構(gòu)分析悼做, 2.具體實(shí)操 3. 總結(jié) 4. 參考資料
1. 結(jié)構(gòu)分析
首先上傳一張瘦身前通過(guò)Analyze app分析出來(lái)的圖片(打開(kāi)方式:Android Studio下 ——> Build——> Analyze app):
APK包結(jié)構(gòu)如下:
- lib/:包含特定于處理器軟件層的編譯代碼。該目錄包含了每種平臺(tái)的子目錄撵割,像armeabi贿堰,armeabi-v7a, arm64-v8a啡彬,x86羹与,x86_64,和mips庶灿。大多數(shù)情況下我們可以只用一種armeabi-v7a纵搁,后面會(huì)講到原因。
- assets/:包含應(yīng)用可以使用AssetManager對(duì)象檢索的應(yīng)用資源往踢。
- res/:包含未編譯到的資源 resources.arsc,主要有圖片資源文件腾誉。
- META-INF/:包含CERT.SF和 CERT.RSA簽名文件以及MANIFEST.MF 清單文件。
- resources.arsc:包含已編譯的資源峻呕。該文件包含res/values/ 文件夾所有配置中的XML內(nèi)容利职。打包工具提取此XML內(nèi)容,將其編譯為二進(jìn)制格式瘦癌,并將內(nèi)容歸檔猪贪。此內(nèi)容包括語(yǔ)言字符串和樣式,以及直接包含在resources.arsc文件中的內(nèi)容路徑 讯私,例如布局文件和圖像热押。
- classes.dex:包含以Dalvik / ART虛擬機(jī)可理解的DEX文件格式編譯的類。
- AndroidManifest.xml:包含核心Android清單文件斤寇。該文件列出應(yīng)用程序的名稱桶癣,版本,訪問(wèn)權(quán)限和引用的庫(kù)文件娘锁。該文件使用Android的二進(jìn)制XML格式牙寞。
通過(guò)分析圖可以知道,目前app主要是so文件占比比較大莫秆,占了31.7M,占了整個(gè)應(yīng)用是38.2%碎税。其次是assets目錄,整個(gè)目錄占了32M,第三就是資源文件res目錄了馏锡。所以接下來(lái)我們處理步驟就是按這個(gè)順序來(lái)處理雷蹂。(簡(jiǎn)單說(shuō)下圖中的Raw File Size(磁盤解壓后的大小)和DownLoad Size(從應(yīng)用商店下載的大斜馈)匪煌,如果想了解更多關(guān)于Analyaer分析的知識(shí)责蝠,可以參考這篇文章使用APK Analyzer分析你的APK),分析了包結(jié)構(gòu)組成之后萎庭,我們可以開(kāi)始瘦身操作了霜医。
2.具體實(shí)操
1. 對(duì)lib目錄下的文件進(jìn)行瘦身處理
1. 修改lib配置:
參考資料
so文件的優(yōu)化:通常我們?cè)谑褂肗DK開(kāi)發(fā)的時(shí)候,我們經(jīng)常會(huì)有如下這么一段代碼:
ndk {
//設(shè)置支持的so庫(kù)架構(gòu)
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64", "armeabi"
}
最后我的修改代碼如下:
ndk {
//設(shè)置支持的so庫(kù)架構(gòu)
abiFilters "armeabi-v7a"
}
接下來(lái)說(shuō)明這么做的依據(jù):
看上面圖分析驳规,armeabi-v7主要不支持ARMv5(1998年誕生)和ARMv6(2001年誕生).目前這兩款處理器的手機(jī)設(shè)備基本不在我公司的適配范圍(市場(chǎng)占比太少)肴敛。
而許多基于 x86 的設(shè)備也可運(yùn)行 armeabi-v7a 和 armeabi NDK 二進(jìn)制文件。對(duì)于這些設(shè)備吗购,主要 ABI 將是 x86医男,輔助 ABI 是 armeabi-v7a。
最后總結(jié)一點(diǎn):如果適配版本高于4.1版本捻勉,可以直接像我上面這樣寫(xiě)镀梭,當(dāng)然,如果armeabi-v7a不是設(shè)備主要ABI踱启,那么會(huì)在性能上造成一定的影響报账。
參考文章:安卓app打包的時(shí)候還需要兼容armeabi么?
好了埠偿,我們?cè)俅蛞淮伟囋嚒?/p>
確實(shí)有點(diǎn)震驚透罢,一下子包小了這么多,從87.1M到51.9M,容我好好算算少了多少M(fèi).趕快讓測(cè)試幫忙測(cè)一下冠蒋∮鹌裕基于之前的理論知識(shí),心里還是有點(diǎn)底浊服。果然统屈,測(cè)試效果和之前是一樣的胚吁。心里的石頭先落下羅牙躺。
2. 重新編譯so文件,用更小的庫(kù)代替
相信很多開(kāi)發(fā)者都有這種苦惱腕扶,很多第三方我們導(dǎo)入進(jìn)來(lái)只用到其中很小一部分功能孽拷,大部分功能都是我們用不上的。這時(shí)候我們找到源代碼半抱,將我們需要的那部分代碼提取出來(lái)脓恕,重新編譯成新的so文件,再導(dǎo)入到我們項(xiàng)目中窿侈。當(dāng)然炼幔,如果之前沒(méi)有編譯過(guò)so文件,這部分建議做最后的優(yōu)化去處理史简。不然你會(huì)遇到很多問(wèn)題乃秀。上一波處理后的效果圖:
這里說(shuō)下,因?yàn)轫?xiàng)目中有使用到ffmpeg庫(kù),之前導(dǎo)入的第三方的放在assets文件夾下跺讯,重寫(xiě)編寫(xiě)后的so庫(kù)文件放在lib文件夾下枢贿,所以lib文件夾反而大了。從51.9M到35.6M,效果還是蠻不錯(cuò)的刀脏。
對(duì)了局荚,別問(wèn)我為什么assets文件夾下為什么還有12.6M資源,因?yàn)楹芏?mp3都是第三方的人臉識(shí)別必備配置文件愈污,我也很無(wú)奈耀态。
2. 優(yōu)化res,assets文件大小
1. 手動(dòng)lint檢查,手動(dòng)刪除無(wú)用資源
在Android Studio中打開(kāi)“Analyze” 然后選擇"Inspect Code..."钙畔,范圍選擇整個(gè)項(xiàng)目茫陆,然后點(diǎn)擊"OK"。配置如下:
2. 使用tinypng等圖片壓縮工具對(duì)圖片進(jìn)行壓縮擎析。
打開(kāi)網(wǎng)址簿盅,將大圖片導(dǎo)入到tinypng,替換之前的圖片資源揍魂。
3. 大部分圖片使用Webp格式代替桨醋。
可以給UI提要求,讓他們將圖片資源設(shè)置為Webp格式现斋,這樣的話圖片資源會(huì)小很多喜最。如果想了解更多關(guān)于webp,請(qǐng)點(diǎn)擊這里webp,當(dāng)然庄蹋,如果對(duì)圖片顏色通道要求不高瞬内,可以考慮轉(zhuǎn)jpg,最好用webp,因?yàn)樾Ч选?/p>
4. 盡量不要在項(xiàng)目中使用幀動(dòng)畫(huà)
一個(gè)幀動(dòng)畫(huà)幾十張圖片,再怎么壓縮都還是占很大內(nèi)存比重的限书。所以建議是讓UI去搞虫蝶,這里可以參考使用lottie-android,如果項(xiàng)目中動(dòng)畫(huà)效果多的話效果更加明顯倦西。當(dāng)然這就要辛苦我們UI設(shè)計(jì)師大大了能真。
5. 使用gradle開(kāi)啟shrinkResources
移除無(wú)用資源文件,下面是我的配置:
buildTypes {
release {
// 不顯示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
// 移除無(wú)用的resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
通過(guò)上述步驟操作扰柠,apk效果如下:
又優(yōu)化了將近5M,別問(wèn)我為什么還有7.5M粉铐,里面大量的gif和webp格式的動(dòng)圖,都是UI丟給我的卤档,一個(gè)2.7M.后面再慢慢和他細(xì)究這個(gè)問(wèn)題蝙泼。后面要做的兩部分,一部分是將資源文件下的所有g(shù)if圖放后臺(tái)下載處理劝枣,第二個(gè)是和UI討論下如何減小webp 動(dòng)圖的大刑捞ぁ(我看其他平臺(tái)只有100K的樣子倡缠,給我的就2.7M?)。
3. 減少chasses.dex大小
classes.dex中包含了所有的java代碼茎活,當(dāng)你打包時(shí)昙沦,gradle會(huì)將所有模板力的.class文件轉(zhuǎn)換成classes.dex文件,當(dāng)然载荔,如果方法數(shù)超過(guò)64K盾饮,將要新增其他文件進(jìn)行存儲(chǔ)±廖酰可以通過(guò)multidexing分多個(gè)文件丘损,比如我這里的chasses2.dex。換句話說(shuō)工扎,就是減少代碼量徘钥。我們可以通過(guò)以下方法來(lái)實(shí)現(xiàn):
- 盡量減少第三方庫(kù)的引用,這個(gè)在上面我們已經(jīng)做過(guò)優(yōu)化了肢娘。
- 避免使用枚舉呈础,這里特別去網(wǎng)上查了一下,具體可以參考下這篇文章Android 中的 Enum 到底占多少內(nèi)存橱健?該如何用而钞?,得出的結(jié)論是拘荡,可能幾十個(gè)枚舉的內(nèi)存占有量才相當(dāng)一張圖片這樣子臼节,優(yōu)化效果也不會(huì)特別明顯。當(dāng)然珊皿,如果你是個(gè)追求極致的人网缝,我不反對(duì)你用靜態(tài)常量替代枚舉。
- 如果你的dex文件太大蟋定,檢查是否引入了重復(fù)功能的第三方庫(kù)(圖片加載庫(kù)粉臊,glide,picasso,fresco,image_loader,如果不是你一個(gè)人單獨(dú)開(kāi)發(fā)完成的很容易出現(xiàn)這種情況)溢吻,盡量做到一個(gè)功能點(diǎn)一個(gè)庫(kù)解決维费。
關(guān)于classes.dex文件大小分析可以參考這篇譯文使用 APK Analyzer 分析你的 APK
4. 其他
- 用7zip代替壓縮資源果元。
- 刪除翻譯資源促王,只保留中英文
- 嘗試將andorid support庫(kù)徹底踢出你的項(xiàng)目。
- 嘗試使用動(dòng)態(tài)加載so庫(kù)文件而晒,插件化開(kāi)發(fā)蝇狼。
- 將大資源文件放到服務(wù)端,啟動(dòng)后自動(dòng)下載使用倡怎。
3. 總結(jié)
好了迅耘,說(shuō)道這里基本上就結(jié)束了贱枣,apk包從87.1M減小到了23.1M(優(yōu)化了73%,不要說(shuō)我標(biāo)題黨)已經(jīng)差不多了,關(guān)于第四部其他部分的優(yōu)化我是沒(méi)有進(jìn)行再操作的颤专。因?yàn)楣具\(yùn)營(yíng)覺(jué)得二三十M的包比較真實(shí)纽哥,太小了就太假了。所以我暫時(shí)就不進(jìn)行優(yōu)化了栖秕。如果再上面提到的部分通過(guò)所有將所有非啟動(dòng)頁(yè)面首頁(yè)之外的所有資源春塌,so庫(kù)放服務(wù)端,理論上apk包大小能在10M以內(nèi)這樣子簇捍。當(dāng)然我們有做到就不多加評(píng)價(jià)了只壳。最后,如果對(duì)插件化開(kāi)發(fā)感興趣的話可以參考下這篇文章Android全面插件化方案-RePlugin踩坑暑塑。最后吼句,如果你在Android上有什么疑問(wèn),可以添加我的同名微信公眾號(hào)aserbao和我一塊交流事格。
個(gè)人微信 | 公眾號(hào) | 微信交流群過(guò)期請(qǐng)點(diǎn)擊這里 |
---|---|---|
文章本來(lái)是周三的差不多的惕艳,到今天才發(fā),還是有點(diǎn)小偷懶了驹愚。最后祝大家五一快樂(lè)尔艇,出門玩的開(kāi)心。如果你看到了這里么鹤,覺(jué)得文章寫(xiě)得不錯(cuò)就給個(gè)贊唄终娃?如果你覺(jué)得那里值得改進(jìn)的,請(qǐng)給我留言蒸甜。一定會(huì)認(rèn)真查詢棠耕,修正不足。謝謝柠新。
4. 參考資料:
文章主要參考文章如下窍荧,文章有少部分文字參考了下面文章中的語(yǔ)句。如果有侵犯到作者權(quán)益恨憎,請(qǐng)和我聯(lián)系蕊退,查實(shí)后馬上刪除。