Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-donuts-search.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Context>()
private val assets = mock<AssetManager>()
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")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually a more important case I saw in prod, tens of thousands of frames per week here at a first/quick look (although some could be older versions who don't have a releaseIdentifier in the first place).

the first one with manual releaseIdentifier isn't as common


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"
}
}
Loading