正常的編譯原理
按照google給出的編譯步驟如下:
1> source build/envsetup.sh:加載命令
2> lunch:選擇平臺編譯選項
3> make:執行編譯
https://www.cnblogs.com/shakin/p/4615872.html
java編譯過程
Android的4種文件類型Java,class,dex,apk
Java文件-----應用程序源文件
Android本身相當一部分都是用java編寫而成(基本上架構圖裏頭藍色的部份都是用Java開發的),android的
應用必須使用java來開發
Class文件------Java編譯後的目標文件
不像J2se,java編譯成class就可以直接運行,android平臺上class文件不能直接在android上運行。 由於Google
使用了自己的Dalvik來運行應用, 所以這裏的class也肯定不能在AndroidDalvik的java環境中運行, android
的class文件實際上只是編譯過程中的中間目標文件,需要鏈接成dex文件後才能在dalvik上運行
Dex文件-----Android平臺上的可執行文件
Android虛擬機Dalvik支持的字節碼文件格式Google在新發布的Android平臺上使用了自己的Dalvik虛擬機
來定義, 這種虛擬機執行的並非Java字節碼, 而是另一種字節碼: dex格式的字節碼。在編譯Java代碼之後,
通過Android平臺上的工具可以將Java字節碼轉換成Dex字節碼。雖然Google稱Dalvik是爲了移動設備定
做的,但是業界很多人認爲這是爲了規避向sun申請Javalicense。這個DalvikVM針對手機程式/CPU做過最
佳化,可以同時執行許多VM而不會佔用太多Resource。
Apk文件-------Android上的安裝文件
Apk是Android安裝包的擴展名,一個Android安裝包包含了與某個Android應用程序相關的所有文件。apk
文件將AndroidManifest.xml文件、應用程序代碼(.dex文件)、資源文件和其他文件打成一個壓縮包。一個工
程只能打進一個.apk文件
來源: https://www.cnblogs.com/xgjblog/p/5809449.html
大概的意思是編譯成java字節碼之後可以在任何平臺使用
下面是一些區別
java執行的流程
而後使用java虛擬機運行
加載的時候關鍵的就是如何加載和獲取程序相關的文件等
加載之後需要進行執行的過程
將程序運行起來之後,就是數據的分佈
上文已經說過dex文件和class文件的各自作用,下面是二者的比對
生成的過程
dex結構分成三部分:
文件頭:表明了是dex文件,已經文件的大小等等數據
索引頭:如下圖所示
數據區:數據區,就像是jvm中的堆保存方法+變量。
https://www.jianshu.com/p/cfeb8dec53c3
// Raw header_item.
struct Header {
uint8_t magic_[8];
uint32_t checksum_; // See also location_checksum_
uint8_t signature_[kSha1DigestSize];
uint32_t file_size_; // size of entire file
uint32_t header_size_; // offset to start of next section
uint32_t endian_tag_;
uint32_t link_size_; // unused
uint32_t link_off_; // unused
uint32_t map_off_; // unused
uint32_t string_ids_size_; // number of StringIds
uint32_t string_ids_off_; // file offset of StringIds array
uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535
uint32_t type_ids_off_; // file offset of TypeIds array
uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535
uint32_t proto_ids_off_; // file offset of ProtoIds array
uint32_t field_ids_size_; // number of FieldIds
uint32_t field_ids_off_; // file offset of FieldIds array
uint32_t method_ids_size_; // number of MethodIds
uint32_t method_ids_off_; // file offset of MethodIds array
uint32_t class_defs_size_; // number of ClassDefs
uint32_t class_defs_off_; // file offset of ClassDef array
uint32_t data_size_; // unused
uint32_t data_off_; // unused
......
}
file_size_: 整個文件的大小,單位字節
header_size_: 文件頭的大小,單位字節
string_ids_size_: 字符串列表中字符串的數量
string_ids_off_: 字符串列表在文件中的偏移
type_ids_size_: 類型列表中元素數量
type_ids_off_: 類型列表在文件中的偏移
proto_ids_size_: 方法原型列表元素數量
proto_ids_off_: 方法原型列表在文件中的偏移
field_ids_size_: 字段列表的元素數量
field_ids_off_: 字段列表在文件中的偏移
method_ids_size_: 方法列表元素的數量
method_ids_off_: 方法列表在文件中的偏移
class_defs_size_: 類定義列表中元素數量
class_defs_off_: 類定義列表在文件中的偏移
data_size_: data段的大小
data_off_: data段在文件中的偏移
鏈接:https://www.jianshu.com/p/7afbadd6099f 具體的介紹 很多的
一個真實的例子
apk打包過程
Android安裝包的後綴都是.apk, apk是Android Package的縮寫。 解壓apk文件後包含AndroidManifest.xml、assets目錄、classes.dex(還可能有 classes2.dex,classes3.dex...classesN.dex)、lib目錄、META-INF目錄、res目錄和resources.arsc。
ndroidManifest.xml對應源代碼中的AndroidManifest.xml, 但這裏是編譯過的,文件內容已經不同了。
assets對應源代碼的assets目錄, 是直接複製過來的。
classes.dex是包含所有Java文件對應的字節碼。
lib目錄對應源代碼中的libs目錄,包含so文件。
META-INF目錄包含CERT.RSA、CERT.SF、MANIFEST.MF等, 保存了各個資源文件的SHA1值,用於校驗資源文件是否被篡改,從而防止二次打包時資源文件被替換。
res目錄對應源碼的res目錄, 包含各種圖片、xml等。
resources.arsc包含了各個資源文件的映射, 可以理解爲索引, 通過該文件能找到對應的資源文件信息。
(AAPT - Android Asset Packaging Tool AAPT是Android資源打包工具)資源打包的過程如下:
1.從圖中我們可以看出
(1)除了assets和res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理「2」。
(2)除了assets資源之外,其它的資源都會被賦予一個資源ID。包括res/raw也會有資源ID,即R.id.resourceId。
(3)打包工具負責編譯和打包資源,編譯完成之後,會生成一個resources.arsc文件和一個R.java,前者保存的是一個資源索引表,後者定義了各個資源ID常量。
這個在AS中我們編譯的時候也看到了
還是沒明白resources.arsc和R.java存在的意義?我們可以這樣想,一個項目由代碼和資源文件組成,代碼通過對資源的處理來展現業務流程,那我們代碼中肯定要獲取到某個所需要的資源吧?Android爲了方便管理,就定了一個文件,裏面定義了各個專屬資源ID常量,來表示我們項目中存在的資源。寫代碼的時候,我們要用某個資源,是不是都是類似這樣寫:tvMrchNo = (TextView) findViewById(R.id.tv_mrch_no);
apk打包過程圖,其中包括資源打包 代碼的編譯等 資源打包的方法在上邊已經說過了這裏主要是看流程
從上圖中可以看到。完整的打包流程應該是:
(1)打包資源文件。
(2)處理aidl文件,生成相應java 文件。對於沒有使用到aidl的android工程,可以跳過此步驟。
(3)編譯工程源代碼,生成相應class 文件。
這一步調用了javac編譯工程src目錄下所有的java源文件,生成的class文件位於工程的bin\classes目錄下,上圖假定編譯工程源代碼時程序是基於android SDK開發的,實際開發過程中,也有可能會使用android NDK來編譯native代碼,因此,如果可能的話,這一步還需要使用android NDK編譯C/C++代碼,當然,編譯C/C++代碼的步驟也可以提前到第一步或第二步。通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。
(4)轉換所有class文件,生成classes.dex文件。Android虛擬機的可執行文件爲dex格式,所以需要此步驟。
(5)打包生成apk。打包後的res文件夾(除res/raw資源被原裝不動地打包進APK之外)、打包後類文件(.dex文件)、libs文件(包括.so文件,當然很多工程都沒有這樣的文件,如果你不使用C/C++開發的話)、resources.arsc、assets、AndroidManifest.xml打包成apk文件。
(6)對apk文件進行簽名。
(7)對簽名後的apk文件進行對其處理。在 Android SDK 中包含一個名爲 “zipalign” 的工具,它能夠對打包後的 app 進行優化。 即對簽名後的apk進行對齊處理。
另外一種圖示結構,這裏主要爲了說明的是源碼的編譯流程
源碼進行javac編程class文件 然後編譯爲dex文件,然後進行一系列處理,簽名 優化等 最後生成可以打包apk文件
除了上述標註的,還有以下參考文章
https://www.jianshu.com/p/d29c37dda256
https://blog.csdn.net/brycegao321/article/details/79127159
https://www.jianshu.com/p/7afbadd6099f