徒手构建 APK
本文我们将从零开始,不依赖任何的ide、ant、gradle等编译工具,仅通过 Android SDK 里面提供的 build 工具,一步一步的构建一个最基本,但完整的 apk。
1、基础介绍
Android项目的构建实际上就是将我们工程中各种杂七杂八的文件合成一个apk 后缀的文件的过程。这个apk文件实质其实是一个压缩的 zip包(我们可以对其重命名后缀解压),这个压缩包内包括了源码打包出来的dex文件、一个编译成了二进制的AndroidManifest.xml文件、和一个包括了所有资源的二进制资源文件、未编译的资源文件、so 文件等,然后在运行前再对这个压缩包进行签名操作即可。具体流程如下图:
你可以在这里https://git.coding.net/saymagic/FairProject.git clone 基础代码和资源,其结构如下
- AndroidManifest 文件
- java 目录包含项目的源代码
- res 包含项目的所有资源
2、 项目构建
- 后续所有命令所在的根目录就是项目的根目录:
- 最好已将 aapt、adb、dx 等命令放置到 PATH中(如果没有,后面请使用全路径进行引用)。
2.1 生成资源索引文件 R.java
构建一个 APK 的第一步是生成 Android 中的 R 文件,这个文件是对所有资源建立索引,R 文件可以通过 aapt 命令来生成。如,我们对 res 下的所有资源建立 索引文件R,并输出到 out 目录:
1. mkdir out
2. aapt package -f -M ./AndroidManifest.xml -I "$SDK_HOME/platforms/android-26/android.jar" -S ./res/ -J out/ -m
使用的参数:
-f 如果编译出来的文件已经存在,进行强制覆盖。
-M AndroidManifest.xml的路径
-I 某个版本平台的android.jar的路径
-S res文件夹路径
-J 指定生成的R.java的输出目录
-m 使生成的包的目录放在-J参数指定的目录。
-A assert文件夹的路径
-
其中
$SDK_HOME
表示 Android SDK 所在的目录(通常就是我们在gradle 工程中local.properties文件中sdk.dir 的值)。 -
android-26
需要换成你所使用的版本。
执行成功后,out 目录下就会生成R.java 文件:
2.2 编译 Java 文件
接下来我们需要将我们的源代码和上一步生成的 R.java 文件通过 javac 命令编译成 class 文件
1. mkdir build
2. javac -bootclasspath "$SDK_HOME/platforms/android-26/android.jar" -d ./build/ ./java/tech/saymagic/fairproject/*.java ./out/tech/saymagic/fairproject/*.java
javac 命令所使用的参数说明:
-bootclasspath <路径> 覆盖引导类文件的位置
-d <目录> 指定放置生成的类文件的位置
执行成功后,build 目录下就会生成所有的class文件:
2.3 生成 dx
经过上面两个步骤,我们已经成功的编译出了所需的 class 文件。但 Android 系统的虚拟机认识的并不是 class 文件,而是通过 class 进一步编译出的 dex 文件,将 class 转换为 dex 文件需要 dx 命令来帮忙
dx --dex --output=./build/classes.dex ./build
执行成功后,在 build 文件夹中就会多出一个名为 classes.dex 的文件,这个文件就是我们需要的 dex 文件:
2.4 编译资源
经过了上面的三个步骤,我们成功的解决了代码的部分,接下来处理资源。 首先,Android 中的资源并非按照我们刚刚的格式完整的放置在 apk 文件中的,而是需要将所有的资源打包成一个二进制文件,这样做是为了节省大小。这个步骤依旧使用我们上文提到的 aapt 工具:
aapt package -f -M ./AndroidManifest.xml -I "$SDK_HOME/platforms/android-26/android.jar" -S ./res/ -F ./build/resources.ap_
经过上面的命令,我们就将所有的资源文件打包成为一个二进制文件resources.ap_:
2.5 组装 dex 文件与资源文件
这一步骤由 apkbuilder 来完成,apkbuilder的源码被打进了 sdklib 包中,我们可以通过直接调用 jar 包的方式来启用:
java -classpath "$SDK_HOME/tools/lib/sdklib-26.0.0-dev.jar" com.android.sdklib.build.ApkBuilderMain ./build/fair.apk -v -u -z ./build/resources.ap_ -f ./build/classes.dex
- 其中,
sdklib-26.0.0-dev.jar
文件需要按照实际情况来修改
成功之后,我们就可以在 build 文件夹中看到生成的fair.apk文件了
2.6 生成 debug 签名
上一步生成的 apk 文件并不能被直接安装在手机上,原因是这个 apk 还没有被签名。 我们可以使用 Android 提供给我们的 debug 证书来来对这个 apk 进行签名。这个 debug 证书是存放在用户家目录的.android 文件夹中:
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android ./build/fair.apk androiddebugkey
这样,我们的 apk就完成了签名。
3、安装
经过上面的六个步骤,我们完成了一次最基本的 apk 的构建。整个 apk 的大小不到100k,我们可以通过adb install -r ./build/fair.apk
来将应用安装到手机上,我们见到了熟悉的 hello world:
4、总结
我们从无到有的构建了一个可以运行的 apk,总的来看其过程就是将所有 java 文件打包成 dex,将资源文件打包为一个文件,最终将其合成一个文件。当然,本文当中省略了很多的打包分支,如包含 so 的情况,包含第三方 jar 包、第三方资源的情况。如果要实现这么细粒度的控制,最好就需要通过比较成熟的工具来进行了,如早期的 ant 到现在的 gradle。它们都能很好胜任刚刚提到的情况。本文就到这里,后面一篇文章我们将分析 apk 是如何被安装在手机上的。
on