APK瘦身-是時候給App進行減負了


前言

APK瘦身即是對APK大小進行壓縮策略,減小APK安裝包大小,更小的安裝包更有助於吸引用戶安裝。前一段時間我司某一App進行APK的瘦身,最終也達到了減小10M的目標,現做一個簡單的總結記錄。

如何着手這個問題?

需要對一個App進行瘦身,首先最重要的就是對App大小有一個大致的了解,最直觀看到App的大小就是通過Android Studio自帶的Analyzer進行APK的分析。使用方法:

1、將一個apk拖動到Android Studio的編輯器窗口 
2、在Project窗口中,雙擊build/output/apks/目錄下的apk 
3、在菜單欄中選擇選擇Build > Analyze APK,然后選擇要分析的apk

圖1

獲取如上圖1所示的APK Size分析圖之后,我們就可以針對這里面的目錄進行針對性的優化。

如圖最上方所示的APK Size就是我們應用打包之后的大小,Download Size則是上傳到Google Play之后,用戶下載的大小。所以我們一般可以只針對前一項的APK Size進行對比。

分析問題,發掘優化點

從上圖Analyzer可以發現,一個APK主要包含如下目錄:

  • lib:包含了一些區分於處理器的編譯代碼,主要是SO文件,一般里面包含很多子目錄,例如armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, and mips。
  • res:包含了一些不會被編譯到resources.arsc的資源文件。如drawable文件、layout文件等。
  • assets:包含了一些通過AssetManager能夠檢索到的資源。如MP3、字體、webp等資源文件。
  • META-INF:包含了CERT.SF和CERT.RSA簽名文件,還有MANIFEST.MF文件。

除此之外,還包含了如下的文件:

  • resources.arsc:包括了所有可以被編譯的位於res/values/目錄下的XML資源。打包工具在打包過程中會把XML的內容編譯成二進制的形式,亦或者把相關資源的引用路徑編譯成二進制,然后整合到該文件里面。例如string文件、layout的路徑、圖片的路徑等。

  • classes.dex:包含了所有的Java文件編譯后的class文件,class文件最終轉化成該dex文件。一般文件都比較大,有的App有幾個dex文件,這是因為單個DEX文件限制方法數在65536,所以當代碼量過大時,就需要通過multiDex進行分包,拆分成多個dex文件,解決這個問題。

  • AndroidManifest.xml:整合了多個module的AndroidMainifest文件的權限、聲明等配置到該文件。

知道了APK的組成部分,那么我們就可以針對這些文件/文件夾進行針對性的優化,每個App都不一樣,但是方法都是大同小異,本文講述瘦身策略也是針對這些目錄和文件進行優化,這樣可以顯得更加有條理性。

1. lib目錄優化

Android系統現在支持7種CPU架構,每一種都關聯着對應的ABI(二進制接口,Application Binary Interface),而每一種ABI都定義了二進制文件(尤其是.so文件)如何運行在相應的系統平台上,從使用的指令集,內存對齊到可用的系統函數庫等。所以如果我們的App需要適配不同的CPU架構的話,如下圖2所示,就需要放入不同架構的文件夾下都放入不同的so文件,在打包時,這些so都會放在lib目錄下。由此,如果我們想減小lib目錄的大小,無非就如下一些常見的策略。

圖2

  • so裁剪、刪除

對App引入的so文件進行確認哪些是不需要的,哪些是可以進行裁剪壓縮的,哪些是可以避免引入的。例如如果引入的so需要下載上傳功能而多引入了一個cURL庫導致so增大,這時就可以讓Java層代碼定義接口,讓so來調用,從而避免引入cURL庫;再如Fresco庫,如果不需要webP圖,或者不需要webP動圖功能,然后減少Fresco庫的依賴,同樣可以減小so的大小。

  • 只保留armeabi或者armeabi-v7a

Android系統現在支持很多種CPU架構(如mips、arm、x86等),市面上主流機型都是arm架構,x86和mips類型極少。所以可以有選擇地保留某些架構的so,從而降低lib文件夾的大小。但是我建議你在開始前先對用戶手機的cpu型號進行一次統計,分析自身App對應架構手機的占有率,這樣你才能大膽的進行操作,一般只保留armeabi或者armeabi-v7a即可。操作也是比較簡單,只需要在根目錄的build.gradle下配置:

android {
    buildTypes {
        ndk {
            abiFilters "armeabi-v7a"
        }
    }
}

如果你的App需要支持多種架構,那么就可以在abiFilters里面把多種架構加進去,當然你也可以只保留一種,然后分渠道打包,如Google Play就支持arm和x86等多個渠道打包。

2.res目錄優化

res目錄一般也是占APK Size大頭的一個目錄,如下圖,這個目錄一般都是圖片資源占空間比較多,尤其當App為了適配多種分辨率而存放了多套圖時,這時候就會導致res目錄打下會非常大。而這個目錄的優化方式也是比較多,下面就簡單列舉一下:

圖3

  • 只保留一套圖

因為Android設備在加載圖片時會優先加載對應分辨率文件夾下的圖片,如果對應分辨率文件下沒有所要的圖片,則找高分辨率對應文件夾下的圖片。那是不是我們把圖片放在最高分辨率的文件夾下就可以了呢?不是的!因為如果這樣會導致低分辨率手機加載圖片時會消耗更多的內存,而且是指數級別增長的,所以如果盲目地放在一個目錄是不合適的。目前不同分辨率對應優先加載的文件夾中圖片如下,如果是針對國內用戶的App可以只保留xxhdpi目錄,而如果是東南亞市場的App則可以只保留xhdpi。

320*240        ldpi

480*320        mdpi

800*480        hdpi

1280*720       xhdpi

1920*1080      xxhdpi
  • 非重要圖片動態加載

針對一些非重要的圖片,可以選擇動態在線加載,嚴格來說,非首頁的圖片都可以動態加載,當然,為了提升用戶體驗,我們會把圖片放在本地。但是,一些使用場景非常小或者大小較大的圖片,大膽刪掉,選擇動態加載吧!

  • 保真壓縮圖片

可以使用一些圖片壓縮網站或者工具壓縮你的資源文件吧,例如TinyPng、ImageOptim、Zopfli、智圖等。

  • 使用webp替換png

如果你的App只支持Android4.0以上的話,可以把png格式的圖片轉為webp,相同畫質下體積更小。

  • 使用lint刪除無用資源

在多人開發過程中,通常都會有漏刪無用資源的問題,圖片資源也不例外,例如需要刪除一個模塊的代碼時,很容易就會漏刪資源文件,所以可以定期使用lint檢測出無用的資源文件,原理這里不作介紹,使用方法非常簡單,可以直接在AS里面使用,如下圖所示。注意:lint檢查出來的資源都是無直接引用的,所以如果我們通過getIdentifier()方法引用文件時,lint也會標記為無引用,所以刪除時注意不要刪除通過getIdentifier()引用的資源。

Analyze -> Run Inspection by Name -> 輸入:Unused resources -> 跳出彈框選擇范圍即可
  • 打開shrinkResources

shrinkResources是在編譯過程中用來檢測並刪除無用資源文件,也就是沒有引用的資源,minifyEnabled 這個是用來開啟刪除無用代碼,比如沒有引用到的代碼,所以如果需要知道資源是否被引用就要配合minifyEnabled使用,只有兩者都為true時才會起到真正的刪除無效代碼和無引用資源的目的。打開方式也是非常簡單,在build.gralde文件里面打開即可:

android {
    buildTypes{
        minifyEnabled true
        shrinkResources true
    }
}

3.assests目錄優化

assests目錄存放的通常是一些通過AssetManager能夠檢索到的資源,包括MP3、視頻、字體、webp的資源,各個App存放內容都很大不相同,列舉一些常用的優化方案。

  • 刪除無用字體

中文字體一般都比較大,因為字體文件包含了中文好幾千個漢字,但是我們實際上在App中並不會全部都使用,甚至我們只用到其中的幾個字,這時候我們就可以把字體文件進行刪減,在Github上面有一個字體提取工具FontZip,使用方法也是非常簡單,有興趣可以去star一下。

圖4

  • 動態下載

一些MP3、視頻、Webp等資源可以在使用到時再進行下載,不需要放在本地。

  • 對資源進行壓縮

一些MP3、視頻、Webp等資源如果必須放在本地,可以壓縮成zip文件或者使用7zip進行壓縮,在使用到時再進行解壓,減小空間的占用。

4.META-INF目錄

該目錄下的MANIFEST.MF、CERT.SF、INDEX.LIST、CERT.RSA等文件主要是存放一些APK文件加密后的信息,用以校驗APK的完整性和安全性,這個目錄沒有太好的優化方式,而且文件一般也比較小,不會超過1M。

5.resources.arsc文件壓縮

這個文件包含所有可以被編譯的位於res/values/目錄下的XML資源,如下圖5所示是淘寶APK的resources.arsc文件,像圖片的引用名字、layout文件的引用名字、string資源等都被編譯到了這個文件里面。

圖5

所以如果我們需要對resources.arsc文件進行優化,無非就是對路徑名字進行混淆,刪除無用的資源映射,前者可以使用AndResGuard,后者可以使用lint等進行檢測。

  • 刪除無用的語言

大部分應用都不需要支持幾十種上百種語言,所以在我們引用一些第三方庫時(如Google、Facebook的庫),它們往往帶有上百種多語言資源,而大部分多語言對於我們自己的應用是沒有用處的,我們只需要在build.gralde里面進行如下配置即可完成無用語言資源的刪除,這樣在打包的時候就會排除私有項目、android系統庫和第三方庫中非中文的資源文件了,效果還是比較顯著的。

android {
    //...
    defaultConfig {
        // 只保留中文
        resConfigs "zh"
    }
}
  • 使用AndResGuard壓縮

AndResGuard是一個幫助你縮小APK大小的工具,他的原理類似Java Proguard,但是只針對資源。他會將原本冗長的資源路徑變短,例如將res/drawable/wechat變為r/d/a。詳細使用方法參照Github,很簡單有效地減小resources.arsc文件大小。如下圖6和圖7所示,圖6是壓縮前的效果,圖7是壓縮完的效果,如果是資源比較多的App,壓縮效果也是立竿見影。

圖6
圖7

使用方法也是非常簡單,在build.gradle文件中進行如下配置即可:

andResGuard {
    mappingFile = null
    use7zip = true
    useSign = true
    keepRoot = false
    whiteList = [
        //for your icon
        "R.drawable.icon",
        //for fabric
        "R.string.com.crashlytics.*",
        //for umeng update
        "R.string.umeng*",
        "R.string.UM*",
        "R.layout.umeng*",
        "R.drawable.umeng*",
        //umeng share for sina
        "R.drawable.sina*"
    ]
    compressFilePattern = [
        "*.png",
        "*.jpg",
        "*.jpeg",
        "*.gif",
        "resources.arsc"
    ]
     sevenzip {
         artifact = 'com.tencent.mm:SevenZip:1.1.9'
         //path = "/usr/local/bin/7za"
    }
}

6.dex文件壓縮

Dalvik是Android平台運行時的環境,但是Dalvik虛擬不支持直接執行Java的字節碼,所以會對編譯生成的 .class 文件進行翻譯、重構、解釋、壓縮等處理,這個處理過程是由 dx 進行處理,處理完成后生成的產物會以 .dex 結尾,稱為Dex文件。

像淘寶、微信這些App,如果我們分析它們的APK可以發現,它們有多個Dex文件,如下圖8所示,這是因為單個Dalvik Excutable(DEX)字節碼文件內的方法數不可以超過65536個,所以需要DEX分包配置來避免這個限制,使應用能夠構建並讀取DEX文件。

圖8

  • Proguard代碼混淆

Proguard是一款免費的Java類文件壓縮器、優化器和混淆器,Android Studio已經集成了這個工具,只要經過簡單的配置,即可完成,如下代碼所示,在build.gradle里面設置minifyEnabled 為ture,同時在proguardFiles指向proguard的規則文件即可。

android {
    buildTypes{
        minifyEnabled true
        proguardFiles 'proguard.cfg'
    }
}

總結

App瘦身是一個長期的過程,建議可以進行每個版本對APK大小進行監控,列出增加和減小的點,做到持續的統計和追蹤,從而給公司帶來效益。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM