1. 程式人生 > >Android 安裝包大小優化(Apk瘦身)

Android 安裝包大小優化(Apk瘦身)

目錄

1. 為什麼?

APK越大,在下載安裝過程中,耗費的流量會越多,安裝等待的時間也會越長,安裝包的大小對下載的失敗率也有影響。而對於應用本身,就意味著下載轉化率會越低,在競品中,使用者更願意選擇功能多,體驗號,安裝包最小的應用。因此apk的瘦身優化也很重要。

2. 包體分析

在Android Studio工具欄裡,開啟build–>Analyze APK, 選擇要分析的APK包 

  • res 主要存放圖片資源
  • lib 主要存放so庫,各個cpu架構
  • classes.dex是java原始碼編譯後生成的java位元組碼檔案,因方法限制拆分了多個dex
  • assets 存放不需要編譯處理的檔案
  • resources.arsc是編譯後的二進位制資原始檔,包括圖片,文字索引等
  • META-INF 簽名信息
  • AndroidManifest.xml 描述配置檔案

可以看到佔用空間的主要是程式碼、圖片、資源和lib以及assert檔案。

瘦身的主要方向:精簡程式碼、壓縮圖片、去除無用庫、減少asserts檔案(或大小)。

3. 常用方案

3.1混淆程式碼

程式碼混淆 ProGuard是一個開源的Java程式碼混淆器(obfuscation),並且預設整合到Android SDK中,它具有以下功能:

  • 壓縮:移除無效的類、屬性、方法等。
  • 優化:移除沒用的結構。
  • 混淆:把類名、屬性名、方法名替換為一到兩個字母。

ProGuard常用引數 ProGuard配置引數非常多,以下列出一些常用的引數,具體的引數可參考可參考ProGuard manual

  • 1. ProGuard配置
    • -include {filename}:從給定的檔案中讀取配置引數。
    • -basedirectory {directoryname}:指定基礎目錄為以後對應的檔案名稱。
    • -injars {class_path}:指定要處理的應用程式jar、war、ear和目錄。
    • -outjars {class_path}:指定處理完後要輸出的jar、war、ear和目錄的名稱。
    • -libraryjars {classpath}:指定要處理的應用程式jar、war、ear和目錄所需的程式庫檔案。
    • -dontskipnonpubliclibraryclasses:指定不忽略非公共的庫類。
    • -dontskipnonpubliclibraryclassmembers:指定不忽略包可見的庫類的成員。
  • 2. 保留選項
    • -keep {Modifier} {class_specif ication}:保護指定的類檔案和類的成員。
    • -keepclassmembers {modifier} {class_specification}:保護指定類的成員。
    • -keepclasseswithmembers {class_specif ication}:保護指定的類和類的成員,但條件是所有指定的類和類成員要存在。
    • -keepnames {class_specification}:保護指定的類和類的成員名稱(如果不需要混淆)。
    • -keepclassmembernames {class_specification}:保護指定的類的成員名稱(不需要混淆)。
    • -keepclassmembernames {class_specification}:保護指定的類的成員名稱(不需要混淆)。
    • -keepclasseswithmembernames {class_specification}:保護指定的類和類的成員名稱,如果所有指定的類成員出席(在壓縮步驟之後)。
    • -printseeds {filename}:列出類和類的成員-keep選項的清單,標準輸出到給定的檔案。
  • 3. 壓縮
    • -dontshrink:不壓縮輸入的類檔案。
    • -printusage {filename}:輸出無用檔案。
  • 4. 優化
    • -dontoptimize:不優化輸入的類檔案。
    • -assumenosideeffects {class_specif ication}:優化時假設指定的方法,沒有任何副作用。
    • -allowaccessmodif ication:優化時允許訪問並修改有修飾符的類和類的成員。 (5)混淆
    • -dontobfuscate:不混淆輸入的類檔案。
    • -printmapping {filename}:輸出對映表。
    • -applymapping {filename}:重用對映增加混淆。
    • -obfuscationdictionary {filename}:使用給定檔案中的關鍵字作為要混淆方法的名稱。
    • -overloadaggressively:混淆時應用侵入式過載。
    • -useuniqueclassmembernames:確定統一的混淆類的成員名稱來增加混淆。
    • -renamesourcef ileattribute {string}:設定原始檔中給定的字串常量。

開啟minifyEnabled混淆程式碼

在Android Studio中使用ProGuard

按照上一節的語法規則編寫則編寫proguard-rules.pro後,需要在build.gradle中配置,同時設定minifyEnabled為true,在編譯工程時自動混淆程式碼,可大大減小APP大小,程式碼如下:

minifyEnabled 用開開啟刪除無用程式碼,比如沒有引用到的程式碼

buildTypes {
    debug {
        minifyEnabled false
    }
    release {
        signingConfig signingConfigs.release

        minifyEnabled true
        proguardFiles proguard-rules.pro'
    }
}

3.2 資源優化

3.2.1 使用Android Lint

