Apk構建基本流程
上圖是Android官方提供的打包簡略流程圖在岂。清晰地展示了一個Android Project經(jīng)過編譯和打包后生成apk文件御蒲,然后再經(jīng)過簽名,就可以安裝到設備上了蜀变。
下面是Gradle Console窗口打印的日志:
Executing tasks: [assembleRelease]
Configuration on demand is an incubating feature.
:app:preBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:compileReleaseAidl UP-TO-DATE
:app:compileReleaseRenderscript UP-TO-DATE
:app:checkReleaseManifest UP-TO-DATE
:app:generateReleaseBuildConfig UP-TO-DATE
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceRelease UP-TO-DATE
:app:generateReleaseResValues UP-TO-DATE
:app:generateReleaseResources UP-TO-DATE
:app:mergeReleaseResources UP-TO-DATE
:app:createReleaseCompatibleScreenManifests UP-TO-DATE
:app:processReleaseManifest UP-TO-DATE
:app:splitsDiscoveryTaskRelease UP-TO-DATE
:app:processReleaseResources UP-TO-DATE
:app:generateReleaseSources UP-TO-DATE
:app:javaPreCompileRelease UP-TO-DATE
:app:compileReleaseJavaWithJavac UP-TO-DATE
:app:compileReleaseNdk NO-SOURCE
:app:compileReleaseSources UP-TO-DATE
:app:lintVitalRelease
:app:mergeReleaseShaders UP-TO-DATE
:app:compileReleaseShaders UP-TO-DATE
:app:generateReleaseAssets UP-TO-DATE
:app:mergeReleaseAssets UP-TO-DATE
:app:transformClassesWithDexBuilderForRelease UP-TO-DATE
:app:transformDexArchiveWithExternalLibsDexMergerForRelease UP-TO-DATE
:app:transformDexArchiveWithDexMergerForRelease UP-TO-DATE
:app:mergeReleaseJniLibFolders UP-TO-DATE
:app:transformNativeLibsWithMergeJniLibsForRelease UP-TO-DATE
:app:processReleaseJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForRelease UP-TO-DATE
:app:packageRelease UP-TO-DATE
:app:assembleRelease
BUILD SUCCESSFUL in 5s
我大概總結了下:
首先是預編譯驻售,如果主module依賴了其它module,那么被依賴的module也要進行編譯。
然后是打包資源文件肴盏。
處理配置清單文件和處理資源文件科盛。
編譯,源碼被編譯成字節(jié)碼菜皂。
執(zhí)行所有transform開頭的任務贞绵。
依賴的library生成.aar文件,application生成.apk文件恍飘。
在看下這張圖 榨崩,android apk構建詳細流程圖
打包步驟:
1. 通過aapt打包res資源文件,生成R.java章母、resources.arsc和res文件(二進制 & 非二進制如res/raw和pic保持原樣)詳細步驟如下:
????????檢查AndroidManifest.xml母蛛,主要做一些檢查并使用parsePackage初始化并設置一些attribute,比如package, minSdkVersion, uses-sdk乳怎。
????????添加被引用資源包使用table.addIncludedResources(bundle, assets)添加被引用資源包彩郊,比如系統(tǒng)的那些android:命名空間下的資源。
????????收集資源文件,處理overlay(重疊包蚪缀,如果指定的重疊包有和當前編譯包重名的資源秫逝,則使用重疊包的);
????????將收集到的資源文件加到資源表(ResourceTable)對res目錄下的各個資源子目錄進行處理询枚,函數(shù)為makeFileResources:makeFileResources會對資源文件名做合法性檢查违帆,并將其添加到ResourceTable內。
????????編譯values資源并添加到資源表,在上一步添加過程中金蜀,其實并沒有對values資源進行處理刷后,因為values比較特殊,需要經(jīng)過編譯之后渊抄,才能添加到資源表中尝胆。
????????給bag資源分配id,在繼續(xù)編譯其他資源之前,我們需要先給bag資源(attrs护桦,比如orientation這種屬性的取值范圍定義的子元素)分配id含衔,因為其他資源可能對它們有引用。
????????編譯xml資源文件,最后我們終于可以編譯xml文件了嘶炭,因為我們已經(jīng)為它準備好了一切可能引用到的東西(value, drawable等)抱慌。程序會對layouts, anims, animators等逐一調用
????????ResourceTable.cpp的,進行編譯逊桦,內部流程又可以分為:解析xml文件眨猎,賦予屬性名稱資源id,解析屬性值强经,扁平化為二進制文件睡陪。
????????編譯AndroidManifest.xml文,拿到AndroidManifest.xml文件,清空原來的數(shù)據(jù),重新解,處理package name重載,把各種相對路徑的名字改為絕對路徑,編譯manifest xml文件,生成最終資源表.9.生成R.java文件
生成我們解壓后看到的那個resources.arsc:
2. 處理.aidl文件兰迫,生成對應的Java接口文件信殊。
aidl,全名Android Interface Definition Language汁果,即Android接口定義語言涡拘。
輸入:aidl后綴的文件宇驾。輸出:可用于進程通信的C/S端java代碼覆旱,位于build/generated/source/aidl慢洋。
3. 通過Java Compiler編譯R.java肮塞、Java接口文件站辉、Java源文件废士,生成.class文件
我們有了R.java和aidl生成的Java文件灶搜,再加上工程的源代碼沧侥,現(xiàn)在可以使用javac進行正常的java編譯生成class文件了善玫。
輸入:java source的文件夾(另外還包括了build/generated下的:R.java, aidl生成的java文件水援,以及BuildConfig.java)。輸出:對于gradle編譯茅郎,可以在build/intermediates/classes里蜗元,看到輸出的class文件。
源碼編譯之后只洒,我們可能還會對其進行代碼的混淆许帐,混淆的作用是增加反編譯的難度,同時也將一些代碼的命名進行了縮短毕谴,減少代碼占用的空間成畦。混淆完成之后涝开,會生成一個混淆前后的映射表循帐,這個是用來在反應我們的應用執(zhí)行的時候的一些堆棧信息,可以將混淆后的信息轉化為我們混淆前實際代碼中的內容舀武。
4. 通過dex命令拄养,將.class文件和第三方庫中的.class文件處理生成classes.dex
調用dx.bat將所有的class文件(上一步生成的以及第三方庫的)轉化為classes.dex文件,dx會將class轉換為Dalvik字節(jié)碼银舱,生成常量池瘪匿,消除冗余數(shù)據(jù)等。
5. 通過apkbuilder工具寻馏,將aapt生成的resources.arsc和res文件棋弥、assets文件和classes.dex一起打包生成apk
打包生成APK文件。舊的apkbuilder腳本已經(jīng)廢棄诚欠,現(xiàn)在都已經(jīng)通過sdklib.jar的ApkBuilder類進行打包了顽染。輸入為我們之前生成的包含resources.arcs的.ap_文件漾岳,上一步生成的dex文件,以及其他資源如jni粉寞、jar包內的資源尼荆。
大致步驟為
以包含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());
6. 通過Jarsigner工具捅儒,對上面的apk進行debug或release簽名
對apk文件進行簽名。APK需要簽名才能在設備上進行安裝很多時候我們在逆向改完后振亮,會因為沒有簽名文件導致最后的apk無法正常使用野芒,又細分為本地驗證和服務器驗證。
7. 通過zipalign工具双炕,將簽名后的apk進行對齊處理狞悲。
調用buildtoolszipalign,對簽名后的apk文件進行對齊處理妇斤,使apk中所有資源文件距離文件起始偏移為4字節(jié)的整數(shù)倍摇锋,從而在通過內存映射訪問apk文件時會更快。同時也減少了在設備上運行時的內存消耗站超。這樣我們的最終apk就生成完畢了荸恕。