
如圖,
編譯器將源代碼(包括 Application Module 及其所依賴的所有 Library 源代碼)轉換成DEX(Dalvik Executable)文件(其中包括運行在 Android 設備上的字節碼),將所有其他內容轉換成已編譯資源。(- 將源代碼(包括 Application Module 和 Library Module)編譯成 class 文件,再將所有的 class 文件(包括第三方庫中)打包生成 dex 文件。
- 解壓所有 aar 包中的資源文件,并和項目中所有資源文件合并到一個目錄。
- 生成資源文件的索引文件。
APK 打包器將 DEX 文件和已編譯資源打包生成單個 APK。不過,必須先對 APK 簽名,才能將應用安裝并部署到 Android 設備上。APK 打包器使用 Debug 或 Release 密鑰庫對 APK 簽名:- 如果您構建的是 Debug 版本的應用(即專用于測試和分析的應用),
打包器會使用 Debug 密鑰庫簽名應用。Android Studio 自動使用 Debug 密鑰庫配置新項目。 - 如果您構建的是打算向外發布的 Release 版本應用,
打包器會使用 Release 密鑰庫簽名應用。
- 如果您構建的是 Debug 版本的應用(即專用于測試和分析的應用),
- 在生成最終 APK 之前,打包器會使用 zipalign 工具對應用進行優化,減少其在設備上運行時的內存占用。
2. Gradle 構建 tasks 說明
注:這里是用 Debug 模式做例子,Release 模式時只需將 task 中的 Debug 替換成 Release 理解即可)Executing tasks: [:app:assembleDebug] :app:preBuild UP-TO-DATE :app:preDebugBuild UP-TO-DATE :app:compileDebugAidl UP-TO-DATE :app:compileDebugRenderscript UP-TO-DATE :app:generateDebugResValues UP-TO-DATE :app:generateDebugResources UP-TO-DATE :app:mergeDebugResources UP-TO-DATE :app:transformDataBindingBaseClassLogWithDataBindingMergeGenClassesForDebug UP-TO-DATE :app:dataBindingGenBaseClassesDebug UP-TO-DATE :app:checkDebugManifest UP-TO-DATE :app:generateDebugBuildConfig UP-TO-DATE :app:prepareLintJar UP-TO-DATE :app:mainApkListPersistenceDebug UP-TO-DATE :app:createDebugCompatibleScreenManifests UP-TO-DATE :app:processDebugManifest :app:splitsDiscoveryTaskDebug UP-TO-DATE :app:processDebugResources :app:generateDebugSources :app:dataBindingExportBuildInfoDebug :app:javaPreCompileDebug UP-TO-DATE :app:transformDataBindingWithDataBindingMergeArtifactsForDebug UP-TO-DATE :app:compileDebugJavaWithJavac :app:compileDebugNdk NO-SOURCE :app:compileDebugSources :app:mergeDebugShaders UP-TO-DATE :app:compileDebugShaders UP-TO-DATE :app:generateDebugAssets UP-TO-DATE :app:mergeDebugAssets UP-TO-DATE :app:transformClassesWithDexBuilderForDebug :app:transformDexArchiveWithExternalLibsDexMergerForDebug :app:transformDexArchiveWithDexMergerForDebug :app:mergeDebugJniLibFolders UP-TO-DATE :app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE :app:processDebugJavaRes NO-SOURCE :app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE :app:validateSigningDebug UP-TO-DATE :app:packageDebug :app:assembleDebug BUILD SUCCESSFUL in 20s
特別說明:由于 Gradle 會嘗試通過不重復執行輸入未發生變化的 task 來節省時間(這些 task 被標記為 UP-TO-DATE,如上所示)
所以第一次編譯運行會比較久,而后面就不會了。
上面列出來的 Gradle 構建過程,大致可分為五個階段:
Preparation of dependecies在這個階段 Gradle 檢測 Module 依賴的所有 library 是否 ready。如果這個 Module 依賴于另一個 Module ,則另一個 Module 也要被編譯。Merging resources and processing Manifest打包資源和 Manifest 文件。Compiling在這個階段處理編譯器的注解,源碼被編譯成字節碼。Postprocessing所有帶 transform 前綴的 task 都是這個階段進行處理的。Packaging and publishing這個階段 library 生成.aar文件,Application 生成.apk文件。
這五個階段和上面的構建過程中 task 的時序有大致的對應關系,大家可以相互映照著理解。
為了便于大家理解,下面給出一些關鍵 task 的說明:
-
mergeDebugResources解壓所有的 aar 包輸出到app/build/intermediates/exploded-aar,并且把所有的資源文件合并到app/build/intermediates/res/merged/debug目錄里。 -
processDebugManifest把所有 aar 包里的AndroidManifest.xml中的節點,合并到項目的AndroidManifest.xml中,并根據app/build.gradle中當前buildType 的 manifestPlaceholders配置內容替換 manifest 文件中的占位符,最后輸出到app/build/intermediates/manifests/full/debug/AndroidManifest.xml。 -
processDebugResources- 調用 aapt 生成項目和所有 aar 依賴的
R.java,輸出到app/build/generated/source/r/debug目錄; - 生成資源索引文件
app/build/intermediates/res/debug/resources-debug.ap_; - 把符號表輸出到
app/build/intermediates/symbols/debug/R.txt。
- 調用 aapt 生成項目和所有 aar 依賴的
-
compileDebugJavaWithJavac用來把 java 文件編譯成 class 文件,輸出的路徑是app/build/intermediates/classes/debug編譯的輸入目錄有
- 項目源碼目錄,默認路徑是
app/src/main/java,可以通過 sourceSets 的 dsl 配置,允許有多個(打印project.android.sourceSets.main.java.srcDirs可以查看當前所有的源碼路徑,具體配置可以參考 android-doc,以及這里。 app/build/generated/source/aidl。app/build/generated/source/buildConfig。app/build/generated/source/apt(繼承javax.annotation.processing.AbstractProcessor做動態代碼生成的一些庫,輸出在這個目錄)的代碼。
- 項目源碼目錄,默認路徑是
-
transformClassesWithMultidexlistForDebug(這個任務在使用 Multidex 才會出現)它有兩個作用- 掃描項目的
AndroidManifest.xml文件和分析類之間的依賴關系,計算出那些類必須放在第一個 dex 里面,最后把分析的結果寫到app/build/intermediates/multi-dex/debug/maindexlist.txt文件里面 - 生成混淆配置項輸出到
app/build/intermediates/multi-dex/debug/manifest_keep.txt文件里
項目里的代碼入口是 manifest 中 application 節點的屬性 android.name 配置的繼承自 Application 的類,在 Android 5.0 以前的版本系統只會加載一個 dex(classes.dex),classes2.dex .......classesN.dex 一般是使用
android.support.multidex.MultiDex加載的,所以如果入口的 Application 類不在 classes.dex 里 5.0 以下肯定會掛掉,另外當入口 Application 依賴的類不在 classes.dex 時初始化的時候也會因為類找不到而掛掉,還有如果混淆的時候類名變掉了也會因為對應不了而掛掉,綜上所述就是這個任務的作用。 - 掃描項目的
浙公網安備 33010602011771號