Skip to main content

Overview

TechSales uses Gradle’s version catalog feature for centralized dependency management. All dependencies are declared in gradle/libs.versions.toml and referenced type-safely in build files.

App Dependencies

The application module declares its dependencies in app/build.gradle.kts:
app/build.gradle.kts
dependencies {
    implementation(libs.appcompat)
    implementation(libs.material)
    implementation(libs.activity)
    implementation(libs.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

Core Dependencies

AndroidX AppCompat

libs.appcompat
Library
required
Provides backward-compatible versions of Android framework APIs.Version: 1.6.1
Group: androidx.appcompat
Artifact: appcompat
implementation(libs.appcompat)
Key Features:
  • Material Design components
  • ActionBar and Toolbar support
  • AppCompatActivity and theme support
  • Vector drawables on older Android versions
AppCompat is essential for maintaining consistency across Android versions. It backports newer UI components to older devices.

Material Design Components

libs.material
Library
required
Google’s Material Design component library for Android.Version: 1.10.0
Group: com.google.android.material
Artifact: material
implementation(libs.material)
Key Features:
  • Material Design 3 components
  • Bottom sheets, navigation drawers, cards
  • Floating action buttons (FAB)
  • Text fields and input layouts
  • Snackbars and dialogs

AndroidX Activity

libs.activity
Library
required
Modern activity handling with result contracts and ViewModels.Version: 1.8.0
Group: androidx.activity
Artifact: activity
implementation(libs.activity)
Key Features:
  • Activity Result API
  • ComponentActivity base class
  • OnBackPressedDispatcher
  • Integration with ViewModels and Lifecycle

ConstraintLayout

libs.constraintlayout
Library
required
Flexible layout manager for creating responsive UIs.Version: 2.1.4
Group: androidx.constraintlayout
Artifact: constraintlayout
implementation(libs.constraintlayout)
Key Features:
  • Flat view hierarchy for better performance
  • Responsive layouts without nested ViewGroups
  • Constraint-based positioning
  • Guidelines, barriers, and chains
ConstraintLayout is the recommended layout manager for modern Android apps. It reduces layout nesting and improves performance.

Test Dependencies

JUnit 4

libs.junit
Library
Standard unit testing framework for Java/Kotlin.Version: 4.13.2
Group: junit
Artifact: junit
Configuration: testImplementation
testImplementation(libs.junit)
Use Cases:
  • Unit tests for business logic
  • ViewModel testing
  • Repository and data source tests
  • Utility function tests

AndroidX JUnit Extension

libs.ext.junit
Library
AndroidX test runner with JUnit 4 integration.Version: 1.1.5
Group: androidx.test.ext
Artifact: junit
Configuration: androidTestImplementation
androidTestImplementation(libs.ext.junit)
Use Cases:
  • Instrumented tests that require Android context
  • Activity and Fragment testing
  • Integration tests

Espresso

libs.espresso.core
Library
UI testing framework for Android.Version: 3.5.1
Group: androidx.test.espresso
Artifact: espresso-core
Configuration: androidTestImplementation
androidTestImplementation(libs.espresso.core)
Use Cases:
  • UI interaction testing
  • View matching and assertions
  • Automated user flow testing
Espresso tests run on real devices or emulators and can interact with your app’s UI like a real user would.

Version Catalog Structure

The version catalog is defined in gradle/libs.versions.toml:
gradle/libs.versions.toml
[versions]
agp = "9.0.1"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
appcompat = "1.6.1"
material = "1.10.0"
activity = "1.8.0"
constraintlayout = "2.1.4"

[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }

Structure Breakdown

[versions] Section:
  • Declares version numbers as variables
  • Referenced using version.ref in library declarations
  • Single source of truth for versions
[libraries] Section:
  • Declares dependencies with Maven coordinates
  • Format: { group = "...", name = "...", version.ref = "..." }
  • Accessed in build files as libs.libraryName
[plugins] Section:
  • Declares Gradle plugins
  • Accessed as libs.plugins.pluginName

Dependency Configurations

Implementation

implementation(libs.appcompat)
  • Used for dependencies required at runtime
  • Not exposed to consumers (in library modules)
  • Faster compilation than api

TestImplementation

testImplementation(libs.junit)
  • Used for unit test dependencies
  • Only available in test source set
  • Not included in APK

AndroidTestImplementation

androidTestImplementation(libs.espresso.core)
  • Used for instrumented test dependencies
  • Only available in androidTest source set
  • Not included in production APK
Choose the most restrictive configuration possible. Using testImplementation instead of implementation for test-only dependencies reduces APK size.

Adding New Dependencies

Step 1: Add Version to Catalog

Edit gradle/libs.versions.toml:
[versions]
# Existing versions...
retrofit = "2.9.0"

[libraries]
# Existing libraries...
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }

Step 2: Add to Build File

Edit app/build.gradle.kts:
dependencies {
    // Existing dependencies...
    implementation(libs.retrofit)
    implementation(libs.retrofit.gson)
}

Step 3: Sync Project

Click “Sync Now” in Android Studio or run:
./gradlew build
Android Studio provides auto-completion for version catalog entries. Type libs. to see available dependencies.

Updating Dependencies

Manual Updates

  1. Edit version in gradle/libs.versions.toml
  2. Sync the project
  3. Test thoroughly

Checking for Updates

Use the Gradle Versions Plugin:
build.gradle.kts
plugins {
    id("com.github.ben-manes.versions") version "0.51.0"
}
Then run:
./gradlew dependencyUpdates
Always test your app after updating dependencies, especially major version updates. Check release notes for breaking changes.

Dependency Management Best Practices

1. Use Version Catalogs

// Good - Type-safe and centralized
implementation(libs.appcompat)

// Avoid - String literals scattered across files
implementation("androidx.appcompat:appcompat:1.6.1")
[versions]
retrofit = "2.9.0"

[libraries]
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }

3. Use Specific Configurations

// Good - Minimizes APK size
testImplementation(libs.junit)

// Avoid - Includes test dependency in production
implementation(libs.junit)

4. Avoid Dynamic Versions

# Good - Pinned version
appcompat = "1.6.1"

# Avoid - Unpredictable builds
appcompat = "1.6.+"
appcompat = "latest.release"

5. Document Custom Dependencies

Add comments in libs.versions.toml for non-standard dependencies:
[libraries]
# Custom analytics SDK from internal repository
analytics-sdk = { group = "com.company.internal", name = "analytics", version.ref = "analyticsSdk" }

Viewing Dependency Tree

To see all dependencies and their transitive dependencies:
# All configurations
./gradlew :app:dependencies

# Specific configuration
./gradlew :app:dependencies --configuration releaseRuntimeClasspath

Resolving Dependency Conflicts

When multiple dependencies require different versions of the same library:
dependencies {
    implementation(libs.appcompat)
    
    // Force specific version
    constraints {
        implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0") {
            because("standardize Kotlin version across all dependencies")
        }
    }
}
Forcing dependency versions can lead to compatibility issues. Only use this when necessary and test thoroughly.

Common Dependencies to Add

Here are commonly added dependencies for Android apps:
[versions]
retrofit = "2.9.0"
okhttp = "4.12.0"

[libraries]
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }

Build docs developers (and LLMs) love