Android APK(Android Package)是 Android 應用的安裝包文件,其組成和打包流程涉及多個步驟和文件結構。以下是詳細的說明:
一、APK 的組成
APK 是一個 ZIP 格式的壓縮包,包含應用運行所需的所有文件。解壓后主要包含以下內容:
-
classes.dex
-
由 Java/Kotlin 代碼編譯后的 Dalvik/ART 字節碼文件。
-
如果方法數超過 65536,會生成多個?
classes2.dex
、classes3.dex
?等(需啟用 MultiDex)。
-
-
resources.arsc
-
編譯后的二進制資源索引表,包含字符串、布局、顏色等資源的映射關系,用于快速查找資源。
-
-
AndroidManifest.xml
-
應用的配置文件(二進制格式),聲明包名、權限、組件(Activity/Service 等)、最低 SDK 版本等。
-
-
res/
?目錄-
存放編譯后的資源文件(圖片、布局 XML、動畫等),原始 XML 會被編譯為二進制格式以優化讀取效率。
-
-
assets/
?目錄-
存放原始資源文件(如字體、配置文件),通過?
AssetManager
?直接訪問,不參與資源 ID 生成。
-
-
lib/
?目錄-
存放原生庫(
.so
?文件),按 CPU 架構分目錄(如?armeabi-v7a
,?arm64-v8a
,?x86
)。
-
-
META-INF/
?目錄-
包含應用簽名信息(
MANIFEST.MF
,?CERT.SF
,?CERT.RSA
),用于驗證 APK 完整性。
-
-
kotlin/
?目錄-
如果使用 Kotlin,會包含 Kotlin 標準庫的相關文件。
-
-
其他文件
-
如 ProGuard/R8 生成的映射文件(
mapping.txt
)、AAPT2 生成的資源映射等。
-
二、APK 打包流程
Android 應用的構建流程通過 Gradle 和 Android 構建工具鏈(如 AAPT2、D8、R8 等)完成,主要步驟如下:
1. 資源處理
-
工具:AAPT2 (Android Asset Packaging Tool)
-
編譯?
res/
?下的資源文件(XML、圖片等),生成?resources.arsc
?和二進制 XML。 -
生成?
R.java
?文件,為每個資源分配唯一 ID。
-
2. 代碼編譯
-
Java/Kotlin 編譯
-
將 Java/Kotlin 源代碼編譯為?
.class
?文件(javac
?或?kotlinc
)。
-
-
DEX 轉換
-
使用?D8 或 R8 工具?將?
.class
?文件轉換為 Android 虛擬機所需的?.dex
?文件,優化字節碼并可能啟用代碼混淆(通過 R8)。
-
3. 資源與代碼合并
-
工具:Android Gradle Plugin
-
合并所有模塊的資源文件,處理資源沖突。
-
將?
classes.dex
、resources.arsc
、lib/
、assets/
?等文件打包到臨時 APK 中。
-
4. 原生庫處理
-
將 JNI 庫(
.so
?文件)按 CPU 架構分類,并打包到 APK 的?lib/
?目錄。
5. APK 簽名
-
工具:
apksigner
?或?jarsigner
-
使用開發者密鑰對 APK 進行簽名,確保應用來源可信且未被篡改。
-
生成?
META-INF/
?目錄下的簽名文件。
-
6. APK 對齊優化
-
工具:
zipalign
-
對 APK 中的未壓縮文件進行內存對齊(4 字節邊界),提升運行時加載效率。
-
zipalign 主要工作是將apk包進行對齊處理。使apk包中的所有資源文件,起始偏移為4字節的整數倍,這樣通過mmap內存映射訪問apk時的速度會更快。
-
工具名稱 | 功能介紹 | 在操作系統中的路徑 |
---|---|---|
aapt | Android資源打包工具 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/aapt |
aidl | Android接口描述語言轉化為.java文件的工具 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/aidl |
javac | java Compiler java代碼轉class文件 | ${JDK_HOME}/javac或/usr/bin/javac |
dex | 轉化.class文件為Davik VM能識別的.dex文件 | ${ANDROID_SDK_HOME}/build-tools/30.0.0/dx |
apkbuilder | 生成apk包 | ???沒有找到 |
jarsigner | .jar文件的簽名工具 | ${JDK_HOME}/jarsigner或/usr/bin/jarsigner |
zipalign | 字節碼對齊工具 | ${ANDROID_SDK_HOME}/tools/zipalign |
三、詳細構建流程圖
源代碼 (Java/Kotlin) --> 編譯 --> .class 文件 --> D8/R8 --> classes.dex
資源文件 (res/, assets/) --> AAPT2 --> resources.arsc + 二進制 XML
原生庫 (JNI) --> 按架構分類打包到 lib/
合并所有文件 --> 未簽名 APK --> 簽名 --> 簽名后的 APK --> zipalign 對齊 --> 最終 APK
四、構建工具鏈演進
-
AAPT → AAPT2:支持增量資源編譯,提升構建速度。
-
DX → D8:更快的 DEX 編譯,更好的字節碼優化。
-
ProGuard → R8:將代碼壓縮(Shrinking)、優化(Optimization)、混淆(Obfuscation)與 DEX 編譯合并為一步。
五、優化與擴展
-
Android App Bundle (AAB):Google 推出的動態分發格式,按設備配置生成優化后的 APK。
-
Split APKs:根據屏幕密度、ABI 等拆分 APK,減少用戶下載體積。
-
資源混淆:通過工具(如 AndResGuard)對資源文件名進行混淆,進一步縮減 APK 體積。
六、虛擬機演進
虛擬機是一個可以運行 class , odex , oat 可執行文件的運行環境 ;
常見的虛擬機有 Java 虛擬機、Dalvik 虛擬機?、?ART 虛擬機 ;
Java 虛擬機 : 運行的 class 字節碼文件 , 運行程序時解碼 class 文件中的內容 ; 基于棧架構 , 需要頻繁在棧上讀寫數據 , 造成較多的指令分派 , 更多的內存訪問次數 , 比較耗費 CPU 時間 ;
編譯時 : Java 源碼 , 使用 javac 編譯器 , 編譯成 class 字節碼文件 ; 運行時 : 類加載器通過 Java 類庫驗證字節碼 , 驗證通過會后進入 Java 虛擬機 , 進入 Java 解釋器 或 即時編譯器 , 然后進入運行時系統 , 之后進入操作系統 , 然后調用硬件 ;
Dalvik 虛擬機 : 基于 JIT 機制 ( 即時編譯技術 )?
Android 5.0 以下使用的虛擬機是 Dalvik 虛擬機 , 該虛擬機的可執行文件是 dex 文件 , 該文件比 class 字節碼文件更小 ; JIT ( Just In Time ) 即時編譯技術 , 對應 Dalvik 虛擬機 ; 基于寄存器架構 , 通過寄存器間接訪問數據 , 該方式比基于棧架構速度更快 ;
ART 虛擬機 :
Android 5.0 以上使用的虛擬機是 ART 虛擬機 ; AOT ( Ahhead Of Time ) 預編譯技術 , 對應 ART 虛擬機 ; Java 虛擬機 / Dalvik 虛擬機 / ART 虛擬機 都向上層提供了 3 個接口JNI_GetDefaultJavaVMInitArgs JNI_CreateJavaVM JNI_GetCreatedJavaVMS ; 虛擬機之間可實現無縫銜接 ;
Dalvik 虛擬機 與 ART 虛擬機區別 : 虛擬機中有個 persist.sys.dvlvik.vm.lib 字段 , 如果該字段存儲的是 libdvm.so , 該虛擬機是 Dalvik 虛擬機 ; 如果該字段存儲的是 ;ibart.so , 該虛擬機是 ART 虛擬機 ;
Dalvik 虛擬機 與 ART 虛擬機可執行文件 :
Dalvik 虛擬機加載 dex 文件加載時不是直接加載 dex 文件 , 加載執行的是 odex 文件 , odex 文件是通過 dexopt 工具對 dex 進行優化生成的 ;
ART 虛擬機加載 dex 文件時加載的是 oat 文件 , oat 文件時通過 dex2oat 工具對 dex 文件進行優化生成的 ;
通過理解 APK 的組成和打包流程,開發者可以更好地優化應用性能、調試構建問題,并掌握高級構建技術(如模塊化、動態交付)。
參考:
1. 深入詳解Apk編譯打包流程
2.?APK 打包流程 ( 文件結構 | 打包流程 | 安裝流程 | 安卓虛擬機 )
3.?Android 打包流程