1. 程式人生 > >Android開發之減小APK大小

Android開發之減小APK大小

1.前言:

APK的大小對APP的載入速度,使用記憶體大小和消耗功率多少有一定影響。如何減小APK的大小對於Android開發者是一個永恆的話題。查閱了很多相關資料,並將其做了刪減以及總結,首先就來了解一下APK的組成結構。

2.APK組成結構:

META-INF:包含CERT.SF和CERT.RSA簽名信息。

assets:存放不需要被編譯處理的檔案,程式碼中可以通過AssetManager物件訪問。

res:包含沒有被編譯到resources.arsc中的資源。

lib:包含各個CPU架構下的so檔案。子檔案目錄有armeabi,armeabi-v7a,arm64-v8a,x86,x86_64和mips。

resources.arsc:編譯後的二進位制資原始檔。包括圖片、佈局檔案等。

classes.dex:包含Java原始碼編譯後生成的位元組碼檔案,以DalvikART虛擬機器能理解的dex檔案格式。

AndroidManifest.xml:核心的Android描述清單檔案。這個檔案羅列了APP名稱,版本,訪問許可權,和APP引用的庫檔案等等。

3.減小APK的大小的方式彙總:

3.1 Lint工具:

使用Android Lint工具,檢測res目錄下沒有被引用的資源(並沒有掃描assets目錄下的資源)。

   當lint工具在你的專案中發現一個潛在的未使用的資源,它會列印一條如下示例的訊息。只提醒,不主動移除。

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]  

3.2 使用Gradle的ShrinkResources:

在Gradle中將shrinkResources和minifyEnabled設定為true。這樣在構建的過程中,首先ProGuard會移除沒有使用的程式碼,接著Gradle會移除沒有使用的資源

android{   
    buildTypes{   
        release{   
            minifyEnabled true   
            shrinkResources true   
            proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'   
       }   
   }   
}  
在Proguard中,是否保留符號表APP的大小是有顯著的影響的,可酌情註釋下面這行程式碼,但是建議儘量保留,它可以用於保留除錯資訊。
-keepattributes SourceFile,LineNumberTable  

3.3 使用一套資源:

      對於絕大對數APP來說,只需要取一套設計圖就足夠了。鑑於現在解析度的趨勢,建議取720p的資源放到xhdpi目錄。在視覺上差別不大,很多大公司的產品也是如此,但卻能顯著的減少資源佔用大小,這裡不是說把非xhdpi的目錄都刪除,而是強調保留一套設計資源就夠了。

3.4只保留中文的語言資源:

大部分應用其實並不需要支援幾十種語言的國際化支援。強大的gradle支援語言的配置,比如國內應用只支援中文

android {  
    defaultConfig {  
        resConfigs "zh"  
    }  
}  

3.5 關於PNG圖片和JPG圖片:

Android打包本身會對png進行無失真壓縮,Android的介面能用png最好是用png,因為32位的png顏色過渡平滑且支援透明。在res下這些icon用的都是png格式,就是說Google推薦使用的是png格式的圖片。

【拓展】TinyPNG使用智慧有失真壓縮技術,在儘量少的損失下來減少PNG檔案的大小。具體TinyPNG的資訊請訪問:https://tinypng.com/

jpg是畫素化壓縮過的圖片,如果對於非透明的大圖,jpg將會比png的大小有顯著的優勢,雖然不是絕對的,但是通常會減小到一半都不止。jpg質量已經下降了,再拿來做9path的按鈕和平鋪拉伸的控制元件必然慘不忍睹,要儘量避免

3.6 關於WEBP圖片:

相對於jpg、png,webp作為一種新的圖片格式,壓縮比比jpg更高但顯示效果卻不輸於jpg,Android 4.0+才原生支援webp, 但是我們的app是相容2.3+,所以4.0以下的裝置將無法看到圖片但不會崩潰。限於Android的支援情況暫時還沒用在手機端廣泛應用起來。並且直到Android 4.2.1+才支援顯示含透明度的webp,官方評測quality引數等於75均衡最佳

3.7 覆蓋某些圖片:

