Android APK 打包過程 MD

Markdown版本筆記我的GitHub首頁我的博客我的微信我的郵箱
MyAndroidBlogsbaiqiantaobaiqiantaobqt20094baiqiantao@sina.com

Android APK 打包流程 MD


目錄

目錄
APK 的打包流程
整體流程
資源的編譯和打包
資源ID
資源索引
概況
具體打包過程
aapt階段
aidl階段
Java Compiler階段
dex階段
apkbuilder階段
Jarsigner階段
zipalign階段

APK 的打包流程

參考

Android的包文件APK分為兩個部分:代碼和資源,所以打包方面也分為資源打包和代碼打包兩個方面,這篇文章就來分析資源和代碼的編譯打包原理。

Android打包流程詳圖:

apk_package_flow_detail.png

整體流程

APK整體的的打包流程如下圖所示:

apk_package_flow.png

具體說來:

  • 通過AAPT工具進行資源文件(包括AndroidManifest.xml、布局文件、各種xml資源等)的打包,生成R.java文件。
  • 通過AIDL工具處理AIDL文件,生成相應的Java文件。
  • 通過Javac工具編譯項目源碼,生成Class文件。
  • 通過DX工具將所有的Class文件轉換成DEX文件,該過程主要完成Java字節碼轉換成Dalvik字節碼,壓縮常量池以及清除冗余信息等工作。
  • 通過ApkBuilder工具將資源文件、DEX文件打包生成APK文件。
  • 利用KeyStore對生成的APK文件進行簽名。
  • 如果是正式版的APK,還會利用ZipAlign工具進行對齊處理,對齊的過程就是將APK文件中所有的資源文件舉例文件的起始距離都偏移4字節的整數倍,這樣通過內存映射訪問APK文件的速度會更快。

上述流程都是Android Studio在編譯時調用各種編譯命令自動完成的,具體說來,如下所示:

1、創建Android工程。

android create project \
-n packageTest2 \
-a MainActivity \
-k com.package.test2 \
-t android-23 \
-p ./PackageTest2

2、編譯R文件

aapt package \
-f \
-J ./gen \
-M ./AndroidManifest.xml \
-S ./res/ \
-I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar

3、編譯源代碼文件

javac -source 1.6 \
-target 1.6 \
-cp /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \
./src/com/packtest/test1/MainActivity.java ./src/com/packtest/test1/R.java \
-d ./gen/classes

4、編譯DEX文件

dx --dex \
--verbose \
--output ./gen/dex/packtest1.dex
./gen/classes/

5、生成APK文件

aapt package
-f \
-J ./gen \
-M ./AndroidManifest.xml \
-S ./res/ \
-I /Users/RadAsm/Library/AndroidSDK/sdk/platforms/android-23/android.jar \
-F ./output/res.apk

6、APK文件對齊

zipalign -v -p 4 packagetest_unsigned.apk packagetest_aligned_unsigned.apk

7、APK簽名

apksigner sign --ks my-release-key.jks my-app.apk

以上便是APK打包的整個流程,我們再來總結一下:

  • 除了assets和res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理;
  • 除了assets資源之外,其它的資源都會被賦予一個資源ID;
  • 打包工具負責編譯和打包資源,編譯完成之后,會生成一個resources.arsc文件和一個R.java,前者保存的是一個資源索引表,后者定義了各個資源ID常量。
  • 應用程序配置文件AndroidManifest.xml同樣會被編譯成二進制的XML文件,然后再打包到APK里面去。
  • 應用程序在運行時通過AssetManager來訪問資源,或通過資源ID來訪問,或通過文件名來訪問。

理解了整體的流程,我們再來看看具體的細節。

資源的編譯和打包

在分析資源的編譯和打包之前,我們先來了解一下Android程序包里有哪些資源。

我們知道Android應用程序的設計也是代碼與資源相分離的,Android的資源文件可以分為兩大類:

assets:assets資源放在主工程assets目錄下,它里面保存一些原始的文件,可以以任何方式來進行組織,這些文件最終會原封不動的被打包進APK文件中。

獲取asset資源也十分簡單,如下所示:

InputStream is = getAssets.open("fileName");

res:res資源放在主工程的res目錄下,這類資源一般都會在編譯階段生成一個資源ID供我們使用。

res資源包含了我們開發中使用的各種資源,具體說來:

  • animator
  • anim
  • color
  • drawable
  • layout
  • menu
  • raw
  • values
  • xml

這些資源的含義大家應該都很熟悉,這里就不再贅述。

