From 4b59320a7fb99d06b7ad045ed3a86f3561c278a8 Mon Sep 17 00:00:00 2001 From: dkhawk <107309+dkhawk@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:12:55 -0700 Subject: [PATCH 1/2] feat: Add automatic AttributionId initialization at application startup --- gradle/libs.versions.toml | 2 + library/build.gradle.kts | 53 ++++++++++++++++++ library/src/main/AndroidManifest.xml | 13 ++++- .../attibution/AttributionIdInitializer.kt | 55 +++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8acf97e4e..d92304d44 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,9 +24,11 @@ lint = "31.13.0" org-jacoco-core = "0.8.13" material = "1.13.0" gradleMavenPublishPlugin = "0.34.0" +androidx-startup-runtime = "1.2.0" [libraries] appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } +androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup-runtime" } dokka-gradle-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka-gradle-plugin" } gradle = { module = "com.android.tools.build:gradle", version.ref = "gradle" } jacoco-android = { module = "com.mxalbert.gradle:jacoco-android", version.ref = "jacoco-android" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 11329b883..bc2bf10eb 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -60,6 +60,7 @@ android { unitTests.isReturnDefaultValues = true } namespace = "com.google.maps.android" + sourceSets["main"].java.srcDir("build/generated/source/artifactId") } dependencies { @@ -75,6 +76,7 @@ dependencies { testImplementation(libs.kotlin.test) testImplementation(libs.truth) implementation(libs.kotlin.stdlib.jdk8) + implementation(libs.androidx.startup.runtime) testImplementation(libs.mockk) testImplementation(libs.kotlinx.coroutines.test) @@ -89,3 +91,54 @@ tasks.register("instrumentTest") { if (System.getenv("JITPACK") != null) { apply(plugin = "maven") } + +// START: Attribution ID Generation Logic + +// 1. Define the attribution string format. +// It uses the 'version' property inherited from the root build.gradle.kts. +// Customize the prefix to match your library's identifier. +val attributionId = "gmp_git_androidmapsutils_v$version" + +// 2. Register the custom Gradle task. +val generateArtifactIdFile = tasks.register("generateArtifactIdFile") { + description = "Generates an AttributionId object from the project version." + group = "build" + + // 3. Define the output directory and file. + val outputDir = layout.buildDirectory.dir("generated/source/artifactId") + val packageName = "com.google.maps.android.utils.meta" // <-- Customize your package name + val packagePath = packageName.replace('.', '/') + val outputFile = outputDir.get().file("$packagePath/ArtifactId.kt").asFile + + // 4. Declare the output file so Gradle understands task dependencies. + outputs.file(outputFile) + + // 5. Define the action that writes the file. + doLast { + outputFile.parentFile.mkdirs() + outputFile.writeText( + // This is the content of the generated Kotlin file. + // It uses Kotlin's trimIndent() for clean formatting. + """ + package $packageName + + /** + * Automatically generated object containing the library's attribution ID. + * This is used to track library usage for analytics. + */ + public object AttributionId { + public const val VALUE: String = "$attributionId" + } + """.trimIndent() + ) + println("Generated attribution ID file at: ${outputFile.absolutePath}") + } +} + +// 6. Hook the custom task into the build lifecycle. +// This ensures your file is generated before the Kotlin compiler needs it. +tasks.named("preBuild") { + dependsOn(generateArtifactIdFile) +} + +// END: Attribution ID Generation Logic diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index bb23d7b93..436be07d1 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -15,12 +15,23 @@ limitations under the License. --> - + + + + + diff --git a/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt b/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt new file mode 100644 index 000000000..8a5211b46 --- /dev/null +++ b/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2025 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 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. + */ + +package com.google.maps.android.utils.attibution + +import android.content.Context +import android.util.Log +import androidx.startup.Initializer +import com.google.android.gms.maps.MapsApiSettings +import com.google.maps.android.utils.meta.AttributionId +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +/** + * Initializes the AttributionId at application startup. + */ +internal class AttributionIdInitializer : Initializer { + override fun create(context: Context) { + Log.d(TAG, "Initializing AttributionId: ${AttributionId.VALUE}") + + // 🚨 CRITICAL: Launch the potentially blocking call on the IO thread + CoroutineScope(Dispatchers.IO).launch { + Log.d(TAG, "Running MapsApiSettings.addInternalUsageAttributionId on background thread.") + + // This is now safely off the main thread + MapsApiSettings.addInternalUsageAttributionId( + /* context = */ context, + /* internalUsageAttributionId = */ AttributionId.VALUE + ) + } + } + + override fun dependencies(): List>> { + return emptyList() + } + + private companion object { + private val TAG = AttributionIdInitializer::class.java.simpleName + } +} From f9b538a06a8e3104405ecd3e42e4930cb05b3808 Mon Sep 17 00:00:00 2001 From: dkhawk <107309+dkhawk@users.noreply.github.com> Date: Wed, 12 Nov 2025 11:17:36 -0700 Subject: [PATCH 2/2] refactor(attribution): Remove logging from AttributionIdInitializer This change removes debug logging statements from the `AttributionIdInitializer` to reduce log verbosity. --- .../utils/attibution/AttributionIdInitializer.kt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt b/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt index 8a5211b46..4e5062d96 100644 --- a/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt +++ b/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt @@ -18,7 +18,6 @@ package com.google.maps.android.utils.attibution import android.content.Context -import android.util.Log import androidx.startup.Initializer import com.google.android.gms.maps.MapsApiSettings import com.google.maps.android.utils.meta.AttributionId @@ -31,12 +30,8 @@ import kotlinx.coroutines.launch */ internal class AttributionIdInitializer : Initializer { override fun create(context: Context) { - Log.d(TAG, "Initializing AttributionId: ${AttributionId.VALUE}") - - // 🚨 CRITICAL: Launch the potentially blocking call on the IO thread + // 🚨 CRITICAL: Launch the potentially blocking call on the IO dispatcher CoroutineScope(Dispatchers.IO).launch { - Log.d(TAG, "Running MapsApiSettings.addInternalUsageAttributionId on background thread.") - // This is now safely off the main thread MapsApiSettings.addInternalUsageAttributionId( /* context = */ context, @@ -48,8 +43,4 @@ internal class AttributionIdInitializer : Initializer { override fun dependencies(): List>> { return emptyList() } - - private companion object { - private val TAG = AttributionIdInitializer::class.java.simpleName - } }