type
status
date
slug
summary
tags
category
icon
password
本文通过手动编译 apk 的形式,带你了解 Android apk 的生成流程。
Android Apk 编译打包流程
Android 项目从编译到打包流程如下(Google 官网已经找不到,取而代之是一张简化后的,但我还是更喜欢这张)
简要描述此流程使用的一些编译工具:
- aapt:
aapt(Android Asset Packaging Tool)
工具会打包应用中的资源文件,如AndroidManifest.xml、layout
布局中的xml
等,并将 xml 文件编译为二进制形式,当然 assets 文件夹中的文件不会被编译,图片及 raw 文件夹中的资源也会保持原来的形态,(需要注意的是 raw 文件夹中的资源也会生成资源 id。aapt 编译完成之后会生成R.java
文件)。
- aidl:AIDL 工具会将所有的 aidl 接口转化为 java 接口。
- Java Compiler(Java编译器):当 AAPT 与 AIDL 工具将需要处理的数据处理好后,Java 编译器会将所有的java代码,包括R.java与 aidl 文件编译成 .class 文件。
- dex:
dex
工具会将上述产生的 .class 文件及第三库及其他 .class 文件编译成 .dex 文件(dex文件是Dalvik虚拟机可以执行的格式),dex文件最终会被打包进APK文件。
- apkbuilder:
apkbuilder
工具会将编译过的资源及未编译过的资源(如图片等)以及 .dex 文件打包成APK文件。
- Jarsingner:生成 APK 文件后,需要对其签名才可安装到设备,平时测试时会使用 debug keystore,当正式发布应用时必须使用 release 版的 keystore 对应用进行签名。Jarsigner工具会根据相应的keystore生成相应的签名APK文件。
- zipalign(release mode):
zipalign
工具,它能够对打包的应用程序进行优化。在你的应用程序上运行zipalign
,使得在运行时 Android 与应用程序间的交互更加有效率。
手动编译打包流程示例
本示例所使用电脑环境
- 准备一个 Android 项目,此项目只使用 Android-29 平台库,不做过多的依赖,文件结构如下
- 创建 build 文件夹,后面作为输出文件夹,使用 aapt2 编译工具,将 res 目录中的资源文件编译成一个名为 res.zip 的压缩包。
aapt2 compile -o build/res.zip --dir res
命令解析
aapt2
: 这是 Android Asset Packaging Tool 2 (aapt2) 的命令行工具,用于处理 Android 应用程序资源。
compile
: 这是 aapt2 命令的子命令,指示 aapt2 编译资源文件。
-o build/res.zip
: 这个参数指定编译后的资源文件输出的位置和文件名。在这里,资源文件将被编译成一个名为res.zip
的压缩包,并存储在build
目录下。
-dir res
: 这个参数指定要编译的资源文件所在的目录。在这里,资源文件位于res
目录下,aapt2 将编译这个目录中的资源文件。
- 对资源进行链接
aapt2 link build/res.zip -I $ANDROID_HOME/platforms/android-29/android.jar --java build --manifest AndroidManifest.xml -o build/app-debug.apk
命令解析
aapt2 link
: 使用 aapt2 工具进行链接操作。
build/res.zip
: 要链接的资源文件(通常是资源文件的压缩包)。
I $ANDROID_HOME/platforms/android-29/android.jar
: 指定 Android 平台的 android.jar 文件,用于包含 Android 框架的类和资源。
-java build
: 生成 R.java 文件到指定的目录 build 中,这个文件包含了资源 ID 的映射。
-manifest AndroidManifest.xml
: 指定 AndroidManifest.xml 文件,这是 Android 应用程序的清单文件。
o build/app-debug.apk
: 指定输出的 APK 文件路径和名称。
- 编译 .java 文件(把 R.java 文件迁移到 MainActivity.java 所在目录,请正确指定的类路径和源代码文件路径是正确的,以确保编译过程顺利进行)
javac -d build -cp $ANDROID_HOME/platforms/android-29/android.jar com/example/compile/old/*.java
命令解析
javac
: Java 编译器命令。
d build
: 指定编译后的 .class 文件输出目录为 build 目录。
cp $ANDROID_HOME/platforms/android-29/android.jar
: 指定编译时的类路径,这里是指定了 Android 平台的 android.jar 文件,以便编译器能够找到 Android 平台的类和接口。
com/example/compile/old/*.java
: 要编译的 Java 源代码文件,这里指定了一个包路径下的所有 Java 文件进行编译。
编译后目录结构如下
- 生成 Dex 文件
d8 --output build/ --lib $ANDROID_HOME/platforms/android-29/android.jar build/com/example/compile/old/*.class 命令解析
d8
: 这是一个命令行工具,用于将 Java 字节码文件转换为 Dex 格式,以便在 Android 设备上运行。
-output build/
: 这个选项指定了输出目录为build/
,即将转换后的 Dex 文件输出到该目录。
-lib $ANDROID_HOME/platforms/android-29/android.jar
: 这个选项指定了 Android 平台库的路径,其中$ANDROID_HOME
是 Android SDK 的根目录,android-29
是 Android API 版本,android.jar
是 Android 平台库文件。
build/com/example/compile/old/*.class
: 这是要转换的 Java 字节码文件的路径,通配符.class
表示选择该目录下所有的.class
文件。
编译后目录结构如下
- 将 dex 文件放入 apk 文件中
zip -j build/app-debug.apk build/classes.dex
参数解析
zip
: 这是用于创建和修改zip文件的命令。
j
: 这个选项表示在压缩文件时不包含目录路径,只压缩文件本身。
build/app-debug.apk
: 这是指定要创建的zip文件的路径和名称。在这里,将创建一个名为app-debug.apk
的zip文件,并存储在build
目录下。
build/classes.dex
: 这是指定要添加到zip文件中的文件路径和名称。在这里,classes.dex
文件将被添加到app-debug.apk
中。
- 签名,使用 debug 签名 密码 “android”
apksigner sign -ks ~/.android/debug.keystore build/app-debug.apk
参数解析
apksigner
: 这是用于对 APK 进行签名的工具。
sign
: 这是 apksigner 的子命令,指示对 APK 文件进行签名操作。
ks ~/.android/debug.keystore
: 这个参数指定了用于签名 APK 的密钥库文件的路径。在这里,~/.android/debug.keystore
是密钥库文件的路径。
build/app-debug.apk
: 这是指定要签名的 APK 文件的路径和名称。在这里,app-debug.apk
将被签名。
- 将最终 .apk 文件安装到模拟器或真机
通过这个示例可以看出,即使在小型项目中,编译和打包 Android 应用程序也需要耗费相当的精力。而在大型项目中,涉及数百甚至数千个资源文件、Java/Kotlin 文件,以及各种测试、Lint 检测、编译(apt、asm 等工具又会干预编译)、链接和优化等流程。此外,还要考虑到模块化、复杂的依赖关系等因素,手动编译这样的项目几乎是不可能的任务,并且手动编译容易出错、效率低下。
因此,构建工具如 Gradle 应运而生。Gradle 等构建工具能够自动化和简化整个构建流程,从而减轻开发人员的负担,并确保构建过程的可靠性和一致性。
简洁优雅如 Gradle,也不要高兴的太早,掉入 Gradle 的坑里又是另外一个故事啦。