文章还在写,更新中。。。
1 概述
看完本文,你将收获:
- 区分
AndroidComponentsExtension中onVariants和AppExtension中applicationVariants.forEach的Variant,知道哪个方法适用于什么场景。 - 对
MergeNativeLibsTask的源码了解个大概。 - 能够打印项目里所有的 so 信息及其依赖信息。
2 最简单方案:通过 MergeNativeLibsTask 获取 so 信息
MergeNativeLibsTask 是一个 Gradle 任务,它用于合并 Android 应用中的本地库文件。MergeNativeLibsTask 的作用是将所有的本地库文件复制到一个统一的目录下,以便打包到 APK 或 AAB 文件中。这个任务是由 Android Gradle 插件自动创建和配置的,我们可以在这个任务开始前去获取 so 信息。可以直接通过任务类型去获取到 MergeNativeLibsTask:
afterEvaluate {
tasks.withType(MergeNativeLibsTask::class.java) {
this.doFirst {
projectNativeLibs.asFileTree.forEach {
println("projectNativeLibs, ${it.path}")
}
subProjectNativeLibs.asFileTree.forEach {
println("subProjectNativeLibs, ${it.path}")
}
externalLibNativeLibs.asFileTree.forEach {
println("externalLibNativeLibs, ${it.path}")
}
if (profilerNativeLibs.isPresent) {
profilerNativeLibs.asFileTree.forEach {
println("profilerNativeLibs, ${it.path}")
}
}
}
}
}
输出如下:
projectNativeLibs, D:\StudioProjects\xxx\app\build\intermediates\merged_jni_libs\basicDebug\out\x86\libucrop.so
...
subProjectNativeLibs, D:\StudioProjects\xxx\xxx\traceroute\build.transforms\db7deceeac3bc2a2f08352329ee919c1\transformed\jetified-traceroute-release\jni\x86\libtraceroute.so
...
externalLibNativeLibs, E:\gradle\caches\transforms-3\e244ec361d4eabe03f0a45d27fd3f4c7\transformed\jetified-sinaweibo-core-12.5.0\jni\arm64-v8a\libweibosdkcore.so
...
当然也可以用任务名去获取。需要注意的是,gradle 构建过程是有构建变体(Variant)的,这个变体是由 buildType 和 flavor 组成的,可以用迪卡尔积去算出所有的组合变体,如下:
fun cartesianProductString(array1: Array<String>, vararg arrays: Array<String>): List<String> {
return arrays.fold(array1.toList()) { acc, array ->
acc.flatMap { list ->
array.map { element -> list + element }
}
}
}
afterEvaluate {
val flavors = arrayOf("flavor1", "flavor2")
val buildTypes = arrayOf("Debug", "Release")
cartesianProductString(flavors, buildTypes).forEach {
tasks.findByName("merge${it}NativeLibs")?.run {
}
}
}
至于为什么是 merge${it}NativeLibs,变体为什么在中间,看下面的源码就懂了,Android 构建体系中很多任务都是这样的。
override val name: String
get() = computeTaskName("merge", "NativeLibs")
/**
* 下面方法中的 name 就是变体名
*/
override fun computeTaskName(prefix: String, suffix: String): String =
prefix.appendCapitalized(name, suffix)override val name: String
get() = computeTaskName("merge", "NativeLibs")
3 在插件里打印 So 信息
基本思路就是获取到所有的跟 jni 有关的构建中间产物(artifact),然后打印 artifact 内的 so 文件相关信息。artifact 的获取有几种方式,可以通过 org.gradle.api.artifacts.Configuration,也可以通过 Variant,下面的代码演示了两种方式。
project.afterEvaluate {
val android = project.extensions.getByType(AppExtension::class.java)
android.applicationVariants.forEach { variant ->
// 方式一
val variantName = variant.name
val configuration = project.configurations.getByName("${variantName}RuntimeClasspath")
val artifacts = configuration.incoming.artifactView {
attributes {
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, AndroidArtifacts.ArtifactType.JNI.name)
}
}.artifacts.artifacts
// 方式二
val variantData = (variant as com.android.build.gradle.internal.api.ApplicationVariantImpl).variantData
val artifacts = variantData.variantDependencies.getArtifactCollection(
AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH,
AndroidArtifacts.ArtifactScope.ALL,
AndroidArtifacts.ArtifactType.JNI
).artifacts
}
}
这里能拿到所有的编译中间 jni 目录,到这一步基本可以“为所欲为”了,可以打印 so 所在的 aar 或者子工程信息,也可以将信息输出到单独的文件中,甚至复制 so 到别的文件然后删除当前目录的 so 做个动态下发,稳定起见要做删除操作的话最好设置下放在 MergeNativeLibsTask 之前。
但是注意这两种方式获取到的 so 都不包含 app project 下的,只有子 project 和第三方库的。在解决这个问题之前,我们先把 so 的信息打印下吧:
artifacts.forEach artifact@{ artifactResult ->
val soFiles = artifactResult.file.walkTopDown()
.filter { it.name.endsWith(".so") }
.toMutableList()
.takeIf { it.isNotEmpty() } ?: return@artifact
println("artifact name: ${artifactResult.id.componentIdentifier.displayName}")
val artifactPath = artifactResult.file.absolutePath
val artifactPathLength = artifactPath.length
println("jni path: $artifactPath")
soFiles.forEach {
println("\t\t${it.absolutePath.substring(artifactPathLength)}")
}
}
输出如下:
artifact name: com.tencent.bugly:nativecrashreport:3.9.2
jni path: E:\gradle\caches\transforms-3\f3687876b97dd3bdd6fc701685d0e47b\transformed\jetified-nativecrashreport-3.9.2\jni
\arm64-v8a\libBugly.so
...