相信在日常开发中你已经发现,当我们添加某个库的依赖时,它会帮助我们同步它所依赖的库,比如我们常用的网络请求库 OkHttp 就依赖了 Okio,但我们依赖 OkHttp 时并不需要把 Okio 的依赖也添加进去,这是由 POM 声明的。
这种方案能够帮助我们屏蔽掉一些多余的信息,降低上手门槛,但有时候却不利于追踪。
追踪 AAR / JAR 依赖
好在 Android 官方已经帮我们准备好一个 Gradle 任务用于分析项目中的依赖关系,我们只需要一行命令就可以查询。
➜ ./gradlew app:dependencies
控制台中会输出整个项目的依赖树:
+--- androidx.appcompat:appcompat:1.7.1
| +--- androidx.activity:activity:1.8.0 -> 1.10.1
| | +--- androidx.annotation:annotation:1.8.1
| | | \--- androidx.annotation:annotation-jvm:1.8.1
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 1.8.22
| | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22
| | | \--- org.jetbrains:annotations:13.0 -> 23.0.0
| | +--- androidx.core:core-ktx:1.13.0
| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | +--- androidx.core:core:1.13.0
| | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*)
| | | | +--- androidx.annotation:annotation-experimental:1.4.0
| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 1.8.22 (*)
| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2
| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | | +--- androidx.arch.core:core-common:2.2.0
| | | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2
| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.7.3
| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3
| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3
| | | | | | | | +--- org.jetbrains:annotations:23.0.0
| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3
| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 (c)
| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3 (c)
| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 (c)
| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.20 -> 1.8.22
| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20 -> 1.8.22
| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (*)
| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22
| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (*)
| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3 (*)
| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20 -> 1.8.22 (*)
| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (c)
| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 (c)
| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (c)
| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 (c)
| | | | | | \--- androidx.lifecycle:lifecycle-livedata:2.6.2 (c)
| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (c)
| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (c)
| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (c)
| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 (c)
| | | | | \--- androidx.lifecycle:lifecycle-livedata:2.6.2 (c)
| | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1
| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | | \--- androidx.collection:collection:1.0.0 -> 1.1.0
| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (*)
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (*)
| | +--- androidx.core:core-viewtree:1.0.0
| | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 1.8.22 (*)
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (c)
| | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.6.2 (*)
| | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.6.2 (*)
| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.6.2
| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 (c)
| | | \--- androidx.lifecycle:lifecycle-livedata:2.6.2 (c)
| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.6.2
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.0 (*)
| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2
| | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (*)
| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 (c)
| | | | \--- androidx.lifecycle:lifecycle-livedata:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (*)
| | | +--- androidx.savedstate:savedstate:1.2.1
| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.7.3 (*)
| | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 (c)
| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (c)
| | | \--- androidx.lifecycle:lifecycle-livedata:2.6.2 (c)
| | +--- androidx.savedstate:savedstate:1.2.1 (*)
| | +--- org.jetbrains.kotlin:kotlin-stdlib -> 1.8.22 (*)
| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 (c)
| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*)
| +--- androidx.appcompat:appcompat-resources:1.7.1
| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*)
| | +--- androidx.core:core:1.6.0 -> 1.13.0 (*)
| | +--- androidx.vectordrawable:vectordrawable:1.1.0
| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | +--- androidx.core:core:1.1.0 -> 1.13.0 (*)
| | | \--- androidx.collection:collection:1.1.0 (*)
| | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0
| | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*)
| | | +--- androidx.interpolator:interpolator:1.0.0
| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | | \--- androidx.collection:collection:1.1.0 (*)
| | \--- androidx.appcompat:appcompat:1.7.1 (c)
| +--- androidx.core:core:1.13.0 (*)
| +--- androidx.cursoradapter:cursoradapter:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| +--- androidx.drawerlayout:drawerlayout:1.0.0 -> 1.1.1
| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | +--- androidx.core:core:1.2.0 -> 1.13.0 (*)
| | \--- androidx.customview:customview:1.1.0
| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | \--- androidx.core:core:1.3.0 -> 1.13.0 (*)
| +--- androidx.fragment:fragment:1.5.4
| | +--- androidx.activity:activity:1.5.1 -> 1.10.1 (*)
| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | +--- androidx.annotation:annotation-experimental:1.0.0 -> 1.4.0 (*)
| | +--- androidx.collection:collection:1.1.0 (*)
| | +--- androidx.core:core-ktx:1.2.0 -> 1.13.0 (*)
| | +--- androidx.lifecycle:lifecycle-livedata-core:2.5.1 -> 2.6.2 (*)
| | +--- androidx.lifecycle:lifecycle-viewmodel:2.5.1 -> 2.6.2 (*)
| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1 -> 2.6.2 (*)
| | +--- androidx.loader:loader:1.0.0
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | | +--- androidx.core:core:1.0.0 -> 1.13.0 (*)
| | | +--- androidx.lifecycle:lifecycle-livedata:2.0.0 -> 2.6.2
| | | | +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0
| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | | | | \--- androidx.arch.core:core-common:2.2.0 (*)
| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (*)
| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 1.8.22 (*)
| | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 (c)
| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.2 (c)
| | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 (c)
| | | \--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.6.2 (*)
| | +--- androidx.savedstate:savedstate:1.2.0 -> 1.2.1 (*)
| | +--- androidx.viewpager:viewpager:1.0.0
| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | | +--- androidx.core:core:1.0.0 -> 1.13.0 (*)
| | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*)
| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 1.8.22 (*)
| +--- androidx.savedstate:savedstate:1.2.1 (*)
| \--- androidx.appcompat:appcompat-resources:1.7.1 (c)
+--- com.google.android.material:material:1.12.0
| +--- androidx.activity:activity:1.8.0 -> 1.10.1 (*)
| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*)
| +--- androidx.appcompat:appcompat:1.6.1 -> 1.7.1 (*)
| +--- androidx.cardview:cardview:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| +--- androidx.coordinatorlayout:coordinatorlayout:1.1.0
| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | +--- androidx.core:core:1.1.0 -> 1.13.0 (*)
| | +--- androidx.customview:customview:1.0.0 -> 1.1.0 (*)
| | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
| +--- androidx.constraintlayout:constraintlayout:2.0.1 -> 2.2.1
| +--- androidx.core:core:1.6.0 -> 1.13.0 (*)
| +--- androidx.drawerlayout:drawerlayout:1.1.1 (*)
| +--- androidx.dynamicanimation:dynamicanimation:1.0.0
| | +--- androidx.core:core:1.0.0 -> 1.13.0 (*)
| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
| | \--- androidx.legacy:legacy-support-core-utils:1.0.0
| | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | +--- androidx.core:core:1.0.0 -> 1.13.0 (*)
| | +--- androidx.documentfile:documentfile:1.0.0
| | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | +--- androidx.loader:loader:1.0.0 (*)
| | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
| | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| | \--- androidx.print:print:1.0.0
| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*)
| +--- androidx.annotation:annotation-experimental:1.0.0 -> 1.4.0 (*)
| +--- androidx.fragment:fragment:1.2.5 -> 1.5.4 (*)
| +--- androidx.lifecycle:lifecycle-runtime:2.0.0 -> 2.6.2 (*)
| +--- androidx.recyclerview:recyclerview:1.0.0 -> 1.1.0
| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| | +--- androidx.core:core:1.1.0 -> 1.13.0 (*)
| | +--- androidx.customview:customview:1.0.0 -> 1.1.0 (*)
| | \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
| +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1
| +--- androidx.transition:transition:1.5.0
| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*)
| | \--- androidx.core:core:1.13.0 (*)
| +--- androidx.vectordrawable:vectordrawable:1.1.0 (*)
| \--- androidx.viewpager2:viewpager2:1.0.0
| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*)
| +--- androidx.fragment:fragment:1.1.0 -> 1.5.4 (*)
| +--- androidx.recyclerview:recyclerview:1.1.0 (*)
| +--- androidx.core:core:1.1.0 -> 1.13.0 (*)
| \--- androidx.collection:collection:1.1.0 (*)
+--- androidx.activity:activity:1.10.1 (*)
+--- androidx.constraintlayout:constraintlayout:2.2.1
追踪 SO 依赖
在添加的 AAR 依赖中还可能存在 SO 库,这追踪起来就相对麻烦一些,相信近期适配 Android 16KB Page Size 的小伙伴可能深有体会。
我目前没找到官方有类似的任务供我们一键调用,所以写了个任务:
def variantName = "dokitDebug"
def soName = "librtmp-jni.so"
android.applicationVariants.all { variant ->
if (variant.name != variantName) return // 只处理你关心的变体
tasks.register("findSoOwner${variant.name.capitalize()}") {
group = "verification"
description = "查找 ${soName} 来自哪个 AAR"
def artifacts = variant.runtimeConfiguration.incoming.artifacts
doLast {
artifacts.artifacts.each { artifact ->
def file = artifact.file
if (file.name.endsWith(".aar")) {
new java.util.zip.ZipFile(file).withCloseable { zf ->
zf.entries().each { entry ->
if (entry.name.endsWith(soName)) {
println "Found ${soName} in ${artifact.id.componentIdentifier} (${file.name})"
}
}
}
}
}
}
}
}
将最开始的两个变量要修改为自己实际项目中的内容,比如我这里就在一个名为 dokitDebug
的变体下查询 librtmp-jni.so
这个 SO 的来源,只需在终端中执行命令:
➜ ./gradlew :app:findSoOwner
就可以得到以下输出:
> Task :app:findSoOwnerDokitDebug
Found librtmp-jni.so in io.antmedia:rtmp-client:3.2.0 (rtmp-client-3.2.0.aar)
Found librtmp-jni.so in io.antmedia:rtmp-client:3.2.0 (rtmp-client-3.2.0.aar)
Found librtmp-jni.so in io.antmedia:rtmp-client:3.2.0 (rtmp-client-3.2.0.aar)
Found librtmp-jni.so in io.antmedia:rtmp-client:3.2.0 (rtmp-client-3.2.0.aar)
我们可以在结果中看到查找的 SO 库来源于哪个依赖,结果可能会输出多次。
查询到的依赖也许并不是你自己添加的,这时候只需再使用上一节提到的命令打印依赖树,就可以追踪到根依赖了。