Android Lint工具可以用來掃描佈局層級,Android Lint也能掃描到沒有使用的資原始檔。

  • 資原始檔最少化

        系統根據不同解析度會自動載入不同圖片資源(ldpi、mdpi、tvdpi、hdpi、xhdpi、xxhdpi等),如果為了適配不同螢幕,每個資料夾都放一套圖,對安裝包大小的影響非常嚴重,雖然Android支援這麼多的螢幕密度,但是不代表應用為每一個螢幕都提供一套資源,在這方面可以參考以下幾個建議:

  •  儘量使用一套圖片資源,遇到一些圖片在不同解析度手機上變化差異過大的情況時,再考慮在相應資料夾下放入這個特定的圖片。
  • 使用一套圖、一套佈局、多套dimens.xml檔案,在使用最小資源的情況下,解決多解析度適配。
  • 減少專案中的預設圖片,預置圖片改成伺服器下發,儘可能將程式與資源分離。
  • 刪除無用so包
    • armable-v7下so包
      • 基本上armble的so也是相容armable-v7的,armable-v7a的庫會對圖形渲染方面有很大的改進,如果沒有這方面的要求,可以精簡。
    • x86包下的so包
      • x86包下的so在x86型號的手機是需要的,如果產品沒用這方面的要求也可以精簡。建議實際工作的配置是隻保留armable、armable-x86下的so檔案,算是一個折中的方案。
    • 刪除無用的語言資源
      • 大部分應用其實不需要支援多種語言的國際化,可以配置gradle的語言,比如國內應用只支援中文。
android {
    defaultConfig {
        resConfigs "zh"
    }
}

3.2.2  清理無用資源

  • Android 工具
    • 使用AndroidStuido -> Refactor -> Remove Unused Resources 篩選出無用的資原始檔

         

  • 避免重複庫   
    • 在應用開發中,比如幾種圖片開源庫,可能一個開源庫不能支援所有業務功能,而需要用到多個開源庫,若一個應用放了兩個圖片庫,不但增加了安裝包大小,也增加了維護成本,此時,建議選擇價效比更高、更適合當前應用業務需求的一個,在這個基礎上增加相應的功能,擴充套件當前的圖片庫,而非引入新的開源庫。 
  • 清理三方庫和冗餘程式碼
    • 版本迭代過程中,因為刪減功能經常有冗餘程式碼和第三方庫留下,這或多或少都會增加包體,這種情況沒有捷徑,只能每個檔案查詢,這是苦力活。還有要檢視第三方庫有沒可能精簡,比如谷歌分基礎、廣告和分析包,網路庫、supportv4等,這個就具體情況具體分析。
    • (比如使用ShareSDK的分享功能,圖示和預設的分享彈窗都沒有用到,引用時可以根據需求刪減)

3.3.3 圖片優化

  • Android應用的資源中主要用到兩種格式的圖片:PNG和JPG。
    • PNG(Portable Network Graphic Format)用來儲存灰度影象時,灰度影象的深度可多到16位,儲存彩色影象時,彩色影象的深度可多到48位,並且可儲存多達16位的透明通道資料。
    • JPG(JPEG)圖片以24位顏色儲存單個位圖。JPEG是與平臺無關的格式,支援最高級別的壓縮,但這種壓縮有損耗,並且沒有透明通道。

在開發Android應用時,PNG資源圖片在應用打包過程中,資源打包工具AAPT(Android Asset Packaging Tool)自動對PNG圖片做壓縮處理,但減小的大小比較有限,除了靠工具自動打包,一般還能採用以下兩種方式。

  •  降低圖片色彩位數 如果使用的圖片色彩比較單一,可以降低影象位數來減少圖片大小。
  • PNG圖片壓縮工具

對於非透明的大圖,JPG檔案會比PNG檔案小很多,通常會減小到一半以上。一般使用於應用中的一些閃屏介紹頁,全圖背景等。

  • 使用tinyPng壓縮
    • TinyPNG工具只支援上傳PNG圖片到官網上壓縮,然後下載儲存,在保持alpha通道的情況下對PNG的壓縮可以達到1/3之內,而且用肉眼基本上分辨不出壓縮的損失.
  • 覆蓋三方庫裡的大圖
    • 有些第三庫裡引用了一些大圖但是實際上並不會被我們用到,就可以考慮用1x1的透明圖片覆蓋。
  • 使用shape背景
    • 特別是在扁平化盛行的當下,很多純色的漸變的圓角的圖片都可以用shape實現,程式碼靈活可控,省去了大量的背景圖片。
  • 使用著色方案
    • 很多圖片相似,只是顏色不同,可以通過著色方案減少圖片的使用。 
  • 使用旋轉方案
    • 很多圖片相似,只是方向不同,可以通過旋轉圖片減少圖片的使用。  

3.4 支援外掛化

外掛化除了可以解決方法數超標的問題,同時如果外掛放到伺服器,在需要時再下載下來,可以減少安裝包大小。但是需要注意的是,因為使用時需要臨時下載,所以建議在使用者使用率不高的功能模組上使用,或者使用預載入。

4. 參考資料