前言
我們完成一個app後,都需要生成一個apk,然後上線,而apk的大小也一定程度的影響了用戶是否願意下載你的這個app,所以也就有了apk瘦身這門藝術。
目錄
- apk的結構
- 圖片壓縮
- 導入矢量圖
- 適配問題
- Tint 着色器
- 動態庫移除
- so庫的相關知識點
- ABI
- 結束語
apk的結構
既然要對一個apk瘦身,首先我們就得知道apk格式的文件內容。實際上一個apk文件就是一個zip包,我們只需要將後綴改爲zip,然後進行解壓就可以看到裏面的內容了。下面我們來看下它裏面的文件以及作用:
apk包含以下目錄:
assets/
: 包含了應用的資源,這些資源能夠通過AssetManager對象獲得。lib/
: 包含了針對處理器層面的被編譯的代碼。這個目錄針對每個平臺類型都有一個子目錄,比如armeabi, armeabi-v7a, arm64-v8a, x86, x86_64和mips。res/
: 包含了沒被編譯到resources.arsc的資源。META-INF/
: 包含CERT.SF和CERT.RSA簽名文件,也包含了MANIFEST.MF文件。(譯註:校驗這個APK是否被人改動過)
apk包含以下文件:
classes.dex
: 包含了能被Dalvik/Art虛擬機理解的 dex 文件格式的類。resources.arsc
: 包含了被編譯的資源。該文件包含了res/values目錄的所有配置的 xml 內容。打包工具將 xml 內容編譯成二進制形式並壓縮。這些內容包含了語言字符串和styles,還包含了那些內容雖然不直接存儲在resources.arsc文件中,但是給定了該內容的路徑,比如佈局文件和圖片。所以又叫 資源映射表AndroidManifest.xml
: 包含了主要的Android配置文件。這個文件列出了應用名稱、版本、訪問權限、引用的庫文件。該文件使用二進制 xml 格式存儲。(譯註:該文件還能看到應用的minSdkVersion, targetSdkVersion等信息)
好的,現在我們已經知道apk到底是個什麼東東了,接下來我們開始一步步對這些內容進行瘦身處理。
圖片壓縮
我們都知道,一個apk會使用大量的圖片,如果圖片這塊能夠壓縮下,那效果還是非常可觀的。
如下圖,我們在項目中經常會用到這樣的套圖。
明明只是一種圖片,而我們卻因爲大小和顏色,需要這樣的一組,顯然很佔大小,那有沒有什麼方式優化下呢?
答案是有的。
谷歌的AS爲我們提供了一個名爲 Vector Asset Studio 的工具,可以幫助我們添加內置Material圖標以及將本地的SVG(Scalable Vector Graphics 可縮放矢量圖)等格式作爲矢量圖資源導入到項目中,會在drawable目錄下生成一個根節點爲vector的xml文件,而且矢量圖的大小也更小,是不是非常棒啊!那下面我們來看看怎麼實現的。
導入矢量圖
首先我們在AS中運行Vector Asset Studio,步驟是:右鍵點擊你工程中的res文件夾,然後選擇 New --> Vector Asset,此時會彈出下面對話框,選擇圖中標記的對應操作即可導入內置Material圖標或者SVG矢量圖。
但是上面這種方式只能一張張導入圖片,顯然很麻煩。那有沒有更好的方式了?實際上我們之所以要用這個工具導入svg圖片,而不是直接將svg圖片複製到drawable中,是因爲安卓不支持svg,需要工具轉換下,所以我們可以使用svg2vector這個第三方庫進行批量轉換,然後直接複製到drawable中即可,轉換命令如下:
java -jar svg2vector-cli-1.0.0.jar -d . -o a -h 20 -w 20
-d 指定svg文件所在目錄
-o 輸出android vector圖像目錄
-h 設置轉換後svg的高
-w 設置轉換後svg的寬
適配問題
因爲矢量圖是在Android 5.0(API21)纔開始支持的,所以這個地方我們還需要適配下。如果不適配,你的最小minSdkVersion版本又小於21,則會自動在每個drawable目錄下生成對應的png圖片,反而會使apk包變大,所以這裏一定要注意了。我們有下面兩種方式進行適配:
方式一:生成 png 格式的圖片
這種方式是在drawable文件中生成對應的png,不過我們可以指定只生成哪幾個。例如如下配置
我們可以在項目的build.gradle中進行如下配置,即可在指定的drawable文件中生成對應的png格式圖片。
方式二:支持庫
還一種方式就是使用支持庫,支持庫的版本需要23.2或者更高,也是在項目的build.gradle中進行配置,如下:
這種適配方式使用圖片的時候,需要用 app:srcCompat
屬性,而不是 android:src
,如下:
通過這個方式只是解決了不同大小需要多張圖片的問題,但是還需要有不同顏色的圖片。這個我們怎麼處理呢?不要急,這個問題谷歌工程師也爲我們準備了一個工具,它就是Tint着色器。
Tint 着色器
一般我們矢量圖都是使用黑色,然後由Tint着色器去修改顏色,直接在xml中使用即可,如下:
在java代碼中,我們可以通過DrawableCompat去設置,如下:
那如果想要實現按鍵效果,通過 Tint 也能實現嗎?答案是可以的。
首先我們需要創建兩個選擇器,一個是 drawable 選擇器,一個是 color 選擇器,如下:
然後就可以直接使用了,如下:
總的來說使用Tint找色器去修改矢量圖的顏色還是蠻簡單的吧。
通過矢量圖這個方式,我們就能夠減小使用圖片的總大小,從而減小apk的大小。
瘦身不是一蹴而就的,所以我們接着減。
動態庫移除
so庫的相關知識點
說到so庫,相信大部分人都有使用過,但是卻不知道它到底是什麼。其實so庫就是由ndk編譯出來的動態庫。
那我們爲什麼要把so文件分別放在armeabi、arm64-v8a、armeabi-v7a、x86、x86_64這些文件中呢?
主要是因爲我們的app運行在不同的手機中,而so庫是由c\c++編譯的,不是跨平臺的,所以不同平臺(不同CPU)需要使用不同的so庫。那不同的文件是什麼意思呢?我們接着往下看。
ABI
ABI 是應用程序二進制接口簡稱(Application Binary Interface),定義了二進制文件(尤其是.so文件)如何運行在相應的系統平臺上,從使用的指令集,內存對齊到可用的系統函數庫。在Android 系統上,每一個CPU架構對應一個ABI,即:armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64。
ABI | Supported Instruction Set(s) |
---|---|
armeabi | ARMV5TE and later,Thumb-1 |
armeabi-v7a | armeabi,Thumb-2,VFPv3-D16,Other,optional |
arm64-v8a | AArch-64 |
x86 | x86(IA-32),MMX,SSE/2/3,SSSE3 |
x86_64 | x86-64,MMX,SSE/2/3,SSE3,SSE4.1,SSE4.2,POPCNT |
mips | MIPS32r1 and later |
mips64 | MIPS64r6 |
各版本分析如下:
- mips / mips64:極少用於手機可以忽略
- x86 / x86_64:x86 架構的手機都會包含由 Intel 提供的稱爲 Houdini 的指令集動態轉碼工具,實現 對 arm .so 的兼容,再考慮 x86 1% 以下的市場佔有率,x86 相關的兩個 .so 也是可以忽略的
- armeabi:ARM v5 這是相當老舊的一個版本,缺少對浮點數計算的硬件支持,在需要大量計算時有性能瓶頸
- armeabi-v7a:ARM v7 目前主流版本
- arm64-v8a:64位支持
所以現在我們一般只要在項目的build.gradle中適配ARM v7就行了,如下:
結束語
如果你的技術提升遇到瓶頸了,或者缺高級Android進階視頻學習提升自己,這有大量大廠面試題爲你面試做準備!
點擊Android 學習,面試文檔,視頻收集大整理獲取
未完待續。。。
好的,今天我們就暫時介紹到這兒,瘦身之旅長路漫漫,還有的方式我們下次分享。
如果喜歡本文可以關注我們的官方賬號,第一時間獲取資訊。
你的關注是對我們更新最大的動力~