一些aar庫裡面包含根本就沒有用的圖。最典型的是support-v4相容庫中包含一些“可能”用到的圖片,實際上在你的app中不會用到。可以考慮把幾張大一些的圖用1×1的圖片替換,如果9patch圖的話,要做成3×3的9patch圖替換。

同理可用於覆蓋第三方庫中我們用不到的大圖,可以在/build/intermediates/exploded-aar/下的各個aar庫的res目錄查詢檢驗。

3.8 刪除armable-v7和x86包下的so:

基本上armable的so也是相容armable-v7的,armable-v7a的庫會對圖形渲染方面有很大的改進,如果沒有這方面的要求,可以精簡。這裡不排除有極少數裝置會Crash,請務必測試周全後再發布。

x86包下的so在x86型號的手機是需要的,如果產品沒用這方面的要求也可以精簡。

建議實際工作的配置是隻保留armable、armable-x86下的so檔案,算是一個折中的方案。

   我們可以構建一個 APK,它支援所有的 CPU 型別。但是反過來,我們可以為每個 CPU 型別都單獨構建一個 APK,然後不同 CPU 型別的裝置安裝對應的 APK 即可,當然前提是應用市場得提供使用者裝置 CPU 型別設別的支援,就目前來說,至少 PLAY 市場是支援的。
   Gradle 可以通過以下配置生成不同 ABI 支援的 APK(引用自別的文章,沒實際使用過):

android {  
    ...  
    splits {  
        abi {  
            enable true  
            reset()  
            include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for  
            universalApk true //generate an additional APK that contains all the ABIs  
        }  
    }  
    // map for the version code  
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]  
    android.applicationVariants.all { variant ->  
        // assign different version code for each output  
        variant.outputs.each { output ->  
            output.versionCodeOverride =  
                    project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode  
        }  
    }  
 }  

3.9 微信資源壓縮打包:

微信中的資源混淆工具主要為了混淆資源ID長度(例如將res/drawable/welcome.png混淆為r/s/a.png),同時利用7zip深度壓縮,大大減少了安裝包體積,同時也增加了逼格,提升了反破解難度。效果非常的好,強烈推薦。

3.10 著色方案以及使用shape背景:

相信你的工程裡也有很多selector檔案,也有很多相似的圖片只是顏色不同,通過著色方案我們能大大減輕這樣的工作量,減少這樣的檔案。藉助於android support庫可實現一個全版本相容的著色方案。

在扁平化盛行的當下,很多純色的漸變的圓角的圖片都可以用shape實現,程式碼靈活可控,省去了大量的背景圖片。

3.11 外掛化:

外掛化技術支援動態的載入程式碼和動態的載入資源,把APP的一部分分離出來了,對於業務龐大的專案來說非常有用,極大的分解了APP大小。因為外掛化技術需要一定的技術保障和服務端系統支援,有一定的風險,如無必要(比如一些小型專案,也沒什麼擴充套件業務)就不需要了,建議酌情選擇。

3.12 資源的重用:

同一個圖片的著色,陰影,或者旋轉版本等等,可以重用同一個資源集合和定製它們。
   比如避免幀動畫的使用就是一個很好的例子(因為幀動畫每一幀都必須是一張明確的圖片檔案)。

3.13 向量圖的使用 :

向量圖在Android中以VectorDrawable物件代表(Android L版本引入)。使用VectorDrawable物件,允許開發人員以純程式碼方式生成類似繪製的效果。一個100-byte檔案可以生成一個螢幕大小清晰影象。 

   然而,每個VectorDrawable物件的渲染明顯的消耗系統時間,並且更大的圖片需要更長的時間來展示在螢幕上。因此僅僅在顯示小的圖片的時候考慮使用向量圖。 

3.14 移除列舉:

一個列舉會增加你的appclass.dex檔案大約1.01.4K的大小。對於複雜的系統或者共享庫這種情況會更加明顯。如果可能的話,考慮使用@IntDefProGuard剝離列舉,並轉換成Integer。這種型別轉換保留了所有列舉的安全效益。

參考資料地址: