天天看點

Android APK瘦身實踐

因為推廣的需要,公司需要把apk的大小再“減小”一下,4m以内!

當達到4m以内之後,公司建議說,能否再壓壓?2m如何?

瘦身前

因為平時就考慮到大小的限制,是以很多工作已經做過了,如下列舉現在的狀态:

7.3m(debug版本)和6.5m(release版本)

開啟minifyenabled

開啟shrinkresources

已經去除不相關的大型庫

圖檔和代碼已經經曆過粗略的一輪清理

開始魔鬼瘦身

1. tinypng有損壓縮

android打包本身會對png進行無損壓縮,不信大家可以看看apk中的圖檔的大小實際上比你代碼工程裡的圖檔要小(針對沒進行過無損壓縮的那些png圖)。

是以,純粹的進行無損壓縮并不會對apk的減小有任何效果,這是我特别想在這裡強調的一個經驗。

現在大家主流的比較喜歡用的tinypng其實是有損壓縮:

https://tinypng.com/

[原文] tinypng uses smart lossy compression techniques to reduce the file size of your png files…

[翻譯] tinypng使用智能有損壓縮技術,來減少png檔案的大小…

通過tinypng确實能在盡量少的損失下再減小apk,如果圖檔資源多或者大的話,效果還是很明顯的。

具體減少多少,因為這個處理過程我們是間隔做的,無法準确給出結果,就按200k~500k算吧。

2. png換成jpg

經驗發現,一些背景,啟動頁,宣傳頁的png圖檔比較大,這些圖檔圖形比較複雜,如果轉用有損jpg可能隻有不到一半(當然是有損,不過通過設定壓縮參數可以這種損失比較小到忽略)。

因為都是大圖,是以這種方式能有效減小apk的大小。

這種情況下的apk的減小是不可估量的。

3. jpg換成webp

如果png大圖轉成jpg還是很大,或者想壓的更小,而盡量不降低畫質,那麼可以考慮一下webp。

android 4.0+才原生支援webp, 但是我們的app是相容2.3+,是以4.0以下的裝置将無法看到圖檔。

考慮到我們4.0以下的所有裝置比例之和大約在0.44%,非常少

4.0以下的裝置不會崩潰

我們選擇不對4.0以下做webp相容處理,不顯示就不顯示。否則,要引入webp相關so檔案增大apk大小。

通過把下面四張大圖換成webp,webp的quality參數按50配置(據說官方評測75是最佳值),清晰度勉強可以接受,這個值大家具體按産品要求來定。

Android APK瘦身實踐
Android APK瘦身實踐

其中安裝jpg轉webp工具:

brew install webp 

轉換指令如下

cwebp -q input.jpg output.webp// example:cwebp -q 50 a.jpg a.webp 

更多下載下傳:https://developers.google.com/speed/webp/docs/precompiled

最終,apk減小了188k。

4. 大圖縮小

如果經過上面的步驟,依然存在大圖的話,說明确實圖有點大了,可能真的有點大了!

是以,要考慮的問題是,是否有必要保證如此的大小?能否縮小?

如果這方面能減小的話,apk瘦身的效果必然又會上一個檔次。

5. 覆寫aar裡的一些預設的大圖

一些aar庫裡面包含根本就沒有用的圖。最典型的是support-v4相容庫中包含一些“可能”用到的圖檔,實際上在你的app中不會用到。

Android APK瘦身實踐

我沒有把所有圖都替換掉,隻是把幾張大一點點的圖(選中的那些圖)用1×1的圖檔替換,如果9patch圖的話,要做成3×3的9patch圖替換。

support庫可能還算好的,就怕有些庫引用了一些大圖而不自知,可以在/build/intermediates/exploded-aar/下的各個aar庫的res目錄查找檢驗。

apk減小了18k。

6. 删除armable-v7包的so

感謝@楊輝__ ,@kymjs張濤的提醒,armable-v7和armable檔案夾可以隻保留armable。

當然,armable-v7a的庫會對圖形渲染方面有很大的改進,因為我們主要是一些業務上動态庫,是以删掉無大礙。

Android APK瘦身實踐

apk減小了191k。

7. 微信資源壓縮打包

這個方案網上一直在說,之前一直沒有需求或者動力實踐,在這裡感謝一下@裸奔的凱子哥的推薦和交流,他那邊的apk可以壓小1m,效果還是比較驚人的。

這個步驟我是在後面很多步壓縮之後測試的,每個階段的壓縮結果都會有些許出入,是以資料僅供參考。

通過正常壓縮,apk包減小了464k。

