javac(编译java文件)
接下来就是编译java文件了,用到的工具就是大家熟知的javac
,通过它将java文件编译成.class
文件。
注解代码也是在这个阶段生成的。当注解的生命周期被设置为CLASS的时候,就代表该注解会在编译class文件的时候生效,并且存在与java源文件和Class字节码文件。
javac的基础命令还是可以了解下:
javac -d destdir(class文件存放目录) srcFile(java文件)
dx/r8/d8 (编译class文件)
这一步就是转换.class
文件为dex
文件。
有人就奇怪了,.class文件不就是JVM可以识别的二进制文件吗,为什么还要进行一次转化呢?
这就涉及到另一个问题:JVM 和 Dalvik(ART)的区别。
其中一个重要的区别就是Dalvik(ART)
有自己的二进制文件,也就是.dex
文件,所以需要将class文件进行再一次转换。
你可以把dex文件理解为一个class文件包,里面装着很多的class文件,让这些类能够共享数据,类似这种关系:
再谈谈这三个工具(dx/r8/d8)的区别:
dx
是最早的转换工具,用于转换class文件为dex文件。- Android Studio 3.1之后,引入了
D8
编译器和R8
工具。
注意这里的措辞:D8 编译器和 R8 工具。
所以D8
就是用来代替dx用来进行转换class文件的,它的优势在于:编译更快、更小的dex文件、更好的性能。
而R8
工具是用来替代ProGuard的,用于代码的压缩和混淆。
编译class文件过程也常用于编译插桩,比如ASM,通过直接操作字节码文件完成代码修改或生成。
apkbuilder/zipflinger(生成APK包)
这一步就是生成APK文件,将manifest文件、resources文件、dex文件、assets文件
等等打包成一个压缩包,也就是apk文件。
在老版本使用的工具是apkbuilder
,但是在最新的版本我发现没有这个工具了,sdk目录下也找不到了。
所以我想到从打包的task——packageDebug
中找找答案,果然,让我找到了新的打包工具——zipflinger
。
//PackageAndroidArtifact.java (packageDebug相关代码) for (File arch : archives) { mApkCreator.writeZip(arch, pathNameMap::get, name -> !names.contains(name)); } mApkCreator =new ApkFlinger(mCreationData, compressionLevel, !mIsDebuggableBuild); /** An implementation of [ApkCreator] using the zipflinger library */ class ApkFlinger
同时在Android Studio
的更新日志中也找到了对应的说明:
Android 构建团队不断进行更改以提高生成性能,在此版本中(Android Studio 3.6),我们将默认打包工具更改为 zipflinger 以进行调试生成。
zipalign(对齐处理)
zipalign 是一种归档对齐工具,可对 Android 应用 (APK) 文件提供重要的优化
具体来说,它会使 APK 中的所有未压缩数据(例如图片或原始文件)在 4 字节边界上对齐。
这里涉及到一个Data structurealignment
(数据对齐)的知识点,其大概意思就是如果数据是自然对齐的,CPU读写就会更高效。
有的朋友可能会疑惑,这个对齐处理不是应该放在签名之后吗?其实这里就涉及到了签名工具的不同带来的对齐处理的顺序不同:
- 如果使用的是
apksigner
,只能在为 APK 文件签名之前执行 zipalign。 - 如果使用的是
jarsigner
,只能在为 APK 文件签名之后执行 zipalign。
下面具体聊聊两种签名工具。
jarsigner/apksigner(签名)
在生成APK文件之后,必须对该apk文件进行签名,否则无法被安装。
之前大家比较熟知的签名工具是JDK提供的jarsigner,而apksigner是Google专门为Android提供的签名和签证工具。
其区别就在于jarsigner只能进行v1签名,而apksigner可以进行v2、v3、v4签名。
什么?还有v4?我开始看到的时候也是大吃一惊,没想到都有v4签名了,那就顺带介绍下这几个签名机制吧:
v1签名
v1签名方式主要是利用META-INFO
文件夹中的三个文件。
首先,将apk中除了META-INFO文件夹中的所有文件进行进行摘要写到 META-INFO/MANIFEST.MF;然后计算MANIFEST.MF文件的摘要写到CERT.SF;最后计算CERT.SF的摘要,使用私钥计算签名,将签名和开发者证书写到CERT.RSA。
所以META-INFO文件夹中这三个文件就能保证apk不会被修改。
但是缺点也很明显,META-INFO文件夹不会被签名,所以美团针对这种签名方式设计了一种多渠道打包方案:
利用pythone在META-INFO文件夹中创建一个文件,其名称就是渠道名,然后用java去读取文件名获取渠道。
v2签名
Android7.0
之后,推出了v2签名,为了解决v1签名速度慢以及签名不完整的问题。
apk本质上是一个压缩包,而压缩包文件格式一般分为三块:
文件数据区,中央目录结果,中央目录结束节。
而v2要做的就是,在文件中插入一个APK签名分块,位于中央目录部分之前,如下图:
这样处理之后,文件就完成无法修改了。
v3签名
Android 9
推出了v3签名方案,和v2签名方式基本相同,不同的是在v3签名分块中添加了有关受支持的sdk版本和新旧签名信息,可以用作签名替换升级。
v4签名
Android 11
推出了v4签名方案。
v4 签名基于根据 APK 的所有字节计算得出的 Merkle 哈希树。它完全遵循 fs-verity 哈希树的结构,将签名存储在单独的.apk.idsig 文件中。
小结图
附1、查看 Gradle 源码
这里提供一种Gradle
源码的查看方式,就是导入Gradle
库,然后在External Libraries
中查看:
implementation 'com.android.tools.build:gradle:4.1.1'
先以依赖的方式导入gradle库,然后编译,就能在左侧External Libraries栏中看到源码了:
参考
https://developer.android.google.cn/studio/build/index.html
https://cloud.tencent.com/developer/article/1392511