新建项目

通过android studio来新建一个只有一个activity的项目,不要选择使用androidx,不要选择kotlin,为了是更简单地去体验整个编译apk的过程。

删除无用文件

删除无用文件后,目录如下
和gradle相关的都删除,因为我们自己去做gradle做的事情。
由于项目默认使用的库导致需要多次去链接的关系,所以我把主题文件(theme.xml)删除,并且布局使用了FrameLayout不使用约束布局,因为高版本的as会自动帮你用约束布局。

image.png

资源编译

使用aapt2工具进行资源编译,进入项目的src目录
因为要编译整个res资源文件目录,所以将所有资源最后打包成为一个 .zip文件

  1. $ANDROID_HOME/build-tools/29.0.3/aapt2 compile --dir main/res -o build/resources.zip

最后如果你对resource.zip解压后可以查看到,所有资源都被编译成了 .flat文件
image.png

资源链接

link 语法如下

  1. aapt2 link path-to-input-files [options] -o
  2. outputdirectory/outputfilename.apk --manifest AndroidManifest.xml

在链接阶段,AAPT2 会合并在编译阶段生成的所有中间文件(.flat 文件),并将它们打包成 ZIP 包(最终 APK 的原型,由于不包括 DEX 文件且未签名,所以无法正常安装)。

下面是link命令,进入项目的src目录

  1. $ANDROID_HOME/build-tools/29.0.3/aapt2 link build/resources.zip -I $ANDROID_HOME/platforms/android-30/android.jar --manifest main/AndroidManifest.xml -o build/out.apk

参数说明:

  • I :提供平台的 android.jar 或其他 APK(如 framework-res.apk)的路径,这在构建功能时可能很有用。如果您要在资源文件中使用带有 android 命名空间(例如 android:id)的属性,则必须使用此标记。
  • —manifest:指定AndroidManifest文件,manifest文件中包含了packagename和application id
  • -o:指定了输出目录和输出apk文件

得到一个apk,out.apk,如果你这时候解压该apk,可以看到是一个纯资源的apk。
image.png

编译java源文件

由于是android项目,并且引用到了R文件,因此需要先生成R文件,我们直接把R文件生成在原java文件所在的位置,进入到src目录

  1. $ANDROID_HOME/build-tools/29.0.3/aapt package -f -m -J main/java -M main/AndroidManifest.xml -S main/res -I $ANDROID_HOME/platforms/android-30/android.jar

-f 强制覆盖现有文件
-M 指定的完整路径AndroidManifest.xml文件包含在zip中
-S 在其中查找资源的目录。将扫描多个目录,找到的第一个匹配项(从左到右)将优先。
-I 将现有包添加到基本包含集
-J 指定R.java资源常量定义的输出位置

进入java文件目录,编译MainActivty以及R文件

  1. javac -encoding utf-8 -target 1.8 MainActivity.java R.java -bootclasspath $ANDROID_HOME/platforms/android-30/android.jar

image.png

class转dex

进入项目的src目录

  1. $ANDROID_HOME/build-tools/29.0.3/d8 main/java/net/mikaelzero/gradledemo/*.class --classpath $ANDROID_HOME/platforms/android-30/android.jar --output /build

得到一个classes.dex
image.png

整合

现在build中已经有out.apk ,也就是纯资源的apk以及classes.dex文件,通过如下命令

  1. zip -ur out.apk classes.dex

通过解压可以发现dex文件以及整合到了apk中,其实就是把out.apk解压后,把dex放入再压缩。
image.png

签名

我是通过AS创建了一个jks,放到build目录中

  1. $ANDROID_HOME/build-tools/29.0.3/apksigner sign --ks build/gradle-key_store.jks /build/out.apk

签名后得到一个完整的APK,通过adb install 安装后,截图如下

image.png

aar

下载的一个recyclerview的aar解压后如下:
image.png

AAR 文件的文件扩展名为 .aar,Maven 工件类型应该也是 aar此文件本身是一个 zip 文件。唯一的必需条目是 /AndroidManifest.xml
此外,AAR 文件可能包含以下一个或多个可选条目:

  • /classes.jar
  • /res/
  • /R.txt
  • /public.txt
  • /assets/
  • /libs/name.jar
  • /jni/abi_name/name.so(其中 abi_name 是 Android 支持的 ABI 之一)
  • /proguard.txt
  • /lint.jar
  • /api.jar
  • /prefab/(用于导出原生库

    aar是如何被使用的

一种本地使用

  1. repositories {
  2. flatDir {
  3. dirs 'libs'
  4. }
  5. }
  6. dependencies {
  7. compile(name:'AAR-name', ext:'aar')
  8. }

一种远程使用

dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
}
  1. 远程依赖,gradle会下载对应的pom文件,根据pom文件配置来下载aar文件
  2. 通过transformer对aar转换为一个classes.jar,转换后结果会缓存,一般路径是 ~/.gradle/caches/transforms-2 或者 ~/.gradle/caches/transforms-1
  3. 通过ConfigurationContainer来获取转换后的产物

尝试在自己做的 APK 里面,用上一个 AAR

生成aar

通过android studio新建了一个module,然后获取到aar文件,放入到项目的build目录中,进入build目录
image.png

编译aar的资源文件

$ANDROID_HOME/build-tools/29.0.3/aapt2 compile --zip mylibrary-debug.aar -o resources_module.zip

—zip参数后会遍历aar内部所有文件,识别其中的资源文件进行编译

接着编译主项目的资源

$ANDROID_HOME/build-tools/29.0.3/aapt2 compile --dir main/res -o build/resources.zip

得到两个zip文件,如下

image.png

链接

由于存在多个AndroidManifest.xml文件,所以第一步先对AndroidManifest.xml做一个合并操作。
合并清单文件没有对应的工具,所以需要手动进行了合并
image.png

然后再进行链接,进入src目录

$ANDROID_HOME/build-tools/29.0.3/aapt2 link build/resources.zip build/resources_module.zip  -I $ANDROID_HOME/platforms/android-30/android.jar -o build/out_merge.apk --extra-packages net.mikaelzero.mylibrary --manifest main/AndroidManifest.xml -v --java build/

命令注释:—extra-packages package_name 生成相同的 R.java 文件,但软件包名称不同。为了就是给aar重新生成R文件,因为aar是不带R文件的。
—java directory 指定要在其中生成 R.java 的目录。这里要同时进行生成不能单独生成,否则会发生ID冲突,生成后手动复制到对应的java目录中。

为什么不带R文件,因为R文件中的ID是唯一的,在引用大量的aar情况下可能发生冲突,因此**把 AAR 在合并进 apk 的过程中,对所有的资源 ID 进行重生成,使得这个 R 在这个 app 内全局唯一。

在自己项目中也可以发现,有非常多的R文件
image.png

把编译期生成的两个资源文件合成out_merge.apk,这个时候如果解压该app,可以发现资源合并在了一起

image.png

编译源码

源码需要做一下修改,
image.png
主要是增加一个跳转,跳转的Activity来自aar,所以在编译的时候,需要去链接aar中的jar包

javac -encoding utf-8  -target 1.8 main/java/net/mikaelzero/gradledemo/*.java build/mylibrary/src/main/java/net/mikaelzero/mylibrary/*.java -bootclasspath  $ANDROID_HOME/platforms/android-30/android.jar;build/classes.jar

class转dex

$ANDROID_HOME/build-tools/29.0.3/d8 main/java/net/mikaelzero/gradledemo/*.class build/mylibrary/src/main/java/net/mikaelzero/mylibrary/*.class --classpath $ANDROID_HOME/platforms/android-30/android.jar --output build

那么现在的build目录下就会有一个classes.dex文件,内容如下

image.png

整合

进入build目录

zip -ur out_merge.apk classes.dex

签名

$ANDROID_HOME/build-tools/29.0.3/apksigner sign --ks gradle-key_store.jks out_merge.apk

通过adb命令安装后,可以发现跳转到了TestActivity
image.png