如果開啟7zip,apk包減小了594k。

apk減小了594k。

ps: 關于這個壓縮,我內建到了gradle腳本中了,建立了一個task,大概代碼如下:

task compressreleaseapp { 

    // 在現有release的版本上生成到compressed目錄下 

    def appid = "appid" 

    def channel = "abcdefghijkl" 

    def guardjarfile = file('../andresguard/andresguard-1.1.jar') 

    def guardconfigfile = file('../andresguard/config.xml') 

    def originapkfile = file("../app.${appid}/build/outputs/apk/release/${appid}-release-${rootproject.ext.versionname}-${rootproject.ext.versioncode}-${channel}.apk") 

    def outputdir = file("../app.${appid}/build/outputs/apk/compressed/") 

    def keystorefile = file(release_store_file) 

    // 開始執行壓縮指令 

    def proc = "java -jar ${guardjarfile} ${originapkfile} -config ${guardconfigfile} -out ${outputdir} -signature ${keystorefile} ${release_store_password} ${release_key_password} ${release_key_alias}".execute(); 

    proc.waitfor(); 

    println "return code: ${ proc.exitvalue()}" + ", stderr: ${proc.err.text}" + " stdout: ${proc.in.text}" 

config開啟了7zip, 部配置設定置如下:

<?xml version="1.0" encoding="utf-8"?> 

<resproguard> 

    <!--defaut property to set  --> 

    <issue id="property" > 

        <seventzip value= "true" /> 

        <!--  ...  --> 

    </issue> 

    <issue id="whitelist" isactive="true"> 

        <path value ="com.xxx.yyy.r.drawable.emoji_*" /> 

        <path value ="com.xxx.yyy.... /> 

    <issue id ="compress" isactive="true"> 

</resproguard>  

詳情參考:https://github.com/shwenzhang/andresguard

原理介紹:

http://mp.weixin.qq.com/s?__biz=mzawndy1ody2oq==&mid=208135658&idx=1&sn=ac9bd6b4927e9e82f9fa14e396183a8f#rd

8. proguard深度混淆代碼

之前為了簡單起見,很多包都直接忽略了,現在啟動嚴格模式,把能混淆的都混淆了:

Android APK瘦身實踐

采用微信壓縮方案最終效果比較:

Android APK瘦身實踐

apk減小了215k。

ps:混淆後,一定要經過嚴格測試,有時候甚至很難發現錯誤,比如我開啟嚴格混淆,用了一段時間之後慢慢發現了兩個bug,排除了兩個包程式才正常。

9. 深度清理代碼和資源

有意思的是,無論何時何地去清理代碼和資源,總能有新的發現:

新發現或者新引入的無用圖檔

這幾張圖怎麼一樣

這個類好像沒有用

沒用的類相關的圖檔也沒用

有些圖檔可以用着色方案替換

有些圖檔可以用shape來代替

hdpi裡的ic_luancher.png好像也可以删掉

apk減小了66k。

10. proguard去符号表

之前為了保留調試資訊,我們是在proguard保留了符号表的:

-keepattributes sourcefile,linenumbertable

官方管道我覺得還是盡量保留這個,現在針對推廣管道,隻能采用特殊手段,注釋這一行。

apk減小了230k。

ps:以後友盟上看推廣管道的bug要辛苦一點,手動上傳mapping.txt了。

11. provided關鍵字

可以對僅在運作時需要的庫設定provided關鍵字,實際并不被打包:

provided 'com.android.support:support-annotations:22.0.0' 

我沒有發現這樣的場景,如果說有的話,就是support-annotations,但是經過後來的測試驗證,support-annotations本來就會在release版本中被minifyenabled掉,是以對support-annotations設定provided是沒有意義的。

如果有實際場景,歡迎留言說明,不甚感激。

apk沒有減小。

12. 表情包線上化

雖然應用的表情不多,隻有50來個,但是如果能把這部分表情放到網上,不僅能有效減小apk大小,還可以友善後期擴充支援:

Android APK瘦身實踐

打包成emoji_v1.zip, 大小是202k。

現在把emoji_v1.zip放到網上,按需下載下傳後使用,最終對比結果如下:

Android APK瘦身實踐

apk減小了193k。

13. 全版本相容的着色方案

考慮着色方案主要目的是更友善支援多主題,減輕ui工作量,減少工程裡一大堆selector檔案等,然後才是,順便的減小一下apk大小。

通過着色方案,我們去除了10多張純色的按下狀态圖檔和對應的xml等等。

apk減小了15k。

ps: 具體實作可以參考 http://www.race604.com/tint-drawable/ ,而我也把它內建到了我的lesscode庫中了:drawableless.java:https://github.com/openproject/lesscode/blob/master/lesscode-core/src/main/java/com/jayfeng/lesscode/core/drawableless.java

14. 去除重複庫

發現兩個地方:

現在發現七牛的sdk引用了android-async-http-1.4.6.jar,雖然不大,隻有95.4k,但是感覺完全可以寫一個輕量級的jar,控制在10~20k就足夠了,具體可以在現有的網絡庫上實作。

自己工程使用的是uil,但是引入的第三方庫引用了picasso,兩個重複的圖檔下載下傳庫也是完全沒用必要的。

現在還沒有處理這塊,新任務介入,延期優化,敬請期待。

15. 去除無用庫

這是一個很基本的點,但是确很容易被人忽視,當你仔細回顧的時候,有一些雞肋的功能或者庫,是幾無用處的。不如幹脆去掉。

比如,在很早的時候,我就把我們app裡的sharesdk删除了,因為對于我們的産品定位和推廣來看,這毫無意義。

16. 去除百度統計

這個視具體情況決定。

因為我們的app裡面包含友盟和百度兩套統計系統,早期老闆要求,事實上後面已經很少看這方面的資料,百度統計的資料幾乎沒用人去看,可以暫時先去除。

原本的百度統計的jar有130多k,去除之後的apk的減小會遠遠沒有這麼多。

apk減小了20k。

17. 使用更小的庫

使用更小的庫不應該成為你選擇方案的決定性因素,但是可以作為參考因素(freso确實太大了,這個大小也可以成為決定性因素)。

圖檔下載下傳,網絡請求,json解析等等的庫和它的競品都有多大,你心裡有數嗎?

以工具庫為例,網上有很多工具庫,但是往往它們的大小很難控制。

xutils-3.2.6.aar – 843.8k

lite-common-1.1.3.jar – 148.1k

lesscode-core-0.8.2.aar – 64k

上面最後一個庫lesscode是我自己收集的工具類集合,非常小:lesscode,混淆後隻有不到50k大小。

不僅提高了開發效率,減少了備援代碼,而且能避免引用一些其他大型的庫,有效避免包的增大。

比如,我們碰到過這樣的一個bug,快速點選按鈕多次觸發跳轉,現在rxjava結合rxbind有這樣的一個場景解決方案,如果引入這些庫的話必然會增大apk大小,實際上就幾行代碼,我把這樣的解決方案內建到了lesscode,下次别的項目碰到這樣的問題不用再猶豫是否要引入一個這麼大的庫了。

這些小的工具庫,建議根據自己的經驗人手總結一個,不求全,但求精!

18. 插件化

尴尬的是,我們所呈現的功能大部分都是重要的不可分割的功能,很難從業務上分離出來。

今年預計要實踐一個輕量級的插件化方案,用别人的也好,自己寫也好,希望能解決或者優化一些安裝包加載多子產品,或者主題切換,或者熱修複的問題。

這裡作為候選方案備用。

19. 功能業務取舍

一開始考慮瘦身,上司是允許适當的砍掉一些功能,因為4m的目标我們已經實作了,是以現在還沒有到砍功能的地步。

補充

文章發出後,收到了一些朋友的建議,補充幾點。

1. 去除無用的語言資源

感謝@牧志軒的建議,通過配置resconfigs可以選擇隻打包哪幾種語言,進而去掉各種aar包中全世界的語言,尤其是support包中的。

Android APK瘦身實踐

選擇保留什麼語言要根據産品的使用者和市場來定,如果隻選擇預設英語和中文語言,配置如下

android { 

    defaultconfig { 

        resconfigs "zh" 

    } 

}  

看看效果:

Android APK瘦身實踐

如果不采用微信壓縮方案結果對比,apk減小了197k。

如果采用微信壓縮(開啟7zip)對比結果,apk隻減小了16k,因為微信對resources.arsc進行了強力壓縮,厲害!

apk減小了16k。

2. 删除x86包的so

再次感謝@楊輝__的建議,x86的包删除了之後,測試反應好像有些機器容易崩潰,未能經過嚴格測試,是以主版本又複原了,隻在個别管道執行這條措施。

一般情況下不會有問題,測試了一下效果,apk減小了78k。

小結

最終,我們成功的把apk壓到了2.9m,如果把上面遺漏的步驟繼續再做,應該還能再減小一點。

客戶反應壓的好小,上司簡直不敢相信~

瘦身不難,難的是魔鬼瘦身!

本文作者:佚名

來源:51cto

繼續閱讀