安卓apk組成分析,apk打包流程,以及debug包和release包對比

APK包結構及打包流程

先來介紹一下安卓apk包結構的目錄
實際上,一個APK文件就是一個.zip格式的壓縮包,我們可以用解壓縮工具打開任何一個APK文件,由於代碼混淆和加密,通過普通解壓縮工具打開裏面的文件或目錄會看到各種亂碼。一個典型的apk文件包含以下內容:

Android應用程序APK文件的結構圖
在這裏插入圖片描述

  • assets目錄 存放需要打包到APK中的靜態文件
  • lib目錄 程序依賴的Native庫
  • res目錄 存放應用程序的資源
  • META-INF目錄 存放應用程序簽名和證書的目錄
  • AndroidManifest.xml 應用程序的配置文件
  • classes.dex dex可執行文件
  • resources.arsc 資源配置文件

- AndroidManifest.xml

Android應用的配置清單文件,它向Android系統介紹了這個應用的很多配置信息,系統可以根據這個文件在相當程度上了解這個應用的一些信息。該文件是每個應用都必須定義和包含的,它描述了應用的名字、版本、權限、引用的庫文件等等信息,如要把apk上傳到Google Market上,也要對這個xml做一些配置。在apk中的AndroidManifest.xml是經過壓縮的,可以通過AXMLPrinter2工具(針對該文件)或apktool工具進行反編譯(反編譯整個apk)。

- META-INF目錄

META-INF目錄下存放的是簽名信息,用來保證apk包的完整性和系統的安全。沒有簽名的應用是不被系統認可的,也無法安裝到手機中。Android SDK在對APK進行打包的時候,會把APK中全部文件的完整信息保存到這裏,這樣應用在安裝的時候會進行完整性校驗,確保APK的文件不會被篡改,大大提升了應用和系統的安全性與完整性。META-INF目錄下有CERT.RSA、CERT.SF和MANIFEST.MF這幾個文件,其中的CERT.RSA文件記錄了開發者的私鑰對APK簽名後的信息,MANIFEST.MF文件則保存了整個APK中所有文件的SHA-1進行base64編碼後的值,CERT.SF則與MANIFEST.MF差不多,包括了後者所有的信息,然後又加入了MANIFEST.MF文件的SHA-1並base64編碼的值。

- res目錄

存放各種資源文件的目錄。這個目錄中的所有文件,最終會被映射到Android工程中的R文件中,生成對應的int型的ID,在程序中訪問這些資源文件的時候,直接使用資源的ID就能進行調用了。
res目錄下還包含着多個子文件夾:anmi中存放着動畫文件;drawable則存放着一些圖片資源;layout中存放的是佈局文件;menu則是自定義菜單的項;raw目錄中的文件則是可以直接複製到設備中的文件,不會被編譯;values中存放着一些特殊的值——colors.xml記錄的是你自定義的顏色,dimens.xml記錄着你自定義的尺寸,strings.xml則是你自定義的字符串常量值,styles.xml定義了一些樣式。

- lib目錄

這個目錄中存放着應用依賴的native庫文件,這些以.so結尾的文件是用C或者C++語言編寫的,一個簡單的Android應用可能並不需要這些庫,但一個功能全面而又追求性能的應用是不可能無視這個目錄的,譬如圖片處理、網絡處理、音視頻處理等一些對性能要求很高的功能,單純依靠Java會十分喫力,性能更加強大而且更加接近底層的C/C++就是更合適的選擇了。
根據手機CPU的架構,lib庫大體上可以分爲4種:ARM、ARM-V7、MIPS和X86,分別對應着4種CPU架構,在lib目錄裏則分別是armeabi、armeabi-v7a、mips和x86一共4個目錄。每個目錄中的.so庫名字都是一樣的,實際上功能也是相同的,它們只是爲了適配不同架構的CPU而存在。實際上,市面上的手機幾乎全都是ARM架構的,所以大多數情況下我們只需要有armeabi和armeabi-v7a兩種類型的庫就足夠了。

- assets目錄

跟res目錄有點相似,但實際上二者還是有區別的。res目錄中的文件會映射到R文件中,每個資源文件都有自己的ID,而assets中的文件則直接通過訪問文件的地址來使用AssetManager類進行訪問,而且assets目錄你可以添加任意深度的子目錄,這一點會比較方便管理和歸類文件。相比較之下,res目錄目前不能支持更深級的子目錄。

- classes.dex文件
classes.dex是java源碼編譯後生成的java字節碼文件(首先是java文件通過jdk編譯成字節碼文件然後經過dex編譯成classes.dex)。但由於Android使用的dalvik虛擬機與標準的java虛擬機是不兼容 的,dex文件與class文件相比,不論是文件結構還是opcode都不一樣。目前常見的java反編譯工具都不能處理dex文件。Android模擬 器中提供了一個dex文件的反編譯工具,dexdump。用法爲首先啓動Android模擬器,把要查看的dex文件用adb push上傳的模擬器中,然後通過adb shell登錄,找到要查看的dex文件,執行dexdump xxx.dex。

