正常的编译原理
按照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