diff --git a/.changeset/lazy-donuts-search.md b/.changeset/lazy-donuts-search.md new file mode 100644 index 00000000..7144b9c8 --- /dev/null +++ b/.changeset/lazy-donuts-search.md @@ -0,0 +1,5 @@ +--- +"posthog-android": patch +--- + +Fix a manually configured `releaseIdentifier` being overwritten by the auto-generated fallback (`applicationId@versionName+versionCode`), which broke proguard symbolication due to the map-id mismatch. A pre-set `releaseIdentifier` is now preserved; the value from `posthog-meta.properties` is used when nothing was set, and the fallback only when neither exists. diff --git a/posthog-android/src/main/java/com/posthog/android/internal/PostHogMetaPropertiesApplier.kt b/posthog-android/src/main/java/com/posthog/android/internal/PostHogMetaPropertiesApplier.kt index 9527b85d..dd67f6b2 100644 --- a/posthog-android/src/main/java/com/posthog/android/internal/PostHogMetaPropertiesApplier.kt +++ b/posthog-android/src/main/java/com/posthog/android/internal/PostHogMetaPropertiesApplier.kt @@ -36,26 +36,25 @@ internal class PostHogMetaPropertiesApplier() { config: PostHogAndroidConfig, releaseIdentifierFallback: String, ) { - val metaProperties = loadMetaProperties(context, config) - // if releaseIdentifier is already set, we don't need to do anything - if (!config.releaseIdentifier.isNullOrEmpty() || metaProperties.isNullOrEmpty()) { - config.logger.log("releaseIdentifier not found, using fallback: $releaseIdentifierFallback") - config.releaseIdentifier = releaseIdentifierFallback + if (!config.releaseIdentifier.isNullOrEmpty()) { return } - for (property in metaProperties) { + val metaProperties = loadMetaProperties(context, config) + + metaProperties?.forEach { property -> val uuid = property.getProperty(POSTHOG_PROGUARD_MAPPING_MAP_ID_PROPERTY) - if (uuid.isNullOrEmpty()) { - continue + if (!uuid.isNullOrEmpty()) { + config.logger.log("releaseIdentifier found: $uuid") + config.releaseIdentifier = uuid + return } - - config.logger.log("releaseIdentifier found: $uuid") - config.releaseIdentifier = uuid - break } + + config.logger.log("releaseIdentifier not found, using fallback: $releaseIdentifierFallback") + config.releaseIdentifier = releaseIdentifierFallback } companion object { diff --git a/posthog-android/src/test/java/com/posthog/android/internal/PostHogMetaPropertiesApplierTest.kt b/posthog-android/src/test/java/com/posthog/android/internal/PostHogMetaPropertiesApplierTest.kt new file mode 100644 index 00000000..ae6e1056 --- /dev/null +++ b/posthog-android/src/test/java/com/posthog/android/internal/PostHogMetaPropertiesApplierTest.kt @@ -0,0 +1,88 @@ +package com.posthog.android.internal + +import android.content.Context +import android.content.res.AssetManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.posthog.android.API_KEY +import com.posthog.android.PostHogAndroidConfig +import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import java.io.ByteArrayInputStream +import java.io.FileNotFoundException +import kotlin.test.Test +import kotlin.test.assertEquals + +@RunWith(AndroidJUnit4::class) +internal class PostHogMetaPropertiesApplierTest { + private val context = mock() + private val assets = mock() + private val config = PostHogAndroidConfig(API_KEY) + + private val sut = PostHogMetaPropertiesApplier() + + private fun mockMetaProperties(content: String) { + whenever(context.assets).thenReturn(assets) + whenever(assets.open(any())).thenReturn(ByteArrayInputStream(content.toByteArray())) + } + + private fun mockMissingMetaProperties() { + whenever(context.assets).thenReturn(assets) + whenever(assets.open(any())).thenThrow(FileNotFoundException()) + } + + @Test + fun `preserves manually set releaseIdentifier`() { + config.releaseIdentifier = "manual-id" + mockMetaProperties("io.posthog.proguard.mapid=meta-id") + + sut.applyToConfig(context, config, FALLBACK) + + assertEquals("manual-id", config.releaseIdentifier) + verify(assets, never()).open(any()) + } + + @Test + fun `uses meta properties map id when releaseIdentifier not set`() { + mockMetaProperties("io.posthog.proguard.mapid=meta-id") + + sut.applyToConfig(context, config, FALLBACK) + + assertEquals("meta-id", config.releaseIdentifier) + } + + @Test + fun `uses fallback when meta properties file is missing`() { + mockMissingMetaProperties() + + sut.applyToConfig(context, config, FALLBACK) + + assertEquals(FALLBACK, config.releaseIdentifier) + } + + @Test + fun `uses fallback when meta properties do not contain map id`() { + mockMetaProperties("some.other.property=value") + + sut.applyToConfig(context, config, FALLBACK) + + assertEquals(FALLBACK, config.releaseIdentifier) + } + + @Test + fun `uses fallback when reading meta properties throws`() { + whenever(context.assets).thenReturn(assets) + whenever(assets.open(any())).thenThrow(RuntimeException("boom")) + + sut.applyToConfig(context, config, FALLBACK) + + assertEquals(FALLBACK, config.releaseIdentifier) + } + + companion object { + private const val FALLBACK = "com.package@1.0.0+1" + } +}