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..4e5062d96 --- /dev/null +++ b/library/src/main/java/com/google/maps/android/utils/attibution/AttributionIdInitializer.kt @@ -0,0 +1,46 @@ +/* + * 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 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) { + // 🚨 CRITICAL: Launch the potentially blocking call on the IO dispatcher + CoroutineScope(Dispatchers.IO).launch { + // This is now safely off the main thread + MapsApiSettings.addInternalUsageAttributionId( + /* context = */ context, + /* internalUsageAttributionId = */ AttributionId.VALUE + ) + } + } + + override fun dependencies(): List>> { + return emptyList() + } +}