{
  "$type": "site.standard.document",
  "canonicalUrl": "https://segunfamisa.com/posts/analyze-gradle-dependencies",
  "description": "How to analyze your Gradle dependencies",
  "path": "/posts/analyze-gradle-dependencies",
  "publishedAt": "2024-03-14T19:00:00.000Z",
  "site": "at://did:plc:a5mekodp4afxadlpr4hp2wci/site.standard.publication/3mm2oa7vz5327",
  "tags": [
    "gradle",
    "tutorial",
    "tips"
  ],
  "textContent": "> _Featured in Android Weekly #614 and Kotlin Weekly #398_\n\nAs Android developers, now and then, we may have to investigate or analyze the Gradle dependencies we are using. Whether we are trying to find out which versions of libraries we are using, or we are trying to find out where one - perhaps unusual dependency is coming from, we may end up needing this knowledge.\n\nA short story. Recently, leak canary - which we use to detect memory leaks - was found to be deactivated in our project. Upon investigating, I found that it was deactivated because a test dependency was accidentally added to the classpath of our debug builds. So, I had to investigate to find out what test dependency is there, and how it got there.\n\nIn this post, I will share some tips that can help you analyze our Gradle dependencies and debug them too.\n\nAnalyzing the configurations\n\nFirst, to analyze the dependencies, one needs to know which kinds of dependencies one is looking for. We can do this by trying to understand _how_ exactly the dependencies are declared - and that determines how they end up in the classpath. In other words, we need to know the configurations.\n\nConfigurations are a way for you to tell Gradle how exactly to package these dependencies to achieve the final output. Some dependencies might be used only in compile time, while some are needed both in compile time and runtime. Some might even have special behaviors, or relations to plugins like kapt and ksp, or only available in certain source sets - like tests.\n\nAs described in Google's guide to declaring dependencies, some of the officially supported configurations include api, implementation, compileOnly, runtimeOnly among others.\n\nIn version 7.5 and above, Gradle provides a ResolvableConfigurationsTask task that reports all the configurations that can be resolved within your project. The task is run as indicated below.\n\napp here can be replaced with whichever Gradle module you are interested in seeing.\n\nThe report is printed to the command line, and as a result, I often like to pipe the output of the command to a file, so that I can open and search properly. You can do that by running ./gradlew :app:resolvableConfigurations > conf.txt.\n\nThe report prints all the configurations, including their names, attributes, and other configurations they extend. One of such configurations (debugCompileClasspath) is shown below:\n\nThe compile classpath is typically what you are interested in if you are trying to find out which dependencies are compiled with the app - so you can check the compile classpath for each of your build types and product flavor combinations.\n\nOkay. Now, we have identified the configuration which we want to investigate. Let's proceed to check which dependencies are available in that configuration.\n\nAnalyzing dependencies\n\nTo analyze the dependencies, there are two tasks we can use. The dependency and the dependencyInsights tasks.\n\nThe dependency task takes a parameter --configuration which tells Gradle which configuration's dependencies you are interested in. An example of the run is:\n\nThe command above prints out all the dependencies applied in the debugCompileClasspath configuration - i.e., all the dependencies that are packaged into the debug build. The output of the command looks something like this:\n\nOn the other hand, if we already know which dependency we are looking for, we can use the dependencyInsight task and specify the group:name or a part of the dependency name. For example, to find out information about the arrow-kt dependency above, we can run:\n\nConclusion\n\nThe approaches described above have proven to be immensely helpful in debugging and analyzing dependencies in my projects. I can determine which configurations exist in my project, and with that information, I can explore the dependencies in that configuration.\n\nWith these commands, I was able to pinpoint which dependency caused our leak canary to be deactivated and provided a fix.\n\nI imagine that there are additional use cases like investigating a transitive dependency, or in case of version conflicts, finding out how the conflict is resolved and which version supersedes the other, to mention a few.\n\nThank you for reading. I hope this was helpful or informative in some way.\n\nFor more reading about Gradle dependencies, you can have a look at the following resources:\n\n- https://developer.android.com/build/dependencies\n- https://docs.gradle.org/current/userguide/declaring_dependencies.html#sec:what-are-dependency-configurations\n- https://docs.gradle.org/current/userguide/viewing_debugging_dependencies.html",
  "title": "Analyzing your Gradle dependencies"
}