上述9種類型的資源文件,除了raw類型資源,以及Bitmap文件的drawable類型資源之外,其它的資源文件均為文本格式的XML文件,它們在打包的過程中,會被編譯成二進制格式的XML文件。這些二進制格式的XML文件分別有一個字符串資源池,用來保存文件中引用到的每一個字符串,包括XML元素標簽、屬性名稱、屬性值,以及其它的一切文本值所使用到的字符串。這樣原來在文本格式的XML文件中的每一個放置字符串的地方在二進制格式的XML文件中都被替換成一個索引到字符串資源池的整數值,這寫整數值統一保存在
R.java類中,R.java會和其他源文件一起編譯到APK中去。

前面我們提到xml編寫的Android資源文件都會編譯成二進制格式的xml文件,資源的打包都是由AAPT工具來完成的,資源打包主要有以下流程:

  • 解析AndroidManifest.xml,獲得應用程序的包名稱,創建資源表。
  • 添加被引用資源包,被添加的資源會以一種資源ID的方式定義在R.java中。
  • 資源打包工具創建一個AaptAssets對象,收集當前需要編譯的資源文件,收集到的資源保存在AaptAssets對象對象中。
  • 將上一步AaptAssets對象保存的資源,添加到資源表ResourceTable中去,用于最終生成資源描述文件resources.arsc
  • 編譯values類資源,這類資源包括數組、顏色、尺寸、字符串等值。
  • 給bag、style、array這類資源分配資源ID。
  • 編譯xml資源文件,編譯的流程分為四步:① 解析xml文件 ② 賦予屬性名稱資源ID ③ 解析屬性值 ④ 將xml文件從文本格式轉換為二進制格式。
  • 生成資源索引表resources.arsc

資源ID

每個Android項目里都有有一個R.java文件,如下所示:

public final class R {//...public static final class anim {public static final int abc_fade_in=0x7f010000;}public static final class attr {public static final int actionBarDivider=0x7f020000;}public static final class string {public static final int actionBarDivider=0x7f020000;}//...
}

每個資源項后的整數就是資源ID,資源ID是一個4字節的無符整數,如下所示:

  • 最高字節是Package ID表示命名空間,標明資源的來源,Android系統自己定義了兩個Package ID,系統資源命名空間:0x01 和 應用資源命名空間:0x7f。
  • 次字節是Type ID,表示資源的類型,例如:anim、color、string等。
  • 最低兩個字節是Entry ID,表示資源在其所屬資源類型中所出現的次序。

資源索引

上面提到,最終生成的是資源索引表resources.arsc,Android正是利用這個索引表根據資源ID進行資源的查找,為不同語言、不同地區、不同設備提供相對應的最佳資源。查找是通過Resources和AssetManger來完成的,這個我們下面會講。

resources.arsc 是一個編譯后的二進制文件,在Android Stduio里打開以后是這樣的,如下所示:
resources_arsc_file.png

可以看到resources.arsc里存放了各類資源的索引參數和配置信息。

resources.arsc的文件格式如下所示:
resources_arsc_structure.png

注:整個文件都是有一系列chuck(塊)構成的,chuck是整個文件的劃分單位,每個模塊都是一個chuck,chuck最前面是一個ResChunk_header的結構體,用來描述整個chunk的信息,更多關于索引表格式的細節,可以查閱源碼:

? ResourceTypes.h

resources.arsc 索引表從上至下文件格式依次為:

  • 文件頭:數據結構用ResTable_header來描述,用來描述整個文件的信息,包括文件頭大小,文件大小,資源包Package的數量等信息。
  • 全局字符串池:存放所有的字符串,所以資源復用這些字符串,字符串里存放的是資源文件的路徑名和資源值等信息。全局字符串池分為資源類型(type)字符串池和
  • 資源包:會有多個(例如:系統資源包、應用資源包)。

資源包也被劃分為以下幾個部分:

  • 包頭:描述資源包相關信息。
  • 資源類型字符串池:存放資源的類型。
  • 資源名稱字符串池:存放資源的名稱。
  • 配置列表:存放語音、位置等手機配置信息,用來作為查找資源的標準。

從這里可以看到resources.arsc索引表存在很多常量池,常量池的使用目的也很明顯,就是提供資源的復用率,減少resources.arsc索引表的體積,提高索引效率。

概況

參考

Android APK是如何來的呢?

懷著這個問題去查資料,發現了下邊這張圖。

解壓一個普通的apk文件后,解壓出來的文件包括:

  • classes.dex:.dex文件
  • resources.arsc:resources resources文件
  • AndroidManifest.xml:AndroidManifest.xml文件
  • res:uncompiled resources
  • META-INF:簽名文件夾
    • MANIFEST.MF文件:版本號以及每一個文件的哈希值(BASE64),包括資源文件。這個是對每個文件的整體進行SHA1(hash)。
    • CERT.SF:這個是對每個文件的頭3行進行SHA1 hash。
    • CERT.RSA:這個文件保存了簽名和公鑰證書。

具體打包過程

aapt階段

使用aapt來打包res資源文件,生成R.java、resources.arsc和res文件(二進制 & 非二進制如res/raw和pic保持原樣)

  • res目錄,有9種子目錄
  • R.java文件。里面擁有很多個靜態內部類,比如layout,string等。每當有這種資源添加時,就在R.java文件中添加一條靜態內部類里的靜態常量類成員,且所有成員都是int類型。
  • resources.arsc文件。這個文件記錄了所有的應用程序資源目錄的信息,包括每一個資源名稱、類型、值、ID以及所配置的維度信息。我們可以將這個文件想象成是一個資源索引表,這個資源索引表在給定資源ID和設備配置信息的情況下,能夠在應用程序的資源目錄中快速地找到最匹配的資源。

aidl階段

AIDL,Android接口定義語言,Android提供的IPC的一種獨特實現。
這個階段處理.aidl文件,生成對應的Java接口文件。

Java Compiler階段

通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。

dex階段

通過dex命令,將.class文件和第三方庫中的.class文件處理生成classes.dex。

apkbuilder階段

classes.dexresources.arscres文件夾(res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理)、Other Resources(assets文件夾)、AndroidManifest.xml打包成apk文件。

Jarsigner階段

對apk進行簽名,可以進行Debug和Release 簽名。

zipalign階段

release mode 下使用 aipalign 進行align,即對簽名后的apk進行對齊處理。

Zipalign是一個android平臺上整理APK文件的工具,它對apk中未壓縮的數據進行4字節對齊,對齊后就可以使用mmap函數讀取文件,可以像讀取內存一樣對普通文件進行操作。如果沒有4字節對齊,就必須顯式的讀取,這樣比較緩慢并且會耗費額外的內存。

在 Android SDK 中包含一個名為 zipalign 的工具,它能夠對打包后的 app 進行優化。 其位于 SDK 的 \build-tools\23.0.2\zipalign.exe 目錄下

2019-2-18

轉載于:https://www.cnblogs.com/baiqiantao/p/10398653.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387385.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

可用于 主成分分析、R型因子分析、簡單相應分析 的R語言函數總結

一、主成分分析 主成分分析是多元統計分析的一種常用的降維方法,它以盡量少的信息損失,最大程度將變量個數減少,且彼此間互不相關。提取出來的新變量成為主成分,主成分是原始變量的線性組合。 1.1 KMO檢驗和Bartlett球形檢驗 在…

[國家集訓隊]墨墨的等式

Description 墨墨突然對等式很感興趣,他正在研究a1x1a2y2…anxnB存在非負整數解的條件,他要求你編寫一個程序,給定N、{an}、以及B的取值范圍,求出有多少B可以使等式存在非負整數解。 Input 輸入的第一行包含3個正整數,…

Storm簡介

Storm是實時流式數據處理框架,支持多種編程語言 應用案例: realtime analytics online machine learning continuous computation distributed RPC ETL 性能:a million tuples per second per node 可擴展、高容錯 結合消息隊列和數據庫…

持續集成之Jenkins安裝部署

安裝JDKJenkins是Java編寫的,所以需要先安裝JDK,這里采用yum安裝,如果對版本有需求,可以直接在Oracle官網下載JDK。 [rootlinux-node1 ~]# yum install -y java-1.8.0 安裝Jekins [rootlinux-node1 ~]# cd /etc/yum.repos.d/ […

2019/2/18 Python今日收獲

Python day15——032,033異常處理:你不可能總是對的 1. Python標準異常總結AssertionError斷言語句(assert)失敗AttributeError嘗試訪問未知的對象屬性EOFError用戶輸入文件末尾標志EOF(Ctrld)FloatingPoin…

Shell01

shell是一個命令解釋器,是操作系統的最外層。 把用戶的輸入解釋給操作系統,將操作系統的輸入結果返回給用戶。 硬件-->kernel-->shell-->外圍應用程序 shell腳本:將命令或語句寫入文件,進行操作系統管理。 shell腳本…

jenkins svn tomcat ant自動部署

Jenkins Jenkins是基于Java開發的一種持續集成工具,用于監控持續重復的工作,功能包括: 1、持續的軟件版本發布/測試項目。 2、監控外部調用執行的工作。 跟其他持續集成相比,它的主要優點有: 開源,即免…

Shell02

局部變量 1、普通字符串變量 變量名value 變量名value #單引號中不進行變量解析,原樣輸出,應用不多 變量名"value" #雙引號會解析變量 例: a1123 a2234 a3"345" echo "a1$a1" echo "a2$a2&quo…

553 mail from must equal authorized user解決方法

在配置發送郵件通知,驗證其正確性時,出現"553 mail from must equal authorized user"提示的錯誤; 原因在于沒有在"系統管理(Manage Jenkins)"的"系統設置(Configure system&…

3.1 讀入一個參數

已知正方形的邊長&#xff0c;求出其面積。 輸入樣例&#xff1a; 1 2 3 4 輸出樣例&#xff1a; 1 4 9 16 #include<iostream> #include<fstream> using namespace std;int main() {ifstream cin("test.txt");//向OJ提交時&#xff0c;注釋此句i…

[Apple開發者帳戶幫助]八、管理檔案(2)創建臨時配置文件(iOS,tvOS,watchOS)...

創建臨時配置文件以在設備上運行您的應用程序而無需Xcode。在開始之前&#xff0c;您需要一個App ID&#xff0c;一個分發證書和多個注冊設備。 有關完整的臨時配置文件工作流程&#xff0c;請轉到Xcode幫助中的分發到已注冊設備&#xff08;iOS&#xff0c;tvOS&#xff0c;wa…

Ant Build.xml

題記&#xff1a;用 Eclipse 3 &#xff0b;Tomcat 5 做東東&#xff0c;用起來還是比較爽。但是調試時每次手動Deploy到Tomcat中&#xff0c;比較麻煩。今用Ant來完成之。 1。打開Eclipse&#xff0c;在項目的根路徑下建立builds.xml文件。 這個是Ant配置的關鍵。其內容如下&…

3.2 讀入兩個參數

計算兩個整數的差。 輸入樣例&#xff1a; 1 3 5 7 輸出樣例&#xff1a; -2 -2 #include<iostream> #include<fstream> using namespace std;int main() {ifstream cin("test.txt");//向OJ提交時&#xff0c;注釋此句int num1, num2;while (cin &g…

解決做好一個機器學習項目的3個問題

機器學習是目前人工智能最令人激動的研究方向之一。我們可能更關注機器學習算法的實現細節&#xff0c;沉浸于機器學習所需要的數學功底&#xff0c;但對于機器學習從業者來說&#xff0c;如何更好更快速的實現一個機器學習項目更值得關注。 正如吳恩達在《機器學習》這門課中所…

數據挖掘的相關知識例子

一、貝葉斯 貝葉斯定理由英國數學家貝葉斯 ( Thomas Bayes 1702-1761 ) 發展&#xff0c;用來描述兩個條件概率之間的關系&#xff0c;比如 P(A|B) 和 P(B|A)。按照乘法法則&#xff0c;可以立刻導出&#xff1a;P(A∩B) P(A)*P(B|A)P(B)*P(A|B)。如上公式也可變形為&#xf…

3.3 1!到n!的和

求1! 2! ... n! 的結果。 輸入樣例&#xff1a; 3 6 輸出樣例 9 873 #include<iostream> #include<fstream> using namespace std;int main() {ifstream cin("test.txt");//向OJ提交時&#xff0c;注釋此句int num;while (cin >> num){int…

[幣嚴區塊鏈]以太坊(ETH)Dapp開發入門教程之寵物商店領養游戲

閱讀本文前&#xff0c;你應該對以太坊、智能合約有所了解&#xff0c;如果你還不了解&#xff0c;建議你先看以太坊是什么 除此之外&#xff0c;你最好還了解一些HTML及JavaScript知識。 本文通過實例教大家來開發去中心化應用&#xff0c;應用效果如圖: 項目背景 Pete有一個…

怎么通俗易懂地解釋貝葉斯網絡和它的應用?

作者&#xff1a;小杰鏈接&#xff1a;https://www.zhihu.com/question/28006799/answer/38996563來源&#xff1a;知乎著作權歸作者所有。商業轉載請聯系作者獲得授權&#xff0c;非商業轉載請注明出處。英語原文&#xff1a;http://www.norsys.com/tutorials/netica/secA/tut…

3.4 等比數列

已知q與n&#xff0c;求等比數列之和&#xff1a;1 q q^2 ... q^n 輸入樣例&#xff1a; 6 0.3 5 1.3 輸出樣例&#xff1a; 1.428 12.756 #include<iostream> #include<fstream> #include<cmath> using namespace std;int main() {ifstream cin(…

SVM分類算法的基本理論問題

1.引言   隨著網絡技術的飛速發展和普及&#xff0c;進入了信息大爆炸的時代。信息無處不在&#xff0c;給我們的學習生活帶來了諸多便捷&#xff0c;由于堪稱海量的信息量&#xff0c;我們從中獲取有用的信息變得困難&#xff0c;解決這一難題就是要對這些大量的信息進行分…