Android 自定义插件 获取构建apk时的依赖库信息

1,499 阅读2分钟

需求背景

现在的android app 稍微具有一定规模的 可能依赖的 aar就有几十个,甚至上百个。 这些aar 之间又有着 复杂的依赖关系,有时候我们想排查一些线上错误 就需要明确知道 那次构建出来的apk 使用的各个aar的版本号到底是什么? 这些aar 又依赖着哪些库?这些库的 版本号又是什么?

我们期望在apk构建完成的时候 在ci上也能输出一份文件,这份文件里面输出的就是各个依赖库的版本号,以及这些依赖库所依赖的库的版本号

插件实现难点

我们可以确定的是 要完成这个需求 至少应该有一个task, 这个task 要拿到 我们application的 所依赖的全部aar的版本号。以及 这些aar 本身的依赖库的版本号。 拿到以后 将这些信息 写入到一个文件中。

第一个问题就是 这个task 我们要安排在哪个位置执行? 我们过一边agp的编译流程以后发现, 将我们的这个task 放到 preBuild 这个task 之前执行是最何时的。

//正确的hook点就在这里 在这里将依赖信息 捕获 并输出
        val task = project.tasks.create("findDependenciesTask", FindDependenciesTask::class.java)
        project.tasks.findByName("preBuild")?.dependsOn(task)

第二个问题 也是最关键的 我们怎么拿到 这些 依赖库的信息

 project.configurations.forEach {
			//一般 情况下 我们只对release 的构建 执行 非release的 一般都是debug 我们debug场景下不用关注这个信息	
            if (it.name.toLowerCase() == "defaultreleaseruntimeclasspath") {
                
                it.incoming.resolutionResult.root.dependencies.forEach { it2 ->
                    //这里可以拿到所有的依赖库的信息 但是我们通常只关注我们自己的库,一些第三方库 我们都不关心
                    //所以 这里我们可以过滤一下 只处理 我们自己 包名下的库
                    if (it2.toString().startsWith("com.xiaomi.space")) {
                        
                        dependencyResultInfo += "$it2 \n"
                        //这里就是取依赖库自己所依赖的库的版本号 比如我们的app 是依赖的 a1 这个aar
                        //然后a1这个aar 自己依赖了 a2 a3 a4 等三个aar 那我们也要把a2 a3 a4 打出来
                        
                        if (it2 is ResolvedDependencyResult) {
                            //暂不考虑 递归的场景 只输出一层引用 不考虑 递归引用
                            //当然a2 a3 a4 也有自己的依赖库,但是这里我们为了简单 就不再打印第三层的依赖关系了
                            //各位有需要可以自己处理
                            it2.selected.dependencies.forEach { it3 ->
                                dependencyResultInfo += "-----------------$it3 \n"
                            }
                        }
                        dependencyResultInfo += "----------------------------------------- \n"
                    }
                }
            }

        }

拿到 上述信息以后 我们只要写入到一个文件就可以了。注意写入文件的位置 要和你ci上暴露出来的位置一致。否则 ci构建出来的产物是不会有你这个文件的噢

看看效果

com.xiaomi.space.feedback:xiaomispace_feedback:4.6.2.0-SNAPSHOT 
-----------------com.xiaomi.space.core:xiaomispace_core:4.6.2.0-SNAPSHOT -> com.xiaomi.space.core:xiaomispace_core:4.7.999.2 
----------------------------------------- 
com.xiaomi.space.ewarranty:xiaomispace_ewarranty:4.6.2.0-SNAPSHOT 
-----------------com.xiaomi.space.core:xiaomispace_core:4.6.2.0-SNAPSHOT -> com.xiaomi.space.core:xiaomispace_core:4.7.999.2 
----------------------------------------- 
com.xiaomi.space.weex:xiaomispace_weexcore:4.6.2.1-SNAPSHOT 
-----------------com.xiaomi.space.core:xiaomispace_core:4.6.2.0-SNAPSHOT -> com.xiaomi.space.core:xiaomispace_core:4.7.999.2 
-----------------com.alibaba:fastjson:1.2.58 
-----------------org.apache.weex:sdk_legacy:0.28.0 
-----------------com.android.support:support-v4:28.0.0 
----------------------------------------- 
com.xiaomi.space.hardwaredetect:xiaomispace_hardwaredetect:4.5.0.0-SNAPSHOT 
-----------------com.xiaomi.space.core:xiaomispace_core:4.5.0.0-SNAPSHOT -> com.xiaomi.space.core:xiaomispace_core:4.7.999.2