1. 程式人生 > >(轉)android Apk打包過程概述_android是如何打包apk的

(轉)android Apk打包過程概述_android是如何打包apk的

最近看了老羅分析android資源管理和apk打包流程的部落格,參考其他一些資料,做了一下整理,脫離繁瑣的打包細節和資料結構,從整體上概述了apk打包的整個流程。

流程概述:
1、打包資原始檔,生成R.java檔案
2、處理aidl檔案,生成相應java 檔案
3、編譯工程原始碼,生成相應class 檔案
4、轉換所有class檔案,生成classes.dex檔案
5、打包生成apk
6、對apk檔案進行簽名
7、對簽名後的apk檔案進行對其處理

此處輸入圖片的描述

名稱 功能介紹 在作業系統中的路徑 原始碼路徑
aapt(Android Asset Package Tool) Android資源打包工具 ${ANDROID_SDK_HOME} /build-tools/ ANDROID_VERSION/aapt frameworks\base\tools\aap
aidl 將aidl轉化為.Java檔案的工具 build-tools/ANDROID_VERSION/aidl frameworks\base\tools\aidl
javac Java Compiler
dex 轉化.class檔案為Davik VM能識別的.dex檔案 build-tools/ANDROID_VERSION/dx
apkbuilder 生成apk包 /tools/apkbuilder ApkBuilderMain.java
jarsigner .jar檔案的簽名工具 JAVA_HOME/jarsigner或/usr/bin/jarsigner
zipalign 位元組碼對齊工具 ANDROID_HOME/tools/zipalign

第一步:打包資原始檔,生成R.java檔案。
【輸入】Resource檔案(就是工程中res中的檔案)、Assets檔案(相當於另外一種資源,這種資源Android系統並不像對res中的檔案那樣優化它)、AndroidManifest.xml檔案(包名就是從這裡讀取的,因為生成R.java檔案需要包名)、Android基礎類庫(Android.jar檔案)
【工具】aapt工具
【輸出】打包好的資源(bin目錄中的resources.ap_檔案)、R.java檔案(gen目錄中)
打包資源的工具aapt,大部分文字格式的XML資原始檔會被編譯成二進位制格式的XML資原始檔,除了assets和res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理。 。
生成過程主要是呼叫了aapt原始碼目錄下的Resource.cpp檔案中的buildResource()函式,該函式首先檢查AndroidManifest.xml的合法性,然後對res目錄下的資源子目錄進行處理,處理的函式為makeFileResource(),處理的內容包括資原始檔名的合法性檢查,向資源表table新增條目等,處理完後呼叫compileResourceFile()函式編譯res與asserts目錄下的資源並生成resources.arsc檔案,compileResourceFile()函式位於aapt原始碼目錄的ResourceTable.cpp檔案中,該函式最後會呼叫parseAndAddEntry()函式生成R.java檔案,完成資源編譯後,接下來呼叫compileXmlfile()函式對res目錄的子目錄下的xml檔案分別進行編譯,這樣處理過的xml檔案就簡單的被“加密”了,最後將所有的資源與編譯生成的resorces.arsc檔案以及“加密”過的AndroidManifest.xml檔案打包壓縮成resources.ap_檔案(使用Ant工具命令列編譯則會生成與build.xml中“project name”指定的屬性同名的ap_檔案)。

第二步:處理aidl檔案,生成相應的java檔案。
【輸入】原始碼檔案、aidl檔案、framework.aidl檔案
【工具】aidl工具
【輸出】對應的.java檔案
對於沒有使用到aidl的android工程,這一步可以跳過。aidl工具解析介面定義檔案並生成相應的java程式碼供程式呼叫。

