Android SharedPreferences Tutorial and Example

A practical Gradle version manager for Android dependencies

Android applications combine your code with AndroidX, Material Components, testing tools, and SDKs supplied by other teams. One outdated or mismatched library can trigger resolution failures, duplicate classes, or crashes on only a subset of devices. The usual fix—editing several build files—works until the same version appears in a fifth place.

A Gradle version catalog moves those versions into one checked-in file and gives each dependency a typed alias. Your build scripts request an alias instead of repeating a Maven coordinate and version. This makes managing dependencies with a version manager practical for small apps and multi-module products.

The catalog also creates a clear review boundary: dependency changes appear as ordinary source-code changes. The examples below use Kotlin build scripts and a root gradle/libs.versions.toml, which Gradle discovers automatically.

Centralising dependency versions

Direct declarations keep the coordinate beside its use, but the same library may require different versions in several modules. A catalog separates selection from declaration, allowing every module to request the approved alias. Here, the version manager concerns Maven-style libraries; Android’s SDK Manager handles platform packages and build tools instead.

Concern Direct declarations Version catalog
Version source Repeated in build files One TOML file
Reuse Copy and paste Shared version references
Mistakes Typos and version mismatches Generated, fail-fast accessors
Review Changes scattered across modules One focused diff

The catalog cannot remove compatibility conflicts, but it exposes them earlier. A failed version request points to an alias, while build scans and dependency reports reveal which path upgraded the library.

Creating a version catalog

Create gradle/libs.versions.toml at the project root. Library aliases describe the module and point to a named version; no extra plugin is needed for this standard Gradle location.

[versions]
agp = "8.7.3"
coreKtx = "1.15.0"
junit = "4.13.2"

[libraries]
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
junit = { module = "junit:junit", version.ref = "junit" }

After Gradle sync, the library aliases become typed accessors: libs.androidx.core.ktx and libs.junit. Hyphens in TOML aliases become dots in Kotlin accessors, and an invalid alias stops compilation instead of becoming a runtime surprise. Check the Android Gradle Plugin compatibility requirements before adopting these sample versions.

Applying catalog declarations

Replace the versioned dependency with its accessor in the module that needs it.

dependencies {
    implementation(libs.androidx.core.ktx)
    testImplementation(libs.junit)
}

Plugin versions can use the same catalog. Add a plugin alias to the TOML file, then apply it with alias(...).

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

In build.gradle.kts, use alias(libs.plugins.android.application). Keep the catalog as the single source of truth: when migrating, remove old direct declarations and check that debug-only, test, and release configurations still receive the intended artifacts.

Sharing versions and bundles

Related libraries often need coordinated versions. A bundle groups them under one accessor, while a bill of materials supplies a compatible version set.

[versions]
composeBom = "2024.12.01"

[libraries]
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
compose-ui = { module = "androidx.compose.ui:ui" }
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }

[bundles]
compose = ["compose-ui", "compose-ui-tooling"]

Apply the bill of materials before the bundled libraries.

dependencies {
    implementation(platform(libs.compose.bom))
    implementation(libs.bundles.compose)
}

For critical libraries, Gradle’s rich version constraints can define an accepted range or reject a known-bad release. This adds deliberate control without scattering policy text across modules. Avoid open ranges and changing versions such as 1.+; they make builds depend on the day they run.

Supporting hybrid Android apps

Australian banking, retail, and transport apps used in Sydney and Melbourne often combine native screens with WebView content. A hybrid project can catalog AndroidX WebKit, core libraries, and any bridge component together, keeping native and web-facing capabilities on compatible versions.

For the bridge itself, this JavaScript bridge tutorial demonstrates how JavaScriptInterface connects WebView JavaScript to Android code. Treat that bridge as a security boundary: expose only required methods, validate untrusted input, and test it on the Android versions and devices used by the project’s audience.

The catalog also helps when WebView support arrives through several transitive paths. A dependency report can confirm that one AndroidX WebKit version is selected rather than several releases arriving through unrelated libraries.

Verifying builds and releases

Run ./gradlew test for unit tests, ./gradlew connectedAndroidTest for instrumented tests, and ./gradlew dependencies whenever an upgrade changes the graph. dependencyInsight is especially useful for explaining why Gradle selected a particular version.

Dependency locking can pin the resolved graph after a known-good build. Gradle can then write and update lock state deliberately, while dependency verification metadata checks downloaded artifacts against trusted hashes. Keep both under version control and review lock-file churn as carefully as source changes.

If an Android workflow hands users to a browser, browser-based acceptance tests can verify that web journey, while instrumentation tests cover the native return path. During Australian Eastern Daylight Time, a release can begin in Brisbane at UTC+10 and reach Sydney at UTC+11, so reproducible builds and timestamped test evidence prevent confusion between teams.

Maintaining a safe update routine

A scheduled dependency review is more reliable than accepting every automated pull request. Maintainers read release notes, run the full test suite, inspect APK size and startup time, and check whether a transitive library gained new network or background behaviour. Renovate can propose catalog updates, but a maintainer still approves the resulting diff.

Privacy obligations make that review concrete for Australian releases. Under the Privacy Act 1988 and the Australian Privacy Principles, teams should know which third-party SDKs collect personal information, where that data goes, and whether consent and retention controls remain correct after an upgrade. A dependency that changes telemetry can alter the app’s obligations without changing its visible interface.

For Australians relying on metered mobile plans or conserving battery during their commute, a nominally small update can add download weight, wake-ups, or data use. Release checks compare artefacts, profile a representative device, and record the tested dependency combination. The catalog then remains a dependable record of the libraries behind each Android release.