Understanding Dependency Management in Android

Harsh Maheshwari
2 min readMay 24, 2024

--

Random Rhino's that I saw recently

Setting the Context

Working with a multi-module architecture in an Android app can be complex. Recently, I encountered an issue that perfectly illustrates the challenges of dependency management. Here’s how I resolved it using Dependency Guard from Dropbox.

The Scenario

Our app consists of multiple modules, each hosted in our cloud and available for consumption. One day, I made changes to a particular module and expected those changes to reflect in our main app and other modules consuming it. However, the updates weren’t visible.

The Problem

Initially, I thought dependency resolution would automatically select the latest version of the module I had updated. However, things didn’t go as planned:

  1. Initial Assumption: The latest version of the updated module would be used automatically.
  2. Reality: The updated module was consumed by another intermediary module, which in turn was consumed by the main app.
  3. Issue: The intermediary module wasn’t using the latest version of the updated module, causing the changes to be missed.

Here’s a simplified illustration of the dependency structure:

Main App
└── Module A
└── Module B (updated)

Despite updating Module B, Module A was still referencing an older version, causing the main app to miss the updates.

The Solution

To diagnose and resolve the issue, I turned to Dependency Guard, a library from Dropbox that helps visualize and manage dependencies in your project.

Steps to Resolution:

  1. Integrate Dependency Guard: Add Dependency Guard to your project’s build script.
// sample/app/build.gradle.kts
plugins {
id("com.dropbox.dependency-guard") version "0.5.0"
}

2. Apply the Plugin: Apply the plugin in your app’s build script.

// sample/app/build.gradle.kts
dependencyGuard {
// All dependencies included in Production Release APK
configuration("releaseRuntimeClasspath")

3. Generate Dependency Tree: Run the dependency guard task to generate the dependency tree.

./gradlew dependencyGuard

4. Analyse the Output: Review the generated dependency tree to identify which versions are being used.

With this visualisation, it became evident that Module A was still using an older version of Module B. The dependency tree looked something like this:

Main App
├── Module A:1.0.0
│ └── Module B:1.0.0 (expected 1.1.0)
└── Module B:1.1.0

Resolve the Issue:

  1. Update Dependencies: Ensure all modules are using the latest versions.
// build.gradle (Module A)
dependencies {
implementation "com.example:module-b:1.1.0"
}

2. Implement Module B Directly in the Main Module: This ensures that dependency resolution will select the latest version.

// build.gradle (Main App)
dependencies {
implementation "com.example:module-b:1.1.0"
}

Conclusion

By leveraging Dependency Guard, I was able to pinpoint and resolve the dependency issue efficiently. This tool is especially useful in complex, multi-module projects, ensuring that all modules are in sync and using the correct versions of dependencies.

For more information and detailed configuration options, you can refer to the Dependency Guard GitHub repository.

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Responses (1)

Write a response