Skip to content
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

fix: do not allow default integrations multiple times #219

Merged
merged 7 commits into from
Jan 30, 2025
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
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
## Next

- fix: do not allow default integrations multiple times ([#219](https://github.com/PostHog/posthog-android/pull/219))

## 3.11.0 - 2025-01-27

- chore: Session Replay - GA
- fix: session replay and auto capture works with 'with' method ([#217](https://github.com/PostHog/posthog-flutter/pull/217))
- fix: sending cached events null check ([#218](https://github.com/PostHog/posthog-flutter/pull/218))
- fix: session replay and auto capture works with 'with' method ([#217](https://github.com/PostHog/posthog-android/pull/217))
Copy link
Member Author

Choose a reason for hiding this comment

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

ups, copy-pasta error

- fix: sending cached events null check ([#218](https://github.com/PostHog/posthog-android/pull/218))

## 3.10.0 - 2025-01-07

- chore: change screenshots debouncing approach to throttling ([#214](https://github.com/PostHog/posthog-flutter/pull/214))
- chore: change screenshots debouncing approach to throttling ([#214](https://github.com/PostHog/posthog-android/pull/214))
- Added `throttleDelayMs` config and deprecated `debouncerDelayMs` config.
- chore: change screenshot image type from JPEG to WEBP ([#211](https://github.com/PostHog/posthog-android/pull/211))

Expand Down
13 changes: 12 additions & 1 deletion posthog-android/lint-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

<issue
id="GradleDependency"
message="A newer version of androidx.compose.ui:ui than 1.0.0 is available: 1.7.6"
message="A newer version of androidx.compose.ui:ui than 1.0.0 is available: 1.7.7"
errorLine1=" compileOnly(&quot;androidx.compose.ui:ui:${PosthogBuildConfig.Dependencies.ANDROIDX_COMPOSE}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
Expand All @@ -45,4 +45,15 @@
column="17"/>
</issue>

<issue
id="GradleDependency"
message="A newer version of org.jetbrains.kotlin:kotlin-test-junit than 1.8.22 is available: 1.9.20"
errorLine1=" testImplementation(&quot;org.jetbrains.kotlin:kotlin-test-junit:${PosthogBuildConfig.Kotlin.KOTLIN}&quot;)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="build.gradle.kts"
line="108"
column="24"/>
</issue>

</issues>
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ public class PostHogAndroid private constructor() {

/**
* Setup the SDK and returns an instance that you can hold and pass it around
*
* All default PostHogIntegration's will only be installed for the very 1st instance,
* either that be created with the [setup] or [with] method otherwise they would race each other
* and cause issues, so the 1st instance of the SDK that is created on the hosting app
* will hold all installed integrations, the order of the setup matters.
*
* @param T the type of the Config
* @property context the Context
* @property config the Config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ internal class PostHogActivityLifecycleCallbackIntegration(
) : ActivityLifecycleCallbacks, PostHogIntegration {
private var postHog: PostHogInterface? = null

private companion object {
@Volatile
private var integrationInstalled = false
}

override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?,
Expand Down Expand Up @@ -79,12 +84,18 @@ internal class PostHogActivityLifecycleCallbackIntegration(
}

override fun install(postHog: PostHogInterface) {
if (integrationInstalled) {
return
}
integrationInstalled = true

this.postHog = postHog
application.registerActivityLifecycleCallbacks(this)
}

override fun uninstall() {
this.postHog = null
integrationInstalled = false
application.unregisterActivityLifecycleCallbacks(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@ internal class PostHogAppInstallIntegration(
private val context: Context,
private val config: PostHogAndroidConfig,
) : PostHogIntegration {
private companion object {
@Volatile
private var integrationInstalled = false
}

override fun install(postHog: PostHogInterface) {
if (integrationInstalled) {
return
}
integrationInstalled = true

getPackageInfo(context, config)?.let { packageInfo ->
config.cachePreferences?.let { preferences ->
val versionName = packageInfo.versionName
Expand Down Expand Up @@ -56,4 +66,8 @@ internal class PostHogAppInstallIntegration(
}
}
}

override fun uninstall() {
integrationInstalled = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ internal class PostHogLifecycleObserverIntegration(
@JvmStatic
@Volatile
private var fromBackground = false

@Volatile
private var integrationInstalled = false
}

override fun onStart(owner: LifecycleOwner) {
Expand Down Expand Up @@ -109,6 +112,11 @@ internal class PostHogLifecycleObserverIntegration(
}

override fun install(postHog: PostHogInterface) {
if (integrationInstalled) {
return
}
integrationInstalled = true

try {
this.postHog = postHog
if (isMainThread(mainHandler)) {
Expand All @@ -129,6 +137,7 @@ internal class PostHogLifecycleObserverIntegration(

override fun uninstall() {
try {
integrationInstalled = false
this.postHog = null
if (isMainThread(mainHandler)) {
remove()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,10 @@ public class PostHogReplayIntegration(
}

override fun install(postHog: PostHogInterface) {
if (!isSupported()) {
if (integrationInstalled || !isSupported()) {
return
}
integrationInstalled = true
this.postHog = postHog

// workaround for react native that is started after the window is added
Expand All @@ -334,6 +335,7 @@ public class PostHogReplayIntegration(

override fun uninstall() {
try {
integrationInstalled = false
this.postHog = null
Curtains.onRootViewsChangedListeners -= onRootViewsChangedListener

Expand Down Expand Up @@ -1272,5 +1274,8 @@ public class PostHogReplayIntegration(
const val PH_NO_CAPTURE_LABEL: String = "ph-no-capture"
const val ANDROID_COMPOSE_VIEW_CLASS_NAME: String = "androidx.compose.ui.platform.AndroidComposeView"
const val ANDROID_COMPOSE_VIEW: String = "AndroidComposeView"

@Volatile
private var integrationInstalled = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@ internal class PostHogLogCatIntegration(private val config: PostHogAndroidConfig

private var postHog: PostHogInterface? = null

private companion object {
@Volatile
private var integrationInstalled = false
}

override fun install(postHog: PostHogInterface) {
if (!config.sessionReplayConfig.captureLogcat || !isSupported()) {
if (integrationInstalled || !config.sessionReplayConfig.captureLogcat || !isSupported()) {
return
}
integrationInstalled = true
this.postHog = postHog
val cmd = mutableListOf("logcat", "-v", "threadtime", "*:E")
val sdf = SimpleDateFormat("MM-dd HH:mm:ss.mmm", Locale.ROOT)
Expand Down Expand Up @@ -90,6 +96,7 @@ internal class PostHogLogCatIntegration(private val config: PostHogAndroidConfig
}

override fun uninstall() {
integrationInstalled = false
this.postHog = null
logcatInProgress = false
logcatThread?.interruptSafely()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {
sut.install(fake)

verify(application).registerActivityLifecycleCallbacks(any())

sut.uninstall()
}

@Test
Expand All @@ -70,6 +72,8 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {

sut.install(fake)
sut.onActivityCreated(activity, null)
sut.uninstall()

return fake
}

Expand All @@ -84,6 +88,8 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {

sut.install(fake)
sut.onActivityCreated(activity, null)
sut.uninstall()

return fake
}

Expand Down Expand Up @@ -164,6 +170,8 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {

sut.install(fake)
sut.onActivityStarted(activity)
sut.uninstall()

return fake
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ internal class PostHogAppInstallIntegrationTest {
assertEquals("Application Installed", fake.event)
assertEquals("1.0.0", fake.properties?.get("version"))
assertEquals(1L, fake.properties?.get("build"))

sut.uninstall()
}

@Test
Expand All @@ -58,13 +60,16 @@ internal class PostHogAppInstallIntegrationTest {

context.mockPackageInfo("2.0.0", 2)

sut.uninstall()
sut.install(fake)

assertEquals("Application Updated", fake.event)
assertEquals("1.0.0", fake.properties?.get("previous_version"))
assertEquals(1L, fake.properties?.get("previous_build"))
assertEquals("2.0.0", fake.properties?.get("version"))
assertEquals(2L, fake.properties?.get("build"))

sut.uninstall()
}

@Test
Expand All @@ -79,9 +84,12 @@ internal class PostHogAppInstallIntegrationTest {

assertEquals(1, fake.captures)

sut.uninstall()
sut.install(fake)

// sanity check
assertEquals(1, fake.captures)

sut.uninstall()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ internal class PostHogLifecycleObserverIntegrationTest {
sut.install(fake)

assertEquals(1, fakeLifecycle.observers)

sut.uninstall()
}

@Test
Expand Down Expand Up @@ -69,6 +71,8 @@ internal class PostHogLifecycleObserverIntegrationTest {
assertEquals("1.0.0", fake.properties?.get("version"))
assertEquals(1L, fake.properties?.get("build"))
assertEquals(false, fake.properties?.get("from_background"))

sut.uninstall()
}

@Test
Expand All @@ -84,6 +88,8 @@ internal class PostHogLifecycleObserverIntegrationTest {

assertEquals("Application Opened", fake.event)
assertEquals(true, fake.properties?.get("from_background"))

sut.uninstall()
}

@Test
Expand All @@ -97,5 +103,7 @@ internal class PostHogLifecycleObserverIntegrationTest {
sut.onStop(ProcessLifecycleOwner.get())

assertEquals("Application Backgrounded", fake.event)

sut.uninstall()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@ internal class PostHogSendCachedEventsIntegration(
private val startDate: Date,
private val executor: ExecutorService,
) : PostHogIntegration {
private companion object {
@Volatile
private var integrationInstalled = false
}

override fun install(postHog: PostHogInterface) {
if (integrationInstalled) {
return
}
integrationInstalled = true

executor.executeSafely {
if (config.networkStatus?.isConnected() == false) {
config.logger.log("Network isn't connected.")
Expand Down Expand Up @@ -216,4 +226,8 @@ internal class PostHogSendCachedEventsIntegration(
}
}
}

override fun uninstall() {
integrationInstalled = false
}
}
Loading
Loading