第三步:編譯工程原始碼,生成下相應的class檔案。
【輸入】原始碼檔案(包括R.java和AIDL生成的.java檔案)、庫檔案(.jar檔案)
【工具】javac工具
【輸出】.class檔案
這一步呼叫了javac編譯工程src目錄下所有的java原始檔,生成的class檔案位於工程的bin\classes目錄下,上圖假定編譯工程原始碼時程式是基於android SDK開發的,實際開發過程中,也有可能會使用android NDK來編譯native程式碼,因此,如果可能的話,這一步還需要使用android NDK編譯C/C++程式碼,當然,編譯C/C++程式碼的步驟也可以提前到第一步或第二步。

第四步:轉換所有的class檔案,生成classes.dex檔案。
【輸入】 .class檔案(包括Aidl生成.class檔案,R生成的.class檔案,原始檔生成的.class檔案),庫檔案(.jar檔案)
【工具】javac工具
【輸出】.dex檔案
前面多次提到,android系統dalvik虛擬機器的可執行檔案為dex格式,程式執行所需的classes.dex檔案就是在這一步生成的,使用的工具為dx,dx工具主要的工作是將java位元組碼轉換為dalvik位元組碼、壓縮常量池、消除冗餘資訊等。

第五步:打包生成apk。
【輸入】打包後的資原始檔、打包後類檔案(.dex檔案)、libs檔案(包括.so檔案,當然很多工程都沒有這樣的檔案,如果你不使用C/C++開發的話)
【工具】apkbuilder工具
【輸出】未簽名的.apk檔案
打包工具為apkbuilder,apkbuilder為一個指令碼檔案,實際呼叫的是android-sdk\tools\lib\sdklib.jar檔案中的com.android.sdklib.build.ApkBuilderMain類。它的程式碼實現位於android系統原始碼的sdk\sdkmanager\libs\sdklib\src\com\android\sdklib\build\ApkBuilderMain.java檔案,程式碼構建了一個ApkBuilder類,然後以包含resources.arsc的檔案為基礎生成apk檔案,這個檔案一般為ap_結尾,接著呼叫addSourceFolder()函式新增工程資源,addSourceFolder()會呼叫processFileForResource()函式往apk檔案中新增資源,處理的內容包括res目錄與asserts目錄中的檔案,新增完資源後呼叫addResourceFromJar()函式往apk檔案中寫入依賴庫,接著呼叫addNativeLibraries()函式新增工程libs目錄下的Native庫(通過android NDK編譯生成的so或bin檔案),最後呼叫sealApk()關閉apk檔案。

第六步:對apk檔案進行簽名。
【輸入】未簽名的.apk檔案
【工具】jarsigner
【輸出】簽名的.apk檔案
android的應用程式需要簽名才能在android裝置上安裝,簽名apk檔案有兩種情況:一種是在除錯程式時進行簽名,使用eclipse開發android程式時,在編譯除錯程式時會自己使用一個debug.keystore對apk進行簽名;另一種是打包釋出時對程式進行簽名,這種情況下需要提供一個符合android開發文件中要求的簽名檔案。簽名的方法也分兩種:一種是使用jdk中提供的jarsigner工具簽名;另一種是使用android原始碼中提供的signapk工具,它的程式碼位於android系統原始碼build\tools\signapk目錄下。

第七步:對簽名後的apk檔案進行對齊處理。
【輸入】簽名後的.apk檔案
【工具】zipalign工具
【輸出】對齊後的.apk檔案
這一步需要使用的工具為zipalign,它位於android-sdk\tools目錄,原始碼位於android系統原始碼的build\tools\zipalign目錄,它的主要工作是將apk包進行對齊處理,使apk包中的所有資原始檔距離檔案起始偏移為4位元組整數倍,這樣通過記憶體對映訪問apk檔案時速度會更快,驗證apk檔案是否對齊過的工作由ZipAlign.cpp檔案的verify()函式完成,處理對齊的工作則由process()函式完成。

以一個具體專案中包含的具體檔案為例作圖如下:
此處輸入圖片的描述
關於Android打包apk過程中的細節以及打包後如何獲取資源、查詢資源、使用資源,移步老羅的部落格,十分詳細。