對比普通java程序和安卓程序差異
普通java程序 java虛擬機 java字節碼(class) 基於棧
安卓程序 Davlik虛擬機 Dalvik字節碼(dex) 基於寄存器

- resources.arsc
編譯後的二進制資源文件的索引,記錄了資源文件(即res目錄中的文件)和資源文件ID的映射關係,這樣程序運行的時候就可以根據資源的ID獲取到相應的資源了。

APK打包流程
網上找的圖:
在這裏插入圖片描述
谷歌官方文檔的圖及介紹:在這裏插入圖片描述
一個典型的Android應用模塊的構建過程遵循以下一般步驟:

1、編譯器將您的源代碼轉換爲DEX(Dalvik可執行文件)文件,其中包括在Android設備上運行的字節碼,以及所有其他內容都轉換爲已編譯資源。2、APK打包器將DEX文件和已編譯的資源合併到一個APK中。但是,必須先對APK簽名,然後才能將您的應用安裝和部署到Android設備上。
3、APK Packager使用調試或釋放密鑰庫對您的APK進行簽名:
a、如果要構建應用程序的調試版本,即僅打算進行測試和性能分析的應用程序,則打包程序將使用調試密鑰庫對應用程序進行簽名。Android Studio使用調試密鑰庫自動配置新項目。
b、如果您要構建要從外部發布的應用程序發行版本,則打包程序將使用發行密鑰庫對應用程序進行簽名。
4、在生成最終APK之前,打包程序會使用zipalign工具優化您的應用,以在設備上運行時使用更少的內存

Debug包和Release包對比

再來看看debug包和release包對比,話不多說,先上圖
在這裏插入圖片描述
在這裏插入圖片描述
左邊是release包,右邊是debug包,可以看到,一樣的打包配置,debug包要比release包要大0.3mb。主要大在dex文件和res文件夾,其他都一樣

我們繼續看看dex文件區別在哪裏:
在這裏插入圖片描述
有android、androidx、kotlin、test四個文件夾大小不一樣,其他文件夾大小均一樣,我們再來看看android文件夾
在這裏插入圖片描述
我們可以看到,有定義方法的文件夾,他們的大小就是不一樣的,再往裏看
在這裏插入圖片描述
可以看到support包下的v4、v7等文件夾大小均不一樣,再往下看
在這裏插入圖片描述
打開對比看看這個類的字節碼
在這裏插入圖片描述
左邊的debug包的字節碼行數要比右邊的release包字節碼行數要多100多行(至於爲什麼會是這樣,,我猜測是debug模式下要多一些調試信息吧)

我們再來看看res文件夾,drawable-xxx-v4的文件夾大小不一樣在這裏插入圖片描述
再往下看,發現debug包裏面ic_launcher_background圖片文件大小和release包裏面ic_launcher_background大小不一樣,一個是2.75kb,一個是767b,換算一下正好是drawable-xxhdpi-v4文件夾大小的區別,,其他幾個drawable文件夾也類似,至於爲什麼谷歌官方會把debug包和release包相同的文件用不同的大小,我也不得而知,我猜測是release包進行了壓縮處理之類

在這裏插入圖片描述
結論毫無疑問,相同代碼配置情況下,debug包會比release包大一點,應該是debug包包含了一些調試信息,而release包進行了一些優化,以期達到代碼最小和速度最優

摘自此篇
Debug通常稱爲調試版本,通過一系列編譯選項的配合,編譯的結果通常包含調試信息,而且不做任何優化,以爲開發 人員提供強大的應用程序調試能力。
Release通常稱爲發佈版本,是爲用戶使用的,一般客戶不允許在發佈版本上進行調試。所以不保存調試信 息,同時,它往往進行了各種優化,以期達到代碼最小和速度最優。爲用戶的使用提供便利。

(1) debug程序通常比release程序要慢,尤其是處理視頻方便release要比debug快很多。在release模式對程序進行調試的時候經常會遇到變量雖然初始化了,但是在查看其值的時候卻發現是一個隨機的數並不是初始化的值,有時候在對變量進行監視的時候了,會出現找不到變量的情況。
(2) debug跟release在初始化變量時所做的操作是不同的,debug是將每個字節位都賦成0xcc, 而release的賦值近似於隨機。在聲明變量後馬上對其初始化一個默認的值是最簡單有效的辦法,否則項目大了你找都沒地方找。代碼存在錯誤在debug方式下可能會忽略而不被察覺到。debug方式下數組越界也大多不會出錯,在release中就暴露出來了,這個找起來就比較難了。
(3) 只有DEBUG版的程序才能設置斷點、單步執行、使用 TRACE/ASSERT等調試輸出語句。REALEASE不包含任何調試信息,所以體積小、運行速度快。

至此,我們對apk的研究結束

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章