diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt index 98007c4553..93cb5200f6 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/CaptureStrategy.kt @@ -58,6 +58,10 @@ internal interface CaptureStrategy { companion object { private const val BREADCRUMB_START_OFFSET = 100L + // 5 minutes, otherwise relay will just drop it. Can prevent the case where the device + // time is wrong and the segment is too long. + private const val MAX_SEGMENT_DURATION = 1000L * 60 * 5 + fun createSegment( scopes: IScopes?, options: SentryOptions, @@ -76,7 +80,7 @@ internal interface CaptureStrategy { events: Deque ): ReplaySegment { val generatedVideo = cache?.createVideoOf( - duration, + minOf(duration, MAX_SEGMENT_DURATION), currentSegmentTimestamp.time, segmentId, height, @@ -179,7 +183,9 @@ internal interface CaptureStrategy { recordingPayload += rrwebEvent // fill in the urls array from navigation breadcrumbs - if ((rrwebEvent as? RRWebBreadcrumbEvent)?.category == "navigation") { + if ((rrwebEvent as? RRWebBreadcrumbEvent)?.category == "navigation" && + rrwebEvent.data?.getOrElse("to", { null }) is String + ) { urls.add(rrwebEvent.data!!["to"] as String) } } diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/capture/SessionCaptureStrategyTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/capture/SessionCaptureStrategyTest.kt index 79afdb8f85..b704350125 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/capture/SessionCaptureStrategyTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/capture/SessionCaptureStrategyTest.kt @@ -336,6 +336,30 @@ class SessionCaptureStrategyTest { ) } + @Test + fun `does not throw when navigation destination is not a String`() { + val now = + System.currentTimeMillis() + (fixture.options.sessionReplay.sessionSegmentDuration * 5) + val strategy = fixture.getSut(dateProvider = { now }) + strategy.start(fixture.recorderConfig) + + fixture.scope.addBreadcrumb(Breadcrumb().apply { category = "navigation" }) + + strategy.onScreenshotRecorded(mock()) {} + + verify(fixture.scopes).captureReplay( + check { + assertNull(it.urls?.firstOrNull()) + }, + check { + val breadcrumbEvents = + it.replayRecording?.payload?.filterIsInstance() + assertEquals("navigation", breadcrumbEvents?.first()?.category) + assertNull(breadcrumbEvents?.first()?.data?.get("to")) + } + ) + } + @Test fun `sets screen from scope as replay url`() { fixture.scope.screen = "MainActivity"