Android系统的APK应用程序可以有以下几种编译方式
借助系统编译:利用Android.mk 文件将众多小项目组织起来
借助IDE编译:AndroidStudio
命令行编译 : 比如利用gradle脚本编译APK应用。
一、 通过命令行编译和打包APK
编译命令(Window系统)
./gradlew build 检查依赖并且编译打包
./gradlew assembleDebug/assembleRelease 编译并打出Debug包 /Release包
./gradlew installDebug 编译出Debug包并且安装
./gradlew installRelease 编译出Release包并且安装
./gradlew assembleDebug/assembleRelease --info 编译包并且打印日志
./gradlew assembleDebug/assembleRelease --scan 编译并且输出更详细的报告
./gradlew clean 清除构建目录下的文件
./gradlew unsinstall <packageName> 卸载安装
./gradlew uninstallDebug / uninstallRelease 卸载安装包
// task相关
./gradlew --tasks 查看主要Task
./gradlew tasks --all 查看所有Task
./gradlew <taskName> or ./gradlew :<moduleName>:<taskName> 执行Task
// 查看依赖
./gradlew dependencies 查看项目根目录下的依赖
./gradlew :app:dependencies 查看app模块下的依赖
./gradlew :app:dependencies > dependencies.txt 查看依赖输出到文件
//性能相关
./gradlew assembleDebug --offline 离线编译
./gradlew assembleDebug --build-cache 可开启缓存
./gradlew assembleDebug --no-build-cache 不开启
./gradlew assembleDebug --configuration-cache 配置缓存开启
./gradlew assembleDebug --no-configuration-cache 不开启
./gradlew assembleDebug --parallel 并行构建开启
./gradlew assembleDebug --no-parallel 不开启
二、 APK编译过程详情
以apk后缀的文件是Android应用系统的标准格式,其实是一个压缩包,用压缩工具截出来,可以看到一个apk应用程序至少包含一下几部分内容 :
|-- AndroidManifest.xml
|-- cleasses.dex
|-- resources.arsc
|-- res
| |-- drawable
| | -- *.png
| |-- layout
| -- *.xml
|
|-- META-INF
| |-- CERT.RSA
| |-- CERT.SF]
| |-- MANIFEST.MF
| |
|
APK编译过程图解
可以清楚看到整个编译过程涉及到了许多工具
1. 首先是.aidl文件要经过aidl工具转换成编译器能处理的Java接口文件。
2. 同时资源文件将aapt处理为最终的resources.arsc,并且生产R.java。
3. Java编译器统一将Java源码,R.java等文件统一变异成.class 文件。
4. dex工具将.class工具转换成Android系统所能识别的格式dex。
5. 接下里dex、资源等通过apkbuilder生成初始的APK 。
6. apk签名。 签名工具有很多。
7. 签名后apk通过zipalign进行优化。
三、 应用程序签名源码简析
接下里分析一下源码来了解META-INF文件的用途以及签名校验大致流程。 应用程序安装时候,首先是PackageManger会对其进行初始化。这包含对签名和文件哈希值的检查。
1.PackageParser 负责解析应用程序包,并完成安全校验
private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {.... PackageParser pp = new PackageParser();...pkg = pp.parsePackage(tmpPackageFile, parseFlags);.... try {// either use what we've been given or parse directly from the APKif (args.certificates != null) {try {PackageParser.populateCertificates(pkg, args.certificates);} catch (PackageParserException e) {// there was something wrong with the certificates we were given;// try to pull them from the APKPackageParser.collectCertificates(pkg, parseFlags);}} else {PackageParser.collectCertificates(pkg, parseFlags);}} catch (PackageParserException e) {res.setError("Failed collect during installPackageLI", e);return;}
}
2. PackageParser通过collectCertificates()来检验程序包中所有文件是否都符合要求,然后才能返回PackageManager继续执行安装过程。 这个函数分为以下关键部分:
解析package包,得到所以文件 ,对这些文件逐一检验。 安全检查关键在于loadCertificates
private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
633 throws PackageParserException {
634 InputStream is = null;
635 try {
636 // We must read the stream for the JarEntry to retrieve
637 // its certificates.
638 is = jarFile.getInputStream(entry);
639 readFullyIgnoringContents(is);
640 return jarFile.getCertificateChains(entry);
641 } catch (IOException | RuntimeException e) {
642 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
643 "Failed reading " + entry.getName() + " in " + jarFile, e);
644 } finally {
645 IoUtils.closeQuietly(is);
646 }
647 }
648
整个检验过程主要涉及以下几点:
CERT.RSA
这是应用程序开发者提供的证书,包含开发者的公钥和一些列身份信息。因为是自签名的,就不需要CA认证。
CERT.SF
后缀名.SF 应该是Signature File的缩写,所以就是我们所说的签名文件。 它是对某个文件的HASH值进行私钥加密产生的。 它是对真个MANIFEST.MF 进行加密---它包好了应用中所有文件的Hash值。
MANIFEST.MF
/frameworks/base/core/java/android/util/jar/StrictJarVerifier.java
void verify() {
141 byte[] d = digest.digest();
142 if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
143 throw invalidDigest(JarFile.MANIFEST_NAME, name, name);
144 }
145 verifiedEntries.put(name, certChains);
146 }
文件 SHA-1是经过了Base64编码的,所以这里要解码在对比。
这样就确保了Android的应用程序没有被恶意篡改,有效的保护了开发者的权益。
V2的校验过程(略)
四、应用签名
我们可以利用sdk中的build-tools里面的apksigner工具来验证一下apk用了那种方式签名。
V2签名的信息存储在Android应用程序的APK文件中的签名块(Signature Block)中。签名块是APK文件的一部分,用于存储应用程序的数字签名信息。
在APK文件的二进制结构中,签名块位于文件的末尾,紧跟在ZIP目录结构之后。签名块使用特定的格式存储签名信息,包括应用程序的证书和签名本身。
要查看APK文件中的签名信息,你可以使用Android SDK提供的工具和命令行选项。一个常用的工具是apksigner,它可以用于验证应用程序的签名并提供签名块的详细信息。
以下是使用apksigner命令查看APK文件签名信息的示例:
apksigner verify --print-certs path/to/your/app.apk
这些签名方案用于验证Android应用程序的完整性和真实性,并确保应用程序在安装和运行时没有被篡改。
V1签名(JAR签名):V1签名是早期版本的Android应用程序签名方案。它使用基于JAR(Java Archive)的签名方式,将整个APK文件视为JAR文件,并使用基于RSA的数字签名算法对其进行签名。V1签名方案在Android 1.0至7.0版本中使用。
V2签名(APK签名):V2签名是Android引入的第二个签名方案,用于增强应用程序的安全性和完整性保护。V2签名将APK文件分为多个部分,并对每个部分进行签名,以提供更好的验证和错误检测。V2签名方案使用基于RSA的数字签名算法,并在APK文件末尾添加签名块。V2签名方案从Android 7.0开始引入,并成为默认的签名方案。
V3签名(APK签名):V3签名是在V2签名基础上进行改进的签名方案。它引入了APK签名方案V2的补充,并使用ECDSA(椭圆曲线数字签名算法)来生成签名。V3签名进一步提高了应用程序验证的安全性,并提供了更好的完整性保护。V3签名方案从Android 9.0开始引入。
V4签名(APK签名):V4签名是Android在Android 11中引入的新签名方案。它是对V2签名的扩展,旨在提供更快的应用程序安装速度和更小的APK文件大小。V4签名使用了更高效的签名算法和压缩技术,以减少签名数据的大小。V4签名方案需要使用Android 11及更高版本的构建工具和设备支持。