上兩篇博客中提到了構建過程的問題,以前畢業在準備面試的過程當中,對這個部分有過較爲認真的學習,也進行了博客記錄,可是實際工做過程當中,若是是在寫業務邏輯上,那麼這方面的問題接觸的就會比較少了。逐漸的淡忘了,其次,以前所寫的文章條理性也不是很強,同時,最近準備進行Gradle插件的一系列博客的產出,其中將會涉及到不少與項目構建相關的內容。因此此文也將成爲後續文章的一個鋪墊。html
項目的構建: 當咱們打開一個項目,咱們能夠看到的是咱們寫的Java Code文件or Other JVM Code,資源文件,Build配置文件,可是經過run the project,咱們就能夠獲得一個在咱們的Andoid設備上能夠運行的Apk,上線應用市場,還須要咱們對其進行簽名處理,來確保咱們App的惟一性和安全性。整個過程就是所謂的項目構建。java
如何實現整個構建的過程,對於每個構建的步驟,都須要相應的功能模塊來進行,好比Java Code編譯,如何打成dex包等等,而這Android則爲咱們提供了相應的工具,在Android Studio命令行窗口中,咱們能夠經過相應的命令行來進行控制,可是,整個構建過程涉及到不少的步驟,不少的工具的使用,若是都經過命令行來進行控制,勢必會至關麻煩,所以Androd Studio等IDE則對整個過程進行了一個打包,當咱們在Run project的時候,底層的打包工具就會被調用,打包流程都會自動執行。而後咱們只須要對構建文件按照本身的需求進行相應的配置,就能夠構建出本身所須要的項目。android
那麼,整個Andoid項目的構建過程當中,都執行了那些構建的任務呢?面試
首先看一下,Google官方爲咱們提供的詳細的構建過程圖segmentfault
若是你接觸Android開發已經有一段時間了,我想當你看到這張圖的時候,就會以爲很清晰。可是更多的可能會一頭霧水,若是以前沒有閱讀相關的資料的話,那麼,接下來,將針對上述的構建過程,先給出一個概述,這樣你將會整個構建流程在心中有一個框架,而後針對其中具體的細節,進行進一步詳細的講解。安全
圖中綠色標註爲其中用到的相應工具,藍色表明的是中間生成的各種文件類型。bash
經過上述講解,我想對於Android項目的整個構建過程,應該有了一個很清晰的框架了,下面將針對其中的具體的細節,和前面挖的一些坑,來進行更細緻的分析,下圖是一個Android項目構建過程的詳細步驟圖。 框架
接下來的分析,咱們仍是按照上述構建過程概述的順序和流程,進行具體的分析。講到資源文件的處理,咱們先來看一下Android中的資源文件有那些呢?Android應用程序資源能夠分爲兩大類,分別是assets和res: 1. assets類資源放在工程根目錄的assets子目錄下,它裏面保存的是一些原始的文件,能夠以任何方式來進行組織。這些文件最終會被原裝不動地打包在apk文件中。若是咱們要在程序中訪問這些文件,那麼就須要指定文件名來訪問。例如,假設在assets目錄下有一個名稱爲filename的文件,那麼就可使用如下代碼來訪問它:工具
AssetManager am= getAssets();
InputStream is = assset.open("filename");
複製代碼
2. res類資源放在工程根目錄的res子目錄下,它裏面保存的文件大多數都會被編譯,而且都會被賦予資源ID。這樣咱們就能夠在程序中經過ID來訪問res類的資源。res類資源按照不一樣的用途能夠進一步劃分爲如下10種子類型: layout(佈局文件),drawable,xml,value,menu,raw,color,anim,animator,mipmap。 爲了使得一個應用程序可以在運行時同時支持不一樣的大小和密度的屏幕,以及支持國際化,即支持不一樣的國家地區和語言,Android應用程序資源的組織方式有18個維度,每個維度都表明一個配置信息,從而可使得應用程序可以根據設備的當前配置信息來找到最匹配的資源來展示在UI上,從而提升用戶體驗。因爲Android應用程序資源的組織方式能夠達到18個維度,所以就要求Android資源管理框架可以快速定位最匹配設備當前配置信息的資源來展示在UI上,不然的話,就會影響用戶體驗。爲了支持Android資源管理框架快速定位最匹配資源,Android資源打包工具aapt在編譯和打包資源的過程當中,會執行如下兩個額外的操做:佈局
爲何要轉化爲二進制文件?
對於具體的一些操做流程,能夠參考本人以前的一篇文章APK打包安裝過程或者更偏向於源碼層級的老羅的文章。(文後參考文獻連接)
aidl,全名Android Interface Definition Language,即Android接口定義語言。是咱們在編寫進程間通訊的代碼的時候,定義的接口。 輸入:aidl後綴的文件。輸出:可用於進程通訊的C/S端java代碼,位於build/generated/source/aidl。
咱們有了R.java和aidl生成的Java文件,再加上工程的源代碼,如今可使用javac進行正常的java編譯生成class文件了。
輸入:java source的文件夾(另外還包括了build/generated下的:R.java, aidl生成的java文件,以及BuildConfig.java)。輸出:對於gradle編譯,能夠在build/intermediates/classes裏,看到輸出的class文件。
源碼編譯以後,咱們可能還會對其進行代碼的混淆,混淆的做用是增長反編譯的難度,同時也將一些代碼的命名進行了縮短,減小代碼佔用的空間。混淆完成以後,會生成一個混淆先後的映射表,這個是用來在反應咱們的應用執行的時候的一些堆棧信息,能夠將混淆後的信息轉化爲咱們混淆前實際代碼中的內容。 而這個過程使用的工具就是ProGuard,是一個開源的Java代碼混淆器(obfuscation)。ADT r8開始它被默認集成到了Android SDK中。 其具有三個主要功能。
-keep public class com.rensanning.example.Test
複製代碼
調用dx.bat將全部的class文件轉化爲classes.dex文件,dx會將class轉換爲Dalvik字節碼,生成常量池,消除冗餘數據等。因爲dalvik是一種針對嵌入式設備而特殊設計的java虛擬機,因此dex文件與標準的class文件在結構設計上有着本質的區別,當java程序編譯成class後,使用dx工具將全部的class文件整合到一個dex文件,目的是其中各個類可以共享數據,在必定程度上下降了冗餘,同時也是文件結構更加經湊,實驗代表,dex文件是傳統jar文件大小的50%左右。class文件結構和dex文件結構比對。
打包生成APK文件。舊的apkbuilder腳本已經廢棄,如今都已經經過sdklib.jar的ApkBuilder類進行打包了。輸入爲咱們以前生成的包含resources.arcs的.ap_文件,上一步生成的dex文件,以及其餘資源如jni、.so文件。 大體步驟爲 以包含resources.arcs的.ap_文件爲基礎,new一個ApkBuilder,設置debugMode
apkBuilder.addZipFile(f);
apkBuilder.addSourceFolder(f);
apkBuilder.addResourcesFromJar(f);
apkBuilder.addNativeLibraries(nativeFileList);
apkBuilder.sealApk(); // 關閉apk文件
generateDependencyFile(depFile, inputPaths, outputFile.getAbsolutePath());
複製代碼
對APK文件進行簽名。Android系統在安裝APK的時候,首先會檢驗APK的簽名,若是發現簽名文件不存在或者校驗簽名失敗,則會拒絕安裝,因此應用程序在發佈以前必定要進行簽名。簽名信息中包含有開發者信息,在必定程度上能夠防止應用被僞造。對一個APK文件簽名以後,APK文件根目錄下會增長META-INF目錄,該目錄下增長三個文件:
MANIFEST.MF
[CERT].RSA
[CERT]
Android系統就是根據這三個文件的內容對APK文件進行簽名檢驗的。簽名過程主要利用apksign.jar或者jarsinger.jar兩個工具。將根據咱們提供的Debug和Release兩個版本的Keystore進行相應的簽名。
MANIFEST.MF中包含對apk中除了/META-INF文件夾外全部文件的簽名值,簽名方法是先SHA1()(或其餘hash方法)在base64()。存儲形式是:Name加[SHA1]-Digest。
[CERT].SF是對MANIFEST.MF文件總體簽名以及其中各個條目的簽名。通常地,若是是使用工具簽名,還多包括一項。就是對MANIFEST.MF頭部信息的簽名。
[CERT].RSA包含用私鑰對[CERT].SF的簽名以及包含公鑰信息的數字證書。
Zipalign是一個Android平臺上整理APK文件的工具,它首次被引入是在Android 1.6版本的SDK軟件開發工具包中。它可以對打包的Android應用程序進行優化, 以使Android操做系統與應用程序之間的交互做用更有效率,這可以讓應用程序和整個系統運行得更快。用Zipalign處理過的應用程序執行時間達到最低限度,當設備運行APK應用程序時佔更少的RAM。
調用buildtoolszipalign,對簽名後的APK文件進行對齊處理,使APK中全部資源文件距離文件起始偏移爲4字節的整數倍,從而在經過內存映射訪問APK文件時會更快。同時也減小了在設備上運行時的內存消耗。若是對於爲什麼提速不理解,那麼能夠看下內存對齊的規則以及做用該篇文章,對於內存對齊的好處有比較生動詳細的解釋。最終這樣咱們的APK就生成完畢了。
典型的APK中內容
AndroidManifest.xml
程序全局配置文件classes.dex
Dalvik字節碼resources.arsc
資源索引表META-INF
該目錄下存放的是簽名信息res
該目錄存放資源文件assets
該目錄能夠存放一些配置或資源文件至此,對於Andoid項目構建過程的分析已經完成,固然,並沒與深刻到源碼層級的分析,本文的旨在對於構建過程流程上的瞭解和其中一些優化的緣由所在,爲後續經過Gradle插件hook構建過程來作必定的操做,作一個鋪墊。