相信在日常开发中你已经发现,当我们添加某个库的依赖时,它会帮助我们同步它所依赖的库,比如我们常用的网络请求库 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 库来源于哪个依赖,结果可能会输出多次。

查询到的依赖也许并不是你自己添加的,这时候只需再使用上一节提到的命令打印依赖树,就可以追踪到根依赖了。