Skip to content

Commit 91c7af5

Browse files
authoredJan 28, 2025··
fix: session replay and auto capture works with 'with' method (#217)
1 parent c6b9942 commit 91c7af5

19 files changed

+171
-107
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## Next
22

33
- chore: Session Replay - GA
4+
- fix: session replay and auto capture works with 'with' method ([#217](https://github.com/PostHog/posthog-flutter/pull/217))
45
- fix: sending cached events null check ([#218](https://github.com/PostHog/posthog-flutter/pull/218))
56

67
## 3.10.0 - 2025-01-07

‎posthog-android/api/posthog-android.api

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public final class com/posthog/android/replay/PostHogReplayIntegration : com/pos
6464
public static final field ANDROID_COMPOSE_VIEW_CLASS_NAME Ljava/lang/String;
6565
public static final field PH_NO_CAPTURE_LABEL Ljava/lang/String;
6666
public fun <init> (Landroid/content/Context;Lcom/posthog/android/PostHogAndroidConfig;Lcom/posthog/android/internal/MainHandler;)V
67-
public fun install ()V
67+
public fun install (Lcom/posthog/PostHogInterface;)V
6868
public fun uninstall ()V
6969
}
7070

‎posthog-android/src/main/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegration.kt

+11-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import android.app.Activity
44
import android.app.Application
55
import android.app.Application.ActivityLifecycleCallbacks
66
import android.os.Bundle
7-
import com.posthog.PostHog
87
import com.posthog.PostHogIntegration
8+
import com.posthog.PostHogInterface
99
import com.posthog.android.PostHogAndroidConfig
1010

1111
/**
@@ -17,6 +17,8 @@ internal class PostHogActivityLifecycleCallbackIntegration(
1717
private val application: Application,
1818
private val config: PostHogAndroidConfig,
1919
) : ActivityLifecycleCallbacks, PostHogIntegration {
20+
private var postHog: PostHogInterface? = null
21+
2022
override fun onActivityCreated(
2123
activity: Activity,
2224
savedInstanceState: Bundle?,
@@ -39,7 +41,10 @@ internal class PostHogActivityLifecycleCallbackIntegration(
3941
} finally {
4042
data?.let { props["url"] = it.toString() }
4143
intent.getReferrerInfo(config).let { props.putAll(it) }
42-
PostHog.capture("Deep Link Opened", properties = props)
44+
45+
if (props.isNotEmpty()) {
46+
postHog?.capture("Deep Link Opened", properties = props)
47+
}
4348
}
4449
}
4550
}
@@ -50,7 +55,7 @@ internal class PostHogActivityLifecycleCallbackIntegration(
5055
val screenName = activity.activityLabelOrName(config)
5156

5257
if (!screenName.isNullOrEmpty()) {
53-
PostHog.screen(screenName)
58+
postHog?.screen(screenName)
5459
}
5560
}
5661
}
@@ -73,11 +78,13 @@ internal class PostHogActivityLifecycleCallbackIntegration(
7378
override fun onActivityDestroyed(activity: Activity) {
7479
}
7580

76-
override fun install() {
81+
override fun install(postHog: PostHogInterface) {
82+
this.postHog = postHog
7783
application.registerActivityLifecycleCallbacks(this)
7884
}
7985

8086
override fun uninstall() {
87+
this.postHog = null
8188
application.unregisterActivityLifecycleCallbacks(this)
8289
}
8390
}

‎posthog-android/src/main/java/com/posthog/android/internal/PostHogAppInstallIntegration.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.posthog.android.internal
22

33
import android.content.Context
4-
import com.posthog.PostHog
54
import com.posthog.PostHogIntegration
5+
import com.posthog.PostHogInterface
66
import com.posthog.android.PostHogAndroidConfig
77
import com.posthog.internal.PostHogPreferences.Companion.BUILD
88
import com.posthog.internal.PostHogPreferences.Companion.VERSION
@@ -16,7 +16,7 @@ internal class PostHogAppInstallIntegration(
1616
private val context: Context,
1717
private val config: PostHogAndroidConfig,
1818
) : PostHogIntegration {
19-
override fun install() {
19+
override fun install(postHog: PostHogInterface) {
2020
getPackageInfo(context, config)?.let { packageInfo ->
2121
config.cachePreferences?.let { preferences ->
2222
val versionName = packageInfo.versionName
@@ -52,7 +52,7 @@ internal class PostHogAppInstallIntegration(
5252
preferences.setValue(VERSION, versionName)
5353
preferences.setValue(BUILD, versionCode)
5454

55-
PostHog.capture(event, properties = props)
55+
postHog.capture(event, properties = props)
5656
}
5757
}
5858
}

‎posthog-android/src/main/java/com/posthog/android/internal/PostHogLifecycleObserverIntegration.kt

+10-6
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import androidx.lifecycle.DefaultLifecycleObserver
55
import androidx.lifecycle.Lifecycle
66
import androidx.lifecycle.LifecycleOwner
77
import androidx.lifecycle.ProcessLifecycleOwner
8-
import com.posthog.PostHog
98
import com.posthog.PostHogIntegration
9+
import com.posthog.PostHogInterface
1010
import com.posthog.android.PostHogAndroidConfig
1111
import java.util.Timer
1212
import java.util.TimerTask
@@ -30,6 +30,8 @@ internal class PostHogLifecycleObserverIntegration(
3030
private val lastUpdatedSession = AtomicLong(0L)
3131
private val sessionMaxInterval = (1000 * 60 * 30).toLong() // 30 minutes
3232

33+
private var postHog: PostHogInterface? = null
34+
3335
private companion object {
3436
// in case there are multiple instances or the SDK is closed/setup again
3537
// the value is still cached
@@ -54,7 +56,7 @@ internal class PostHogLifecycleObserverIntegration(
5456
fromBackground = true
5557
}
5658

57-
PostHog.capture("Application Opened", properties = props)
59+
postHog?.capture("Application Opened", properties = props)
5860
}
5961
}
6062

@@ -67,7 +69,7 @@ internal class PostHogLifecycleObserverIntegration(
6769
if (lastUpdatedSession == 0L ||
6870
(lastUpdatedSession + sessionMaxInterval) <= currentTimeMillis
6971
) {
70-
PostHog.startSession()
72+
postHog?.startSession()
7173
}
7274
this.lastUpdatedSession.set(currentTimeMillis)
7375
}
@@ -85,7 +87,7 @@ internal class PostHogLifecycleObserverIntegration(
8587
timerTask =
8688
object : TimerTask() {
8789
override fun run() {
88-
PostHog.endSession()
90+
postHog?.endSession()
8991
}
9092
}
9193
timer.schedule(timerTask, sessionMaxInterval)
@@ -94,7 +96,7 @@ internal class PostHogLifecycleObserverIntegration(
9496

9597
override fun onStop(owner: LifecycleOwner) {
9698
if (config.captureApplicationLifecycleEvents) {
97-
PostHog.capture("Application Backgrounded")
99+
postHog?.capture("Application Backgrounded")
98100
}
99101

100102
val currentTimeMillis = config.dateProvider.currentTimeMillis()
@@ -106,8 +108,9 @@ internal class PostHogLifecycleObserverIntegration(
106108
lifecycle.addObserver(this)
107109
}
108110

109-
override fun install() {
111+
override fun install(postHog: PostHogInterface) {
110112
try {
113+
this.postHog = postHog
111114
if (isMainThread(mainHandler)) {
112115
add()
113116
} else {
@@ -126,6 +129,7 @@ internal class PostHogLifecycleObserverIntegration(
126129

127130
override fun uninstall() {
128131
try {
132+
this.postHog = null
129133
if (isMainThread(mainHandler)) {
130134
remove()
131135
} else {

‎posthog-android/src/main/java/com/posthog/android/replay/PostHogReplayIntegration.kt

+9-5
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ import androidx.compose.ui.semantics.SemanticsProperties
4949
import androidx.compose.ui.semantics.getAllSemanticsNodes
5050
import androidx.core.view.ViewCompat
5151
import androidx.core.view.WindowInsetsCompat
52-
import com.posthog.PostHog
5352
import com.posthog.PostHogIntegration
53+
import com.posthog.PostHogInterface
5454
import com.posthog.android.PostHogAndroidConfig
5555
import com.posthog.android.internal.MainHandler
5656
import com.posthog.android.internal.densityValue
@@ -118,12 +118,14 @@ public class PostHogReplayIntegration(
118118
}
119119

120120
private val isSessionReplayEnabled: Boolean
121-
get() = PostHog.isSessionReplayActive()
121+
get() = postHog?.isSessionReplayActive() ?: false
122122

123123
// flutter captures snapshots, so we don't need to capture them here
124124
private val isNativeSdk: Boolean
125125
get() = (config.sdkName != "posthog-flutter")
126126

127+
private var postHog: PostHogInterface? = null
128+
127129
private fun addView(
128130
view: View,
129131
added: Boolean = true,
@@ -280,7 +282,7 @@ public class PostHogReplayIntegration(
280282
// if we batch them, we need to be aware that the order of the events matters
281283
// also because if we send a mouse interaction later, it might be attached to the wrong
282284
// screen
283-
mouseInteractions.capture()
285+
mouseInteractions.capture(postHog)
284286
}
285287
}
286288

@@ -311,10 +313,11 @@ public class PostHogReplayIntegration(
311313
decorViews.remove(view)
312314
}
313315

314-
override fun install() {
316+
override fun install(postHog: PostHogInterface) {
315317
if (!isSupported()) {
316318
return
317319
}
320+
this.postHog = postHog
318321

319322
// workaround for react native that is started after the window is added
320323
// Curtains.rootViews should be empty for normal apps yet
@@ -331,6 +334,7 @@ public class PostHogReplayIntegration(
331334

332335
override fun uninstall() {
333336
try {
337+
this.postHog = null
334338
Curtains.onRootViewsChangedListeners -= onRootViewsChangedListener
335339

336340
decorViews.entries.forEach {
@@ -460,7 +464,7 @@ public class PostHogReplayIntegration(
460464
}
461465

462466
if (events.isNotEmpty()) {
463-
events.capture()
467+
events.capture(postHog)
464468
}
465469

466470
status.lastSnapshot = wireframe

‎posthog-android/src/main/java/com/posthog/android/replay/internal/PostHogLogCatIntegration.kt

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.posthog.android.replay.internal
22

33
import android.annotation.SuppressLint
44
import android.os.Build
5-
import com.posthog.PostHog
65
import com.posthog.PostHogIntegration
6+
import com.posthog.PostHogInterface
77
import com.posthog.android.PostHogAndroidConfig
88
import com.posthog.internal.interruptSafely
99
import com.posthog.internal.replay.RRPluginEvent
@@ -18,12 +18,15 @@ internal class PostHogLogCatIntegration(private val config: PostHogAndroidConfig
1818
private var logcatThread: Thread? = null
1919

2020
private val isSessionReplayEnabled: Boolean
21-
get() = PostHog.isSessionReplayActive()
21+
get() = postHog?.isSessionReplayActive() ?: false
2222

23-
override fun install() {
23+
private var postHog: PostHogInterface? = null
24+
25+
override fun install(postHog: PostHogInterface) {
2426
if (!config.sessionReplayConfig.captureLogcat || !isSupported()) {
2527
return
2628
}
29+
this.postHog = postHog
2730
val cmd = mutableListOf("logcat", "-v", "threadtime", "*:E")
2831
val sdf = SimpleDateFormat("MM-dd HH:mm:ss.mmm", Locale.ROOT)
2932
cmd.add("-T")
@@ -65,7 +68,7 @@ internal class PostHogLogCatIntegration(private val config: PostHogAndroidConfig
6568
val time = log.time?.time?.time ?: config.dateProvider.currentTimeMillis()
6669
val event = RRPluginEvent("rrweb/console@1", props, time)
6770
// TODO: batch events
68-
listOf(event).capture()
71+
listOf(event).capture(postHog)
6972
}
7073
} catch (e: Throwable) {
7174
// ignore
@@ -87,6 +90,7 @@ internal class PostHogLogCatIntegration(private val config: PostHogAndroidConfig
8790
}
8891

8992
override fun uninstall() {
93+
this.postHog = null
9094
logcatInProgress = false
9195
logcatThread?.interruptSafely()
9296
}

‎posthog-android/src/test/java/com/posthog/android/internal/PostHogActivityLifecycleCallbackIntegrationTest.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {
4343
fun `install registers the lifecycle callback`() {
4444
val sut = getSut()
4545

46-
sut.install()
46+
val fake = createPostHogFake()
47+
48+
sut.install(fake)
4749

4850
verify(application).registerActivityLifecycleCallbacks(any())
4951
}
@@ -66,7 +68,7 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {
6668

6769
val fake = createPostHogFake()
6870

69-
sut.install()
71+
sut.install(fake)
7072
sut.onActivityCreated(activity, null)
7173
return fake
7274
}
@@ -80,7 +82,7 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {
8082

8183
val fake = createPostHogFake()
8284

83-
sut.install()
85+
sut.install(fake)
8486
sut.onActivityCreated(activity, null)
8587
return fake
8688
}
@@ -160,7 +162,7 @@ internal class PostHogActivityLifecycleCallbackIntegrationTest {
160162

161163
val fake = createPostHogFake()
162164

163-
sut.install()
165+
sut.install(fake)
164166
sut.onActivityStarted(activity)
165167
return fake
166168
}

‎posthog-android/src/test/java/com/posthog/android/internal/PostHogAppInstallIntegrationTest.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ internal class PostHogAppInstallIntegrationTest {
3939

4040
val fake = createPostHogFake()
4141

42-
sut.install()
42+
sut.install(fake)
4343

4444
assertEquals("Application Installed", fake.event)
4545
assertEquals("1.0.0", fake.properties?.get("version"))
@@ -54,11 +54,11 @@ internal class PostHogAppInstallIntegrationTest {
5454

5555
val fake = createPostHogFake()
5656

57-
sut.install()
57+
sut.install(fake)
5858

5959
context.mockPackageInfo("2.0.0", 2)
6060

61-
sut.install()
61+
sut.install(fake)
6262

6363
assertEquals("Application Updated", fake.event)
6464
assertEquals("1.0.0", fake.properties?.get("previous_version"))
@@ -75,11 +75,11 @@ internal class PostHogAppInstallIntegrationTest {
7575

7676
val fake = createPostHogFake()
7777

78-
sut.install()
78+
sut.install(fake)
7979

8080
assertEquals(1, fake.captures)
8181

82-
sut.install()
82+
sut.install(fake)
8383

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

0 commit comments

Comments
 (0)
Please sign in to comment.