Android 面試準備進行曲(apk瘦身/打包優(yōu)化)v1.0

Android 優(yōu)化 (apk瘦身/打包優(yōu)化)

update time 2019年12月11日14:29:56

該文章為學(xué)習 如下參考文章的 學(xué)習筆記,多有雷同。
參考文章

工程分析

如果真機運行過后,我們可以通過 Android Studio Build -> Analyze APK - > 選擇 app/build/output 下的apk文件 debug 或者 relase 兩個文件夾下的 apk文件。下圖為demo工程的 分析結(jié)構(gòu)圖 (忽略raw 文件為啥那么大 -,-)


在這里插入圖片描述

由上圖可知一個APK主要包含如下文件夾(當然有些文件可能我這個Demo APK沒有包含):

  • res:包含了一些不會被編譯到resources.arsc的資源文件。如drawable文件、layout文件、mipmap文件、anim文件等。

  • lib:包含了一些區(qū)分于處理器的編譯代碼,主要是SO文件,eg:armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, and mips。

  • assets:包含了一些通過AssetManager能夠檢索到的資源。如MP3、字體、webp等資源文件。

  • META-INF:包含了CERT.SF和CERT.RSA簽名文件,還有MANIFEST.MF文件 (因為秘鑰文件 或簽名文件大小不大,所以這里暫時沒有優(yōu)化的點

文件

  • resources.arsc:包括了所有可以被編譯的位于res/values/目錄下的XML資源。打包工具在打包過程中會把XML的內(nèi)容編譯成二進制的形式,亦或者把相關(guān)資源的引用路徑編譯成二進制,然后整合到該文件里面。例如string文件、layout的路徑、圖片的路徑等。
  • classes.dex:包含了所有的Java文件編譯后的class文件,class文件最終轉(zhuǎn)化成該dex文件。一般文件都比較大,有的App有幾個dex文件,這是因為單個DEX文件限制方法數(shù)在65536,所以當代碼量過大時,就需要通過multiDex進行分包,拆分成多個dex文件,解決這個問題。
  • AndroidManifest.xml:如果多module,內(nèi)包含多個module的AndroidMainifest文件的權(quán)限、聲明等配置文件。

瘦身優(yōu)化

Res 目錄優(yōu)化

  1. Android設(shè)備在加載圖片時會優(yōu)先加載對應(yīng)分辨率文件夾下的圖片,如果對應(yīng)分辨率文件下沒有所要的圖片,則找高分辨率對應(yīng)文件夾下的圖片。目前不同分辨率對應(yīng)優(yōu)先加載的文件夾中圖片如下,如果是針對國內(nèi)用戶的App可以只保留xxhdpi目錄(19201080 -> xxhdpi),而如果是東南亞市場的App則可以只保留xhdpi (1280720 -> xhdpi)。

  2. PNG圖片壓縮 (詳細辦法在下一個小節(jié)詳細講述)

  3. lint檢測出無用的資源文件,可以直接在AS里面使用。(Android Studio 打開 Analyze -> Run Inspection by Name -> 輸入:Unused resources ->跳出彈框選擇范圍即可)注意:lint檢查出來的資源都是無直接引用的,所以如果我們通過getIdentifier()方法引用文件時,lint也會標記為無引用,所以刪除時注意不要刪除通過getIdentifier()引用的資源。

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

android {
    buildTypes{
        release {
            // 混淆
            minifyEnabled true
            // 移除無用的資源
            shrinkResources true
        }
    }
}

Andorid PNG圖片壓縮

以PNG資源為例,PNG 圖片相對于 JPEG 圖片來說,它是一種無損的圖像存儲格式,同時多了一條透明度A通道,所以一般情況下,PNG 圖片要比 JPEG 圖片要大,如何縮小圖片所占內(nèi)存大概分為三種辦法(個人推薦度依次遞減):

  1. 將PNG圖片通過 AndroidStudio 轉(zhuǎn)換工具將PNG/PSD圖片轉(zhuǎn)為 SVG圖片 (具體AndroidStudio步驟:右鍵res下的drawable 文件 -> 選擇New ->Vector Asset -> Local file 將本地圖片導(dǎo)入轉(zhuǎn)換為 SVG xml文件)。導(dǎo)入后建議使用 AppCompatImageView 顯示SVG圖片,不過只要依賴 AppCompatActivity ,xml中的imageview 會自動轉(zhuǎn)為 AppCompatImageView 處理(support包中所有含有AppCompat前綴的控件均受相同處理)。

    eg:app:srcCompat="@drawable/svg_ic_arrow_right"

  2. 關(guān)于 PNG 的壓縮算法有很多,這里我們只說兩種比較常用的:Indexed_color 和 Color_quantization。
    Indexed_color :將具體的 ARGB 顏色存儲轉(zhuǎn)換成索引下表,來減少文件的大小。ARGB 中,每個通道的存儲都需要 8 位,也就是 1 字節(jié),一個 ARGB 存儲就需要 4 字節(jié),而索引的存儲只需要 1 字節(jié)。而索引指向的顏色會存放在一個叫 palette(調(diào)色板)的數(shù)組里面。優(yōu)點:減少文件大小 缺點:調(diào)色板的大小通常只支持 4,16,256 所以png的顏色不能超過 256個
    Color_quantization:通過使用相似顏色來減少圖像中使用的顏色種類,再配合調(diào)色板,來達到減少圖片文件大小的目的,這是一種有損的壓縮算法

說完我上述的資源優(yōu)化后(個人觀點),我們簡單的分析一下 AAPT2 打包資源的源碼思路。(6.0源碼)

// Check if image is really grayscale
if (isGrayscale) {
    f (rr != gg || rr != bb) {
        // ==>> Code 1
        isGrayscale = false;
    }
}
// Check if image is really opaque
if (isOpaque) {
    if (aa != 0xff) {
        // ==>> Code 2
        isOpaque = false;
    }
}            
// Check if image is really <= 256 colors
if (isPalette) {
    col = (uint32_t) ((rr << 24) | (gg << 16) | (bb << 8) | aa);
    bool match = false;
    for (idx = 0; idx < num_colors; idx++) {
        if (colors[idx] == col) {
            match = true;
            break;
        }
    }
    if (!match) {
        if (num_colors == 256) {
             // ==>> Code 3
             isPalette = false;
        } else {
             colors[num_colors++] = col;
        }
    }
}              

其實看到源碼中部分的判斷 已經(jīng)知道AAPT2 使用的壓縮為 Indexed_color 方式,通過判斷將 PNG圖片分為四種壓縮方式

  • PNG_COLOR_TYPE_PALETTE
    使用調(diào)色板模式,最終圖片的大小就是 一個像素 1 字節(jié) + 調(diào)色板中一個顏色 4 字節(jié)
  • PNG_COLOR_TYPE_GRAY
    灰度模式,這種是最節(jié)省的模式,一個像素 1 字節(jié)
  • PNG_COLOR_TYPE_GRAY_ALPHA
    灰度模式,同時存在透明通道,一個像素 2 字節(jié)
  • PNG_COLOR_TYPE_RGB
    RGB 模式,刪除了透明通道,一個像素 3 字節(jié)
  • PNG_COLOR_TYPE_RGB_ALPHA
    ARGB 模式,一個像素 4 字節(jié)(沒有壓縮)

在不損壞圖片畫質(zhì)的情況下進行壓縮 也算是比較保險的壓縮方式,當然也可以使用 第三方的一些壓縮方式: pngcrush、pngquant(相對推薦 壓縮后的提及其他人測試會更小一點)、tinypng 這里暫時不展開一一說明了。工具用就完了......

Assests 目錄優(yōu)化

  1. 對于中文字體文件,字體文件包含了好幾千個漢字,但是實際上在App中并不會全部都使用,這時候我們就可以把字體文件進行刪減,在Github上面有一個字體提取工具FontZip,刪除不用的字體文件
  2. 如果Assests下有 mp3、mp4等大的資源,可以再使用到的時候 從服務(wù)端下載緩沖下來。如果不聯(lián)網(wǎng)的話,可以通過7z 、zip 壓縮資源到本地,壓縮 -> 打包 -> 安裝使用 -> 解壓縮

libs 目錄優(yōu)化

Android系統(tǒng)現(xiàn)在支持很多種CPU架構(gòu)(如mips、arm、x86等),市面上主流機型都是arm架構(gòu)。所以可以有選擇地保留某些架構(gòu)的so,從而降低lib文件夾的大小。一般只保留armeabi或者armeabi-v7a即可。操作也是比較簡單,只需要在根目錄的build.gradle下配置:

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

resources.arsc文件壓縮

個人感覺這里的優(yōu)化文件名稱壓縮 收效甚微。部分數(shù)據(jù)看下圖


在這里插入圖片描述

如果應(yīng)用不需要支持多種語言的情況下(只保留zh 國內(nèi)的文字),我們只需要在build.gralde里面進行如下配置即可完成無用語言資源的刪除,這樣在打包的時候就會排除私有項目、android系統(tǒng)庫和第三方庫中非中文的資源文件了,效果還是比較顯著的。

android {
    defaultConfig {
        // 只保留中文
        resConfigs "zh"
    }
}
  1. AndResGuard:縮小APK大小的工具,他的原理類似Java Proguard,但是只針對資源。他會將原本冗長的資源路徑變短,例如將res/drawable/xxxxxxx 變?yōu)?r/d/x。在build.gradle文件中進行如下配置:
andResGuard {
    mappingFile = null
    use7zip = true
    useSign = true
    keepRoot = false
    whiteList = [
        //圖標
        "R.drawable.icon",
        ...
    ]
    compressFilePattern = [
        "*.png",
        "*.jpg",
        "*.jpeg",
        "*.gif",
        "resources.arsc"
    ]
     sevenzip {
         artifact = 'com.tencent.mm:SevenZip:1.1.9'
    }
}

dex壓縮

Dalvik是Android平臺運行時的環(huán)境,但是Dalvik虛擬不支持直接執(zhí)行Java的字節(jié)碼,所以會對編譯生成的 .class 文件進行翻譯、重構(gòu)、解釋、壓縮等處理,這個處理過程是由 dx 進行處理,處理完成后生成的產(chǎn)物會以 .dex 結(jié)尾,稱為Dex文件。如果單個Dalvik Excutable(DEX)字節(jié)碼文件內(nèi)的方法數(shù)不可以超過65536個,所以需要DEX分包配置來避免這個限制,使應(yīng)用能夠構(gòu)建并讀取DEX文件。
這里就推薦 官方提供的優(yōu)化方案:Proguard代碼混淆
在build.gradle里面設(shè)置minifyEnabled為ture,同時在proguardFiles指向proguard的規(guī)則文件即可(如下代碼)。

android {
    buildTypes{
        minifyEnabled true
        proguardFiles 'proguard.cfg'
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容