Repository navigation
feat(library): Integrate internal usage attribution ID #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,12 @@ plugins { | |
| alias(libs.plugins.spotless) apply false | ||
| } | ||
|
|
||
| allprojects { | ||
| // {x-release-please-start-version} | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This repo is released with semantic-release (see |
||
| version = "1.13.0" | ||
| // {x-release-please-end} | ||
| } | ||
|
|
||
| subprojects { | ||
| tasks.withType<Test>().configureEach { | ||
| jvmArgs("--add-opens=java.base/jdk.internal.access=ALL-UNNAMED") | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /build |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,114 @@ | ||||||
| /* | ||||||
| * 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 org.jetbrains.kotlin.gradle.dsl.JvmTarget | ||||||
|
|
||||||
| plugins { | ||||||
| alias(libs.plugins.android.library) | ||||||
| alias(libs.plugins.kotlin.android) | ||||||
| alias(libs.plugins.spotless) | ||||||
| } | ||||||
|
|
||||||
| configure<com.diffplug.gradle.spotless.SpotlessExtension> { | ||||||
| kotlin { | ||||||
| target("**/*.kt") | ||||||
| ktlint().editorConfigOverride( | ||||||
| mapOf( | ||||||
| "indent_size" to "4", | ||||||
| "ktlint_function_naming_ignore_when_annotated_with" to "Composable", | ||||||
| "ktlint_standard_max-line-length" to "disabled", | ||||||
| ), | ||||||
| ) | ||||||
| trimTrailingWhitespace() | ||||||
| endWithNewline() | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| android { | ||||||
| namespace = "com.example.maps3dsamples.library" | ||||||
| compileSdk = libs.versions.compileSdk.get().toInt() | ||||||
|
|
||||||
| defaultConfig { | ||||||
| minSdk = libs.versions.minSdk.get().toInt() | ||||||
| testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||||
| consumerProguardFiles("consumer-rules.pro") | ||||||
| } | ||||||
|
|
||||||
| compileOptions { | ||||||
| sourceCompatibility = JavaVersion.VERSION_11 | ||||||
| targetCompatibility = JavaVersion.VERSION_11 | ||||||
| } | ||||||
|
|
||||||
| kotlin { | ||||||
| compilerOptions { | ||||||
| jvmTarget.set(JvmTarget.JVM_11) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| dependencies { | ||||||
| implementation(libs.play.services.maps) | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related to the comment above: this pulls |
||||||
| implementation(libs.startup.runtime) | ||||||
| testImplementation(libs.junit) | ||||||
| testImplementation(libs.robolectric) | ||||||
| testImplementation(libs.mockk) | ||||||
| testImplementation(libs.androidx.core) | ||||||
| } | ||||||
|
|
||||||
| abstract class GenerateArtifactIdTask : DefaultTask() { | ||||||
| @get:OutputDirectory | ||||||
| abstract val outputDir: DirectoryProperty | ||||||
|
|
||||||
| @get:Input | ||||||
| abstract val version: Property<String> | ||||||
|
|
||||||
| @TaskAction | ||||||
| fun generate() { | ||||||
| val dir = outputDir.get().asFile | ||||||
| val packageName = "com.example.maps3dsamples.library.utils.meta" | ||||||
| val packagePath = packageName.replace('.', '/') | ||||||
| val outputFile = File(dir, "$packagePath/ArtifactId.kt") | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the generated object is
Suggested change
|
||||||
| outputFile.parentFile.mkdirs() | ||||||
| val attributionId = "gmp_git_androidmaps3dsamples_v${version.get()}" | ||||||
| outputFile.writeText( | ||||||
| """ | ||||||
| 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(), | ||||||
| ) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| val generateArtifactIdFile = tasks.register<GenerateArtifactIdTask>("generateArtifactIdFile") { | ||||||
| outputDir.set(layout.buildDirectory.dir("generated/source/artifactId")) | ||||||
| version.set(project.version.toString()) | ||||||
| } | ||||||
|
|
||||||
| androidComponents { | ||||||
| onVariants { variant -> | ||||||
| variant.sources.java?.addGeneratedSourceDirectory( | ||||||
| generateArtifactIdFile, | ||||||
| GenerateArtifactIdTask::outputDir, | ||||||
| ) | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # Consumer ProGuard rules for attribution ID initializer |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <!-- | ||
| 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. | ||
| --> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| xmlns:tools="http://schemas.android.com/tools"> | ||
| <application> | ||
| <provider | ||
| android:name="androidx.startup.InitializationProvider" | ||
| android:authorities="${applicationId}.androidx-startup" | ||
| android:exported="false" | ||
| tools:node="merge"> | ||
|
|
||
| <meta-data | ||
| android:name="com.example.maps3dsamples.library.utils.attribution.AttributionIdInitializer" | ||
| android:value="androidx.startup" /> | ||
| </provider> | ||
| </application> | ||
| </manifest> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
| package com.example.maps3dsamples.library.utils.attribution | ||
|
|
||
| import android.content.Context | ||
| import androidx.annotation.Keep | ||
| import androidx.startup.Initializer | ||
| import com.example.maps3dsamples.library.utils.meta.AttributionId | ||
| import com.google.android.gms.maps.MapsApiSettings | ||
|
|
||
| /** | ||
| * Adds a usage attribution ID to the initializer, which helps Google understand which libraries | ||
| * and samples are helpful to developers, such as usage of this library. | ||
| * To opt out of sending the usage attribution ID, please remove this initializer from your manifest. | ||
| */ | ||
| @Keep | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: androidx.startup already ships the keep rules for |
||
| internal class AttributionIdInitializer : Initializer<Unit> { | ||
| override fun create(context: Context) { | ||
| MapsApiSettings.addInternalUsageAttributionId( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @LoyalAbbas . Just to understand it: |
||
| // context = | ||
| context, | ||
| // internalUsageAttributionId = | ||
| AttributionId.VALUE, | ||
| ) | ||
| } | ||
|
|
||
| override fun dependencies(): List<Class<out Initializer<*>>> = emptyList() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
| package com.example.maps3dsamples.library.utils.attribution | ||
|
|
||
| import android.content.Context | ||
| import androidx.test.core.app.ApplicationProvider | ||
| import com.example.maps3dsamples.library.utils.meta.AttributionId | ||
| import com.google.android.gms.maps.MapsApiSettings | ||
| import io.mockk.every | ||
| import io.mockk.just | ||
| import io.mockk.mockkStatic | ||
| import io.mockk.runs | ||
| import io.mockk.unmockkStatic | ||
| import io.mockk.verify | ||
| import org.junit.After | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import org.robolectric.RobolectricTestRunner | ||
|
|
||
| @RunWith(RobolectricTestRunner::class) | ||
| class AttributionIdInitializerTest { | ||
| @Before | ||
| fun setUp() { | ||
| mockkStatic(MapsApiSettings::class) | ||
| every { MapsApiSettings.addInternalUsageAttributionId(any(), any()) } just runs | ||
| } | ||
|
|
||
| @After | ||
| fun tearDown() { | ||
| unmockkStatic(MapsApiSettings::class) | ||
| } | ||
|
|
||
| @Test | ||
| fun `create adds internal usage attribution id`() { | ||
| val context = ApplicationProvider.getApplicationContext<Context>() | ||
| val initializer = AttributionIdInitializer() | ||
|
|
||
| initializer.create(context) | ||
|
|
||
| verify { | ||
| MapsApiSettings.addInternalUsageAttributionId( | ||
| context, | ||
| AttributionId.VALUE, | ||
| ) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a samples repo, so a developer copying one of the samples will not get the
:librarymodule. What about rephrasing it slightly?