feat!: update to Maps SDK 2.0.0 (#2346)

* fix!: upgrade to Maps SDK v20 and resolve build issues

- Upgrade Google Maps SDK to v20.0.0 (BREAKING CHANGE: requires new renderer).
- Fix WearOS build by replacing deprecated kotlinOptions with jvmToolchain.
- Resolve WearOS dependency conflicts by using Kotlin BOM.
- Migrate WearOS dependencies and SDK versions to Version Catalog.
- Refactor Version Catalog: extract versions and organize groups.
- Fix FireMarkers sample: correct Google Services plugin application logic.
- FireMarkers: Add explicit error handling for 'Permission Denied'.

BREAKING CHANGE: This release upgrades the Maps SDK to v20.0.0, which may require code changes for the new renderer and other API adjustments.

* chore: verify build health and remove rx samples

- Create scripts/verify_all.sh for local verification
- Update CI to run tests and lint
- Remove deprecated snippets/app-rx module
- Fix FireMarkers unit tests
- Update README with verification instructions

* fix: add missing license header to verify_all.sh

* fix: remove app-rx from lint workflow

* fix(ci): remove foojay-resolver and rely on CI JDK 21

* fix: address review comments (README typo, settings repo mode)

* feat: add script to sync documentation versions with version catalog

* chore: finalize build settings and documentation versions

- CI: Upgrade to Java 21 and add python docs check

- Settings: Allow local repository overrides

- Docs: Annotate WearOS dependencies with hardcoded versions

* chore: expose version catalog instructions in docs and update sync script

* chore: restore snippets/app-rx to preserve documentation region tags
This commit is contained in:
Dale Hawkins 2026-01-28 14:52:54 -07:00 committed by GitHub
parent f128137079
commit 7e0db8ca37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 435 additions and 136 deletions

View File

@ -111,7 +111,6 @@ jobs:
./gradlew :snippets:app-utils-ktx:assembleDebug
./gradlew :snippets:app-compose:assembleDebug
./gradlew :snippets:app-places-ktx:assembleDebug
./gradlew :snippets:app-rx:assembleDebug
./gradlew :snippets:app-utils:assembleDebug
build-tutorials:
@ -134,13 +133,25 @@ jobs:
run: |
./gradlew :tutorials:kotlin:Polygons:assembleDebug
test: # used as required status check
test:
runs-on: ubuntu-latest
timeout-minutes: 60
needs:
- build-ApiDemos
- build-WearOS
- build-FireMarkers
- build-Snippets
- build-tutorials
- build-FireMarkers
steps:
- run: echo "Fail if all other steps are not successful"
- uses: actions/checkout@v4
- name: set up Java 21
uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: '21'
- name: Run Unit Tests
run: ./gradlew testDebugUnitTest
- name: Run Lint
run: ./gradlew lintDebug

View File

@ -31,7 +31,15 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: '17'
java-version: '21'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Check documentation versions
run: python3 scripts/update_docs_versions.py --check
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
@ -44,7 +52,6 @@ jobs:
./gradlew :snippets:app:lintGmsDebug
./gradlew :snippets:app-utils:lintDebug
./gradlew :snippets:app-utils-ktx:lintDebug
./gradlew :snippets:app-rx:lintDebug
./gradlew :snippets:app-places-ktx:lintDebug
./gradlew :snippets:app-ktx:lintDebug
./gradlew :snippets:app-compose:lintDebug
@ -87,12 +94,6 @@ jobs:
sarif_file: snippets/app-utils-ktx/build/reports/lint-results-debug.sarif
category: snippets-app-utils-ktx
- name: Upload SARIF for snippets:app-rx
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: snippets/app-rx/build/reports/lint-results-debug.sarif
category: snippets-app-rx
- name: Upload SARIF for snippets:app-places-ktx
uses: github/codeql-action/upload-sarif@v3
with:

View File

@ -45,13 +45,11 @@ plugins {
alias(libs.plugins.kotlin.serialization) // Provides Kotlin serialization capabilities.
}
gradle.projectsEvaluated {
if (rootProject.file("app/google-services.json").exists()) {
project(":app").pluginManager.apply("com.google.gms.google-services")
println("Applied Google Services plugin.")
} else {
println("google-services.json not found — skipping plugin application")
}
if (file("google-services.json").exists()) {
apply(plugin = "com.google.gms.google-services")
println("Applied Google Services plugin.")
} else {
println("google-services.json not found — skipping Google Services plugin")
}
android {

View File

@ -59,7 +59,7 @@ class FireMarkersApplication : Application() {
val mapsApiKey =
bundle.getString("com.google.android.geo.API_KEY") // Key name is important!
if (mapsApiKey == null || mapsApiKey.isBlank() || mapsApiKey == "DEFAULT_API_KEY") {
if (mapsApiKey.isNullOrBlank() || mapsApiKey == "DEFAULT_API_KEY") {
Toast.makeText(
this,
"Maps API Key was not set in secrets.properties",

View File

@ -154,10 +154,7 @@ class MarkersViewModel @Inject constructor(
}
override fun onCancelled(error: DatabaseError) {
Log.e(TAG, "[$viewModelId] Database error on markers: ${error.message}")
viewModelScope.launch {
_errorEvents.emit("Database error on markers: ${error.message}")
}
handleDatabaseError(error, "markers")
}
})
}
@ -187,14 +184,23 @@ class MarkersViewModel @Inject constructor(
}
override fun onCancelled(error: DatabaseError) {
Log.e(TAG, "[$viewModelId] DB error on animation: ${error.message}")
viewModelScope.launch {
_errorEvents.emit("DB error on animation: ${error.message}")
}
handleDatabaseError(error, "animation")
}
})
}
private fun handleDatabaseError(error: DatabaseError, context: String) {
val msg = if (error.code == DatabaseError.PERMISSION_DENIED) {
"Permission Denied ($context): Check your Firebase Database Rules."
} else {
"Database error ($context): ${error.message}"
}
Log.e(TAG, "[$viewModelId] $msg")
viewModelScope.launch {
_errorEvents.emit(msg)
}
}
/**
* Toggles the animation state (running/paused) in Firebase.
*

View File

@ -156,7 +156,7 @@ class MarkersViewModelTest {
listenerCaptor.firstValue.onCancelled(error)
testDispatcher.scheduler.advanceUntilIdle()
assertThat(errorMessage).isEqualTo("DB error on animation: Test Error")
assertThat(errorMessage).isEqualTo("Database error (animation): Test Error")
job.cancel()
}
}

View File

@ -0,0 +1 @@
mock-maker-inline

View File

@ -43,6 +43,14 @@ To run the samples, you will need:
1. In the welcome screen of Android Studio, select "Open an Existing project"
1. Select one of the sample directories from this repository
## Verifying the build
To verify that all samples build and pass tests, run:
```bash
./scripts/verify_all.sh
```
Alternatively, use the `gradlew build` command to build the project directly or download an APK
under [releases](https://github.com/googlemaps/android-samples/releases).

View File

@ -1,5 +1,5 @@
/*
* Copyright 2024 Google LLC
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,12 +21,12 @@ plugins {
}
android {
compileSdk = 35
compileSdk = libs.versions.compileSdk.get().toInt()
defaultConfig {
applicationId = "com.example.wearos"
minSdk = 23
targetSdk = 31
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
versionCode = 1
versionName = libs.versions.versionName.get()
}
@ -34,7 +34,7 @@ android {
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
@ -45,10 +45,6 @@ android {
sarifOutput = layout.buildDirectory.file("reports/lint-results-debug.sarif").get().asFile
}
kotlinOptions {
jvmTarget = "21"
}
kotlin {
jvmToolchain(21)
}
@ -57,15 +53,37 @@ android {
// [START maps_wear_os_dependencies]
dependencies {
// [START_EXCLUDE]
implementation("androidx.core:core-ktx:1.15.0")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21")
implementation(libs.core.ktx)
implementation(platform(libs.kotlin.bom))
implementation(libs.kotlin.stdlib)
// [END_EXCLUDE]
compileOnly("com.google.android.wearable:wearable:2.9.0")
implementation("com.google.android.support:wearable:2.9.0")
implementation("com.google.android.gms:play-services-maps:19.0.0")
// Modern Android projects use version catalogs to manage dependencies. To include the necessary dependencies,
// first add the following to your libs.versions.toml file:
//
// [versions]
// playServicesMaps = "20.0.0"
// wear = "1.3.0"
// wearable = "2.9.0"
//
// [libraries]
// play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
// wear = { group = "androidx.wear", name = "wear", version.ref = "wear" }
// wearable-compile = { group = "com.google.android.wearable", name = "wearable", version.ref = "wearable" }
// wearable-support = { group = "com.google.android.support", name = "wearable", version.ref = "wearable" }
compileOnly(libs.wearable.compile)
implementation(libs.wearable.support)
implementation(libs.play.services.maps)
// This dependency is necessary for ambient mode
implementation("androidx.wear:wear:1.3.0")
implementation(libs.wear)
// If your project does not use a version catalog, you can use the following dependencies instead:
//
// compileOnly("com.google.android.wearable:wearable:2.9.0")
// implementation("com.google.android.support:wearable:2.9.0")
// implementation("com.google.android.gms:play-services-maps:20.0.0")
// implementation("androidx.wear:wear:1.3.0")
}
// [END maps_wear_os_dependencies]

View File

@ -0,0 +1,13 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5760d82d08e6c26884debb23736ea57/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/879378f84c64b2c76003b97a32968399/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5760d82d08e6c26884debb23736ea57/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/879378f84c64b2c76003b97a32968399/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/021e528cbed860c875a9016f29ee13c1/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/6141bf023dcc7a96c47cad75c59b054e/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5760d82d08e6c26884debb23736ea57/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/879378f84c64b2c76003b97a32968399/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9b6bab41c3ef2acea6116b7821b8dc11/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/a6eb06d81d82a782734ef3b616ba2684/redirect
toolchainVendor=JETBRAINS
toolchainVersion=21

View File

@ -1,114 +1,151 @@
[versions]
# Project Configuration
androidGradlePlugin = "8.13.2"
minSdk = "24"
compileSdk = "36"
targetSdk = "36"
activity = "1.12.1"
activityKtx = "1.11.0"
androidxJunit = "1.3.0"
appcompat = "1.7.1"
cardview = "1.0.0"
coreKtx = "1.17.0"
easypermissions = "3.0.0"
espresso = "3.7.0"
gradle = "8.13.2"
hilt = "2.57.2"
junit = "4.13.2"
kotlin = "2.2.21"
lifecycle = "2.10.0"
mapsKtx = "5.2.1"
mapsCompose = "6.12.1"
material = "1.13.0"
multidex = "2.0.1"
navigation = "2.9.6"
playServicesMaps = "19.2.0"
places = "5.1.1"
recyclerview = "1.4.0"
secretsGradlePlugin = "2.0.1"
volley = "1.2.1"
truth = "1.4.5"
uiautomator = "2.3.0"
compose = "1.7.6"
composeBom = "2024.12.01"
hiltNavigationCompose = "1.2.0"
dagger = "2.57.2"
firebaseBom = "33.10.0"
kotlinxDatetime = "0.7.1"
kotlinxCoroutinesTest = "1.10.2"
robolectric = "4.16"
turbine = "1.2.1"
mockito = "6.1.0"
versionCode = "1"
# {x-release-please-start-version}
versionName = "1.20.1"
# {x-release-please-end}
versionName = "1.20.1" # {x-release-please-version}
javaVersion = "17"
# Kotlin & Coroutines
kotlin = "2.2.0"
kotlinxCoroutinesTest = "1.10.2"
kotlinxDatetime = "0.7.1"
ksp = "2.2.20-2.0.4"
# AndroidX Core & Jetpack
activity = "1.12.2"
activityKtx = "1.12.2"
androidxJunit = "1.3.0" # Test ext
appcompat = "1.7.1"
cardview = "1.0.0"
constraintlayout = "2.2.1"
coreKtx = "1.17.0"
lifecycle = "2.10.0"
multidex = "2.0.1"
navigation = "2.9.6"
recyclerview = "1.4.0"
# Jetpack Compose
compose = "1.10.1"
composeBom = "2026.01.00"
hiltNavigationCompose = "1.3.0"
material = "1.13.0" # View-based Material
material3 = "1.4.0"
materialIconsExtended = "1.7.8"
# Google Maps & Places
mapsCompose = "7.0.0"
mapsKtx = "6.0.0"
places = "5.1.1"
playServicesMaps = "20.0.0"
secretsGradlePlugin = "2.0.1"
# Wear OS
wear = "1.3.0"
wearable = "2.9.0"
# Dependency Injection
dagger = "2.57.2"
hilt = "2.57.2"
# Testing
espresso = "3.7.0"
junit = "4.13.2"
mockito = "6.2.2"
robolectric = "4.16.1"
truth = "1.4.5"
turbine = "1.2.1"
uiautomator = "2.3.0"
# Firebase
firebaseBom = "34.8.0"
firebaseDatabase = "22.0.1"
# Third Party
easypermissions = "3.0.0"
volley = "1.2.1"
[libraries]
# Kotlin
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
# AndroidX
activity = { module = "androidx.activity:activity", version.ref = "activity" }
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityKtx" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidxJunit" }
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidxJunit" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
cardview = { group = "androidx.cardview", name = "cardview", version.ref = "cardview" }
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
espresso-idling-resource = { module = "androidx.test.espresso:espresso-idling-resource", version.ref = "espresso" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
maps-ktx = { group = "com.google.maps.android", name = "maps-ktx", version.ref = "mapsKtx" }
maps-utils-ktx = { group = "com.google.maps.android", name = "maps-utils-ktx", version.ref = "mapsKtx" }
maps-compose = { module = "com.google.maps.android:maps-compose", version.ref = "mapsCompose" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
material3 = { module = "androidx.compose.material3:material3", version = "1.3.1" }
multidex = { group = "androidx.multidex", name = "multidex", version.ref = "multidex" }
navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigation" }
navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigation" }
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
places = { group = "com.google.android.libraries.places", name = "places", version.ref = "places" }
recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version = "2.2.0" }
# Compose
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose" }
compose-material = { module = "androidx.compose.material:material", version.ref = "compose" }
volley = { group = "com.android.volley", name = "volley", version.ref = "volley" }
truth = { group = "com.google.truth", name = "truth", version.ref = "truth" }
uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
easypermissions = { group = "pub.devrel", name = "easypermissions", version.ref = "easypermissions" }
hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
ui = { module = "androidx.compose.ui:ui", version.ref = "compose" }
ui-graphics = { module = "androidx.compose.ui:ui-graphics", version.ref = "compose" }
ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
# Maps & Places
maps-compose = { module = "com.google.maps.android:maps-compose", version.ref = "mapsCompose" }
maps-ktx = { group = "com.google.maps.android", name = "maps-ktx", version.ref = "mapsKtx" }
maps-utils-ktx = { group = "com.google.maps.android", name = "maps-utils-ktx", version.ref = "mapsKtx" }
places = { group = "com.google.android.libraries.places", name = "places", version.ref = "places" }
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
# Wear OS
wear = { group = "androidx.wear", name = "wear", version.ref = "wear" }
wearable-compile = { group = "com.google.android.wearable", name = "wearable", version.ref = "wearable" }
wearable-support = { group = "com.google.android.support", name = "wearable", version.ref = "wearable" }
# Dependency Injection
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
# Testing
espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
espresso-idling-resource = { module = "androidx.test.espresso:espresso-idling-resource", version.ref = "espresso" }
ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidxJunit" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTest" }
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockito" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
truth = { group = "com.google.truth", name = "truth", version.ref = "truth" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose" }
ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose" }
kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
maps-rx = { module = "com.google.maps.android:maps-rx", version = "1.0.0" }
places-rx = { module = "com.google.maps.android:places-rx", version = "1.0.0" }
rxlifecycle-android-lifecycle-kotlin = { module = "com.trello.rxlifecycle4:rxlifecycle-android-lifecycle-kotlin", version = "4.0.2" }
uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
# Firebase
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
firebase-database = { module = "com.google.firebase:firebase-database", version = "21.0.0" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTest" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockito" }
firebase-database = { module = "com.google.firebase:firebase-database", version.ref = "firebaseDatabase" }
# Third Party
easypermissions = { group = "pub.devrel", name = "easypermissions", version.ref = "easypermissions" }
volley = { group = "com.android.volley", name = "volley", version.ref = "volley" }
[plugins]
android-application = { id = "com.android.application", version.ref = "gradle" }
android-library = { id = "com.android.library", version.ref = "gradle" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
secrets-gradle-plugin = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secretsGradlePlugin" }
ksp = { id = "com.google.devtools.ksp", version = "2.2.20-2.0.4" }

111
scripts/update_docs_versions.py Executable file
View File

@ -0,0 +1,111 @@
#!/usr/bin/env python3
#
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import re
import sys
from pathlib import Path
def parse_versions_toml(toml_path):
versions = {}
with open(toml_path, 'r') as f:
for line in f:
# Simple regex to find string versions: name = "version"
match = re.match(r'^\s*(\w+)\s*=\s*"([^"]+)"', line)
if match:
versions[match.group(1)] = match.group(2)
return versions
def update_file(file_path, versions, check_only=False):
with open(file_path, 'r') as f:
content = f.read()
# Define replacements: (regex, replacement_template)
# matching: implementation(libs.foo) // com.group:artifact:VERSION
replacements = [
(
r'(compileOnly\(libs\.wearable\.compile\)\s*//\s*com\.google\.android\.wearable:wearable:)([\d\.]+)',
f'\\g<1>{versions.get("wearable", "UNKNOWN")}'
),
(
r'(implementation\(libs\.wearable\.support\)\s*//\s*com\.google\.android\.support:wearable:)([\d\.]+)',
f'\\g<1>{versions.get("wearable", "UNKNOWN")}'
),
(
r'(implementation\(libs\.play\.services\.maps\)\s*//\s*com\.google\.android\.gms:play-services-maps:)([\d\.]+)',
f'\\g<1>{versions.get("playServicesMaps", "UNKNOWN")}'
),
# Replacements for the "How-To" comment block
(
r'(//\s*wearable\s*=\s*")([\d\.]+)',
f'\\g<1>{versions.get("wearable", "UNKNOWN")}'
),
(
r'(//\s*playServicesMaps\s*=\s*")([\d\.]+)',
f'\\g<1>{versions.get("playServicesMaps", "UNKNOWN")}'
),
(
r'(//\s*wear\s*=\s*")([\d\.]+)',
f'\\g<1>{versions.get("wear", "UNKNOWN")}'
)
]
new_content = content
for pattern, replacement in replacements:
new_content = re.sub(pattern, replacement, new_content)
if new_content != content:
if check_only:
print(f"ERROR: {file_path} is out of sync with libs.versions.toml.")
print("Run 'python3 scripts/update_docs_versions.py' to update it.")
return False
else:
with open(file_path, 'w') as f:
f.write(new_content)
print(f"Updated {file_path}")
return True
if check_only:
print(f"SUCCESS: {file_path} is in sync.")
return True
def main():
parser = argparse.ArgumentParser(description='Sync documentation versions with Version Catalog')
parser.add_argument('--check', action='store_true', help='Check if files are up to date without modifying them')
args = parser.parse_args()
root_dir = Path(__file__).resolve().parent.parent
toml_path = root_dir / 'gradle' / 'libs.versions.toml'
target_file = root_dir / 'WearOS' / 'Wearable' / 'build.gradle.kts'
if not toml_path.exists():
print(f"Error: {toml_path} not found")
sys.exit(1)
versions = parse_versions_toml(toml_path)
if 'wearable' not in versions or 'playServicesMaps' not in versions:
print("Error: Could not find required versions in libs.versions.toml")
sys.exit(1)
success = update_file(target_file, versions, check_only=args.check)
if args.check and not success:
sys.exit(1)
if __name__ == '__main__':
main()

97
scripts/verify_all.sh Executable file
View File

@ -0,0 +1,97 @@
#!/bin/bash
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# script: verify_all.sh
# description: Builds and verifies all Android modules in the project.
set -e # Exit immediately if a command exits with a non-zero status.
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color
echo "Checking documentation versions sync..."
python3 scripts/update_docs_versions.py --check || {
echo "FAILURE: Documentation versions are out of sync with Version Catalog."
echo "Run 'python3 scripts/update_docs_versions.py' to fix."
exit 1
}
echo "Starting project verification..."
# List of modules to check
# Note: snippets has submodules, checking root snippets project might be enough if it aggregates them,
# but we'll be explicit or use standard tasks.
MODULES=(
":ApiDemos:java-app"
":ApiDemos:kotlin-app"
":ApiDemos:common-ui"
":FireMarkers:app"
":WearOS:Wearable"
":snippets:app"
":snippets:app-ktx"
":snippets:app-utils-ktx"
":snippets:app-compose"
":snippets:app-places-ktx"
":snippets:app-utils"
":tutorials:kotlin:Polygons"
)
# Function to run verification for a module
verify_module() {
local module=$1
echo "------------------------------------------------"
# Determine variant-specific tasks
local assembleTask=":assembleDebug"
local testTask=":testDebugUnitTest"
local lintTask=":lintDebug"
if [[ "$module" == ":snippets:app" ]]; then
assembleTask=":assembleGmsDebug"
testTask=":testGmsDebugUnitTest"
lintTask=":lintGmsDebug"
fi
# Run assemble, lint, and test
if ./gradlew "$module$assembleTask" "$module$testTask" "$module$lintTask"; then
echo -e "${GREEN}SUCCESS: $module verified.${NC}"
else
echo -e "${RED}FAILURE: $module failed verification.${NC}"
return 1
fi
}
FAILED_MODULES=()
for module in "${MODULES[@]}"; do
if ! verify_module "$module"; then
FAILED_MODULES+=("$module")
fi
done
echo "------------------------------------------------"
if [ ${#FAILED_MODULES[@]} -eq 0 ]; then
echo -e "${GREEN}ALL MODULES PASSED VERIFICATION.${NC}"
exit 0
else
echo -e "${RED}THE FOLLOWING MODULES FAILED:${NC}"
for failed in "${FAILED_MODULES[@]}"; do
echo -e "${RED}- $failed${NC}"
done
exit 1
fi

View File

@ -26,7 +26,7 @@ pluginManagement {
// [START maps_android_settings_dependency_resolution_management]
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
@ -63,8 +63,6 @@ include(":snippets:app-compose")
project(":snippets:app-compose").projectDir = file("snippets/app-compose")
include(":snippets:app-places-ktx")
project(":snippets:app-places-ktx").projectDir = file("snippets/app-places-ktx")
include(":snippets:app-rx")
project(":snippets:app-rx").projectDir = file("snippets/app-rx")
include(":snippets:app-utils")
project(":snippets:app-utils").projectDir = file("snippets/app-utils")

View File

@ -16,7 +16,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -16,7 +16,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -16,7 +16,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -16,7 +16,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -16,7 +16,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -18,7 +18,7 @@
plugins {
// [START_EXCLUDE]
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.android)
// [END_EXCLUDE]
alias(libs.plugins.secrets.gradle.plugin)
}

View File

@ -17,7 +17,7 @@
// [START maps_android_secrets_gradle_plugin_project_level_config]
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.secrets.gradle.plugin) apply false
}