Run ./gradlew :app:dependencies and read the release runtime classpath. Gradle prints the full tree, including transitive libraries. For one library, run dependencyInsight to see why that version was selected. Then save the output or an SBOM with each release so you can answer questions later.
The commands
Gradle's documentation gives these forms:
./gradlew :app:dependencies
./gradlew :app:dependencies --configuration releaseRuntimeClasspath
./gradlew :app:dependencyInsight --dependency commons-codec --configuration releaseRuntimeClasspath
Android projects have many configurations, one set per build variant. The release runtime classpath is the one closest to what ships. Debug and test configurations can contain extra libraries that never reach users, so reading all of them mixes noise into your list.
How to read the output
In Gradle's output, a (*) marks a repeated subtree, (c) marks a dependency constraint, and (n) marks a configuration that cannot be resolved. A library you never declared appears indented beneath one you did. That is a transitive dependency. It runs in your app exactly like the ones you chose.
Why this library, why this version
dependencyInsight has a Selection reasons section. Common reasons Gradle documents include:
- by conflict resolution, when several versions were requested and one won,
- by constraint,
- forced, from an enforced platform or resolution strategy,
- selected by rule.
If a vulnerable version shows up, this tells you whether to bump the direct dependency, add a constraint, or remove a rule that holds the old version in place.
Steps for a clean inventory
- Pick the release variant you actually ship.
- Run the dependencies task against its runtime classpath.
- Save the output next to the release tag.
- Run
dependencyInsighton anything flagged by your vulnerability matching. - Repeat for each module that is packaged into the app.
Tree text or SBOM
| Approach | Good for | Weak spot |
|---|---|---|
| Gradle dependency tree | Quick human reading, root cause | Plain text, hard to diff or feed to tools |
| Lock file | Reproducible builds | Records versions, not licenses or hashes of everything |
| SBOM | Sharing with customers and tools, matching to advisories | Needs a generation step in the pipeline |
For a shipped app, an SBOM per release is worth it. See SBOM for a shipped desktop or mobile app.
Try it yourself
Click through it at your own pace, or open it full screen.
Look at how the inventory separates direct from transitive packages, which is the same split you read in the Gradle tree.
Quick check
Does the dependencies task list libraries added by native code?
No. It lists what Gradle resolves. Prebuilt native libraries bundled by hand will not appear, so also inspect the built APK.
Which configuration should I read?
Start with the release runtime classpath for the module that builds your app.
Safeguard builds this kind of inventory through dependency and SBOM scanning and matches it against known vulnerabilities. You can run a free scan.
Sources
Last reviewed: 19 October 2026.