android工程編譯過程

Android Studio安裝
下載地址:https://developer.android.google.cn/studio/
android studio安裝完后要在安裝jdk(1.8)和sdk版本(24)
1、.gradle gradle編譯系統,版本由wrapper決定
.idea AndroidStudio IDE所需要的文件 IntelliJ IDEA 同樣有這個文件
這兩個目錄下文件都是Android Studio 自動生成的一些文件,我們無需關心,也不要手動去編輯
2、app app項目的代碼、資源等內容幾乎都是放在這個目錄下,我們后期的開發也基本都是在這個目錄下進行
3、build build代碼編譯后生成的文件存放的位置
4、gradle wrapper的jar和配置文件所在位置,這個目錄下包含了gradle wrapper的配置文件使用gradle wrapper的方式不需要提前將gradle下載好,而是會自動根據vending的緩存情況決定是否需要聯網下載gradle
5、.gitgnore git使用的ignore文件 這個文件是用來將指定的目錄或者文件排除在版本控制之外的
6、build.gradle gradle編譯的相關配置文件,這是項目全局的gradle構建腳本,通常這個文件中的內容是不需要修改的
7、gradle.properties gradle相關的全局屬性設置,這個文件是全局的gradle配置文件,在這里配置的屬性將會影響到項目中所有的gradle編譯腳本
8、gradlew Unix下的gradle wrapper 可執行文件
gradlew.bat windows下的gradle wrapper 可執行文件
這兩個文件是用來在命令行界面中執行gradle命令的,其中gradlew是在Linux或者Mac系統使用的,gradle是windows下使用的
9、項目名.iml iml文件是所有Android Studio項目自動生成的文件,我們不需要關心或者修改這個文件的內容
10、local.projecties 本地屬性設置(key設置,android ndk sdk 位置等屬性),這個文件是不推薦上傳到VCS中去的
11、settings.gradle 這個文件用于指定項目中所有引入的模塊。
3.app目錄分析
build 編譯后的文件存在的位置(包括最終生成的apk也在這里面)
libs 依賴的庫所在的位置(jar和aar)
src 源代碼所在的目錄
src/main 主要代碼所在位置
src/main/assets android中附帶的一些文件
src/main/java java代碼所在的位置
src/main/jniLibs jni的一些動態庫所在的默認位置(.so文件)
src/main/res android資源文件的所在位置
src/main/AndroidManifest.xml 清單文件
build.gradle 和這個項目有關的gradle配置,相當于這個項目的Makefile,一些項目的依賴就寫在這里
proguard.pro 代碼混淆配置文件

gradle
build.gradle(Project).png

1.buildscript
buildscript中的聲明是gradle腳本自身需要使用的資源。可以聲明的資源包括依賴項、第三方插件、maven倉庫地址等
2.repositories
顧名思義就是倉庫的意思啦,而jcenter()、maven()和google()就是托管第三方插件的平臺
3.dependencies
當然配置了倉庫還不夠,我們還需要在dependencies{}里面的配置里,把需要配置的依賴用classpath配置上,因為這個dependencies在buildscript{}里面,所以代表的是Gradle需要的插件。
4.allprojects
allprojects塊的repositories用于多項目構建,為所有項目提供共同所需依賴包。而子項目可以配置自己的repositories以獲取自己獨需的依賴包。
5.buildscript和allprojects的作用和區別
buildscript中的聲明是gradle腳本自身需要使用的資源,而allprojects聲明的卻是你所有module所需要使用的資源,就是說每個module都需要用同一個第三庫的時候,你可以在allprojects里面聲明
6.task clean
運行gradle clean時,執行此處定義的task。該任務繼承自Delete,刪除根目錄中的build目錄。相當于執行Delete.delete(rootProject.buildDir)。其實這個任務的執行就是可以刪除生成的Build文件的,跟Android Studio的clean是一個道理。
1.android{}
是Android插件提供的一個擴展類型,可以讓我們自定義Android Gradle工程,是Android Gradle工程配置的唯一入口。
2.compileSdkVersion
是編譯所依賴的Android SDK的版本,這里是API Level。
3.buildToolsVersion
是構建該Android工程所用構建工具的版本。
4.defaultConfig{}
defaultConfig是默認的配置,它是一個ProductFlavor。ProductFlavor允許我們根據不同的情況同時生成多個不同的apk包。
5.applicationId
配置我們的包名,包名是app的唯一標識,其實他跟AndroidManifest里面的package是可以不同的,他們之間并沒有直接的關系。
package指的是代碼目錄下路徑;applicationId指的是app對外發布的唯一標識,會在簽名、申請第三方庫、發布時候用到。
6.minSdkVersion
是支持的Android系統的api level,這里是15,也就是說低于Android 15版本的機型不能使用這個app。
7.targetSdkVersion
表明我們是基于哪個Android版本開發的,這里是22。
8.versionName
表明我們的app應用的版本名稱,一般是發布的時候寫在app上告訴用戶的
9.versionCode
表明我們的app應用的版本,一般app升級基于versionCode(應用市場)
10.multiDexEnabled
用于配置該BuildType是否啟用自動拆分多個Dex的功能。一般用程序中代碼太多,超過了65535個方法的時候。
11.ndk{}
多平臺編譯,生成有so包的時候使用,包括四個平臺'armeabi', 'x86', 'armeabi-v7a', 'mips'。一般使用第三方提供的SDK的時候,可能會附帶so庫。
12.manifestPlaceholders
占位符,我們可以通過它動態配置AndroidManifest文件一些內容
builde(module).png
13.buildType
構建類型,在Android Gradle工程中,它已經幫我們內置了debug和release兩個構建類型,兩種模式主要車別在于,能否在設備上調試以及簽名不一樣,其他代碼和文件資源都是一樣的。一般用在代碼混淆,而指定的混淆文件在下圖的目錄上,minifyEnabled=true就會開啟混淆,shrinkResources=true 縮小APK大小,刪除沒有引用的資源文件(drawable和layout)
image.png
16.dependencies{}
我們平時用的最多的大概就這個了,
首先第一句compile fileTree(include: ['.jar'], dir: 'libs')*,這樣配置之后本地libs文件夾下的擴展名為jar的都會被依賴,非常方便。
如果你要引入某個本地module的話,那么需要用compile project('×××')。
如果要引入網上倉庫里面的依賴,我們需要這樣寫compile group:'com.squareup.okhttp3',name:'okhttp',version:'3.1.0',當然這樣是最完整的版本,縮寫就把group、name、version去掉,然后以":"分割即可。
compile 'com.squareup.okhttp3:okhttp:3.1.0'
但是到了gradle3.0以后build.gradle中的依賴默認為implementation,而不是
之前的compile。另外,還有依賴指令api。
gradle 3.0中其實api跟以前的compile沒什么區別,將compile全部改成api是不會錯的;而implementation指令依賴是不會傳遞的,也就是說當前引用的第三方庫僅限于本module內使用,其他module需要重新添加依賴才能用
5.文件編譯及打包
Make Project:編譯Project下所有Module,一般是自上次編譯后Project下有更新的文件,不生成apk。
Clean Project:刪除之前編譯后的編譯文件,并重新編譯整個Project,比較花費時間,不生成apk。
Rebuild Project:先執行Clean操作,刪除之前編譯的編譯文件和可執行文件,然后重新編譯新的編譯文件,不生成apk,這里效果其實跟Clean Project是一致的,這個不知道Google搞什么鬼~~
Build APK:前面4個選項都是編譯,沒有生成apk文件,如果想生成apk,需要點擊Build APK。
Generate Signed APK:生成有簽名的apk。
打包過程
不管使用什么IDE,Android 打包生成Apk主要都是由以下幾步完成:
1、根據資源文件和AndroidManifest.xml生成R.java文件
2、處理aidl,生成對應的java文件,如果沒有aidl,則跳過
3、編譯工程源碼(主項目,庫)src目錄下所有的源碼,同時上邊生成的R.java和aidl生成的java文件也會被編譯生成相應的class文件
4、將第3步生成的class文件打包生成.dex文件
5、將資源文件打包,生成初始的apk
6、將第4步生成的.dex文件加入到apk中生成未簽名的包
7、apk簽名
一、生成R.java
R.java對于Android開發同學,肯定非常熟悉,它是一個非常重要的一個類,并且它是自動生成的,主要是包含了res目錄下所有資源的ID,我們可以在程序中通過它來獲取資源ID,然后通過Android Api來獲取具體的資源。
TextView tv = (TextView) findViewById(R.id.tv_text);
tv.setText(R.string.app_name);
R.java是由SDK中提供的aapt(sdk/build-tools/ 中對應的版本下,本文使用的26.0.2,那么具體的路徑就是sdk/build-tools/26.0.2)工具生成的。
一、生成R.java
R.java對于Android開發同學,肯定非常熟悉,它是一個非常重要的一個類,并且它是自動生成的,主要是包含了res目錄下所有資源的ID,我們可以在程序中通過它來獲取資源ID,然后通過Android Api來獲取具體的資源。
TextView tv = (TextView) findViewById(R.id.tv_text);
tv.setText(R.string.app_name);
R.java是由SDK中提供的aapt(sdk/build-tools/ 中對應的版本下,本文使用的26.0.2,那么具體的路徑就是sdk/build-tools/26.0.2)工具生成的。
二、javac 編譯所有java文件
這一步其實就是使用jdk的javac將項目中所有的java文件編譯成class文件。
三、打包生成.dex文件
dex文件是Android虛擬機可運行文件,可以使用dx工具生成。
dx工具會將上一步app/src/main/build/中生成的class文件全部打包,得到classes.dex,apk包中包含的classes.dex就是這樣生成的,當然實際項目可能類會很多,但是過程是一樣的。
有了classes.dex,開始要打包apk了
四、打包資源文件
apk包中的資源文件都是經過編譯過的,是二進制文件。我們還是使用aapt工具:
將AndroidManifest.xml與res目錄除了assets目錄以為的文件進行編譯,生成resource.arsc和若干二進制的xml文件。
資源ID和資源文件的對應關系都是在resource.arsc中的。這些文件都會被打包到res.apk中。
五、將.dex打包到apk
直接使用apkbuilder的實現類,該類是sdk/tools/lib/sdklib.jar文件中的
com.android.sdklib.build.ApkBuilderMain
如果沒有出錯,會在out目錄下得到app.apk,解壓后可以看到classes文件以及被打進去了。
到此,已經得到了未簽名的apk,剩下的就是apk簽名了。
六、簽名apk
apk用安裝必須要簽名,我們使用jarsigner給apk手動簽名
APK文件結構和安裝過程
APK文件結構
Android應用是用Java編寫的,利用Android SDK編譯代碼,并且把所有的數據和資源文件打包成一個APK (Android Package)文件,這是一個后綴名為.apk的壓縮文件,APK文件中包含了一個Android應用程序的所有內容,是Android平臺用于安裝應用程序的文件。APK就是一個zip壓縮包,解開這個APK包我們可以看到以下的結構:

image

  1. assets目錄:用于存放需要打包到APK中的靜態文件,和res的不同點在于,assets目錄支持任意深度的子目錄,用戶可以根據自己的需求任意部署文件夾架構,而且res目錄下的文件會在.R文件中生成對應的資源ID,assets不會自動生成對應的ID,訪問的時候需要AssetManager類。
  2. lib目錄:這里存放應用程序依賴的native庫文件,一般是用C/C++編寫,這里的lib庫可能包含4中不同類型,根據CPU型號的不同,大體可以分為ARM,ARM-v7a,MIPS,X86,分別對應著ARM架構,ARM-V7架構,MIPS架構和X86架構,這些so庫在APK包中的構成如下圖Figure2:

image

其中,不同的CPU架構對應著不同的目錄,每個目錄中可以放很多對應版本的so庫,且這個目錄的結構固定,用戶只能按照這個目錄存放自己的so庫。目前市場上使用的移動終端大多是基于ARM或者ARM-V7a架構的,X86和MIPS架構的移動智能終端比較少,所以有些應用程序lib目錄下只包含armeabi目錄或者armeabi-v7a目錄,也就是說,這四個目錄要根據CPU的架構來選,而市面上ARM架構的手機占大多數,所以一般的APK只包含ARM和ARM-V7a的so。

  1. res目錄:res是resource的縮寫,這個目錄存放資源文件,存在這個文件夾下的所有文件都會映射到Android工程的.R文件中,生成對應的ID,訪問的時候直接使用資源ID即R.id.filename,res文件夾下可以包含多個文件夾,其中anim存放動畫文件;drawable目錄存放圖像資源;layout目錄存放布局文件;values目錄存放一些特征值,colors.xml存放color顏色值,dimens.xml定義尺寸值,string.xml定義字符串的值,styles.xml定義樣式對象;xml文件夾存放任意xml文件,在運行時可以通過Resources.getXML()讀取;raw是可以直接復制到設備中的任意文件,他們無需編譯。
  2. META-INF目錄:保存應用的簽名信息,簽名信息可以驗證APK文件的完整性。AndroidSDK在打包APK時會計算APK包中所有文件的完整性,并且把這些完整性保存到META-INF文件夾下,應用程序在安裝的時候首先會根據META-INF文件夾校驗APK的完整性,這樣就可以保證APK中的每一個文件都不能被篡改。以此來確保APK應用程序不被惡意修改或者病毒感染,有利于確保Android應用的完整性和系統的安全性。META-INF目錄下包含的文件有CERT.RSA,CERT.DSA,CERT.SF和MANIFEST.MF,其中CERT.RSA是開發者利用私鑰對APK進行簽名的簽名文件,CERT.SF,MANIFEST.MF記錄了文件中文件的SHA-1哈希值。
  3. AndroidManifest.xml:是Android應用程序的配置文件,是一個用來描述Android應用“整體資訊”的設定文件,簡單來說,相當于Android應用向Android系統“自我介紹”的配置文件,Android系統可以根據這個“自我介紹”完整地了解APK應用程序的資訊,每個Android應用程序都必須包含一個AndroidManifest.xml文件,且它的名字是固定的,不能修改。我們在開發Android應用程序的時候,一般都把代碼中的每一個Activity,Service,Provider和Receiver在AndroidManifest.xml中注冊,只有這樣系統才能啟動對應的組件,另外這個文件還包含一些權限聲明以及使用的SDK版本信息等等。程序打包時,會把AndroidManifest.xml進行簡單的編譯,便于Android系統識別,編譯之后的格式是AXML格式,如下圖Figure3所示:
  4. classes.dex:

傳統的Java程序,首先先把Java文件編譯成class文件,字節碼都保存在了class文件中,Java虛擬機可以通過解釋執行這些class文件。而Dalvik虛擬機是在Java虛擬機進行了優化,執行的是Dalvik字節碼,而這些Dalvik字節碼是由Java字節碼轉換而來,一般情況下,Android應用在打包時通過AndroidSDK中的dx工具將Java字節碼轉換為Dalvik字節碼。dx工具可以對多個class文件進行合并,重組,優化,可以達到減小體積,縮短運行時間的目的

  1. resources.arsc:用來記錄資源文件和資源ID之間的映射關系,用來根據資源ID尋找資源。Android的開發是分模塊的,res目錄專門用來存放資源文件,當在代碼中需要調用資源文件時,只需要調用findviewbyId()就可以得到資源文件,每當在res文件夾下放一個文件,aapt就會自動生成對應的ID保存在.R文件,我們調用這個ID就可以,但是只有這個ID還不夠,.R文件只是保證編譯程序不報錯,實際上在程序運行時,系統要根據ID去尋找對應的資源路徑,而resources.arsc文件就是用來記錄這些ID和資源文件位置對應關系的文件。

APK安裝過程
首先,復制APK安裝包到/data/app下,然后校驗APK的簽名是否正確,檢查APK的結構是否正常,進而解壓并且校驗APK中的dex文件,確定dex文件沒有被損壞后,再把dex優化成odex,使得應用程序啟動時間加快,同時在/data/data目錄下建立于APK包名相同的文件夾,如果APK中有lib庫,系統會判斷這些so庫的名字,查看是否以lib開頭,是否以.so結尾,再根據CPU的架構解壓對應的so庫到/data/data/packagename/lib下。
APK安裝的時候會把DEX文件解壓并且優化為odex
odex在原來的dex文件頭添加了一些數據,在文件尾部添加了程序運行時需要的依賴庫和輔助數據,使得程序運行速度更快。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容