在最近的工作中,需要对开发的组件化SDK进行AAR打包,在这里记录一下。

组件化架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                   +--------------------+
| 壳App |
+----------^---------+
+----------------------------------------------------------+
| +--------------------+ |
| 需要打包的SDK | APP(UI相关) | |
| +------^------^------+ |
| | | |
| +--------------------------------------------------+ |
| | | | | |
| | +-----------------++ +---+-------------+ | |
| | | 业务A | | 业务B | | |
| | +-----------------+ +-----------------+ | |
| +----------------------^---------------------------+ |
| | |
| +--------------------------------------------------+ |
| | +--------------+ +-------------+ +-------------| |
| | | 基础库A | | 基础库B | | ... || |
| | +--------------+ +-------------+ +-------------| |
| +--------------------------------------------------| |
+----------------------------------------------------------+

目标

将APP、业务、基础库中自己的代码打包成一个.aar文件,用到的第三方依赖由配置文件提供给宿主App使用

思路

  1. 将业务和基础库中的jar包、aar使用maven依赖,使这些模块可以产出包含自己代码的jar包
  2. 将上述生成的jar包导入APP的lib依赖,切断APP和业务、基础库的gradle依赖关系
  3. 在APP中打包生成AAR

实施

各模块生成.jar文件

gradle编译完成后就会在每个模块的build目录下生成classes.jar文件,这里需要在编译后将jar包重命名并拷贝到app/dep_lib目录。
每个模块的build.gradle配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
android {
buildTypes {
release {
minifyEnabled false
}
}
}
task makeJar(type:Copy){
String filename = "xxx.jar"// 每个模块生成的jar包名字
from('build/intermediates/aar_main_jar/debug/')
into(rootDir.path + '/app/dep_lib')
rename('classes.jar', filename)
}
makeJar.dependsOn(build)

之后,执行./gradlew makeJar就会生成jar包,并复制到app/dep_lib目录中。

注意:各个模块的混淆需要关闭,统一配置在app中,最终由app混淆。

将各模块的jar包导入app的依赖中,切断module依赖

执行完上个步骤后,app目录下已有dep_lib目录,且包含各个模块的jar包。然后配置好混淆规则,切断module依赖,使用jar包依赖,执行./gradlew app:bundleReleaseAar,之后就可以在app/build/outputs/aar中看到aar产物。这个步骤很简单,但是每次打包都这么配置一次,太麻烦了!!!必须有更简单的办法。
所以app/build.gradle需要做判断,只在打包时使用dep_lib下的jar包依赖,正常开发过程中仍使用module依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dependencies {
...

if(project.hasProperties("buildAar")){
implementation fileTree(dir: 'dep_lib', includes: ['*.jar'])
// 这里需要复制各个模块的aar依赖,否则运行时会找不到类
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation ...
} else {
implementation project('baseA')
implementation project('businessA')
}

...
}

这里使用了编译参数buildAar,编译aar的命令就成了

1
./gradlew app:bundleReleaseAar -PbuildAar=true

开发过程中没有这个参数,所以扔使用module依赖。

一键脚本

1
2
3
4
5
6
7
8
9
./gradlew clean
rm -rf app/dep_lib
./gradlew makeJar
./gradlew app:bundleReleaseAar -PbuildAar=true

rm -rf SDK
mkdir SDK
cp app/build/outputs/aar/aar-release.aar SDK
cp app/build/outputs/mapping/release/mapping SDK

壳工程测试AAR

将生成的aar复制到壳工程中。
在壳工程中测试AAR,也需要分情况判断依赖。一般执行Android Studio运行测试,所以配置可以写进gradle配置里。
build.gradle

1
2
3
ext {
buildWithAar:true
}

shellapp/build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
dependencies {
// 壳工程原有依赖
...

if (!rootProject.ext.buildWithAar.toBoolean()){
implementation project(':app')
} else {
//使用继承AAR产物的方式
implementation fileTree(dir:"libs", include:['*.aar'])
// SDK用到的的第三方依赖
...
}
}

大功告成

缺陷

  1. 依赖配置复杂,每个业务模块、基础模块的依赖都需要在app/build.gradle里多配置一次

更好的方式?

maven?