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
2 changes: 1 addition & 1 deletion .github/actions/coverage/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ runs:
with:
path: './${{ inputs.directory }}/coverage/lcov.info'
min_coverage: ${{ inputs.min-coverage }}
exclude: 'lib/src/native/cocoa/binding.dart'
exclude: 'lib/src/native/**/binding.dart lib/src/native/java/android_replay_recorder.dart'
1 change: 1 addition & 0 deletions .github/file-filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ high_risk_code: &high_risk_code
- "flutter/ios/Classes/SentryFlutterPluginApple.swift"
- "flutter/lib/src/screenshot/recorder.dart"
- "flutter/lib/src/screenshot/widget_filter.dart"
- "flutter/lib/src/native/java/android_replay_recorder.dart"
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased 9.0.0

### Breaking changes

- Remove `SentryDisplayWidget` and manual TTID implementation ([#2668](https://github.com/getsentry/sentry-dart/pull/2668))
- Increase minimum SDK version requirements to Dart v3.5.0 and Flutter v3.24.0 ([#2643](https://github.com/getsentry/sentry-dart/pull/2643))
- Remove screenshot option `attachScreenshotOnlyWhenResumed` ([#2664](https://github.com/getsentry/sentry-dart/pull/2664))
Expand All @@ -12,6 +14,10 @@
- Add hint for transactions ([#2675](https://github.com/getsentry/sentry-dart/pull/2675))
- `BeforeSendTransactionCallback` now has a `Hint` parameter

### Enhancements

- Replay: improve Android native interop performance by using JNI ([#2670](https://github.com/getsentry/sentry-dart/pull/2670))

### Dependencies

- Bump Android SDK from v7.20.1 to v8.1.0 ([#2650](https://github.com/getsentry/sentry-dart/pull/2650))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.flutter

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.res.Configuration
Expand Down Expand Up @@ -35,7 +36,6 @@ import io.sentry.protocol.DebugImage
import io.sentry.protocol.SentryId
import io.sentry.protocol.User
import io.sentry.transport.CurrentDateProvider
import java.io.File
import java.lang.ref.WeakReference
import kotlin.math.roundToInt

Expand All @@ -49,7 +49,6 @@ class SentryFlutterPlugin :
private lateinit var channel: MethodChannel
private lateinit var context: Context
private lateinit var sentryFlutter: SentryFlutter
private lateinit var replay: ReplayIntegration

// Note: initial config because we don't yet have the numbers of the actual Flutter widget.
// See how SentryFlutterReplayRecorder.start() handles it. New settings will be set by setReplayConfig() method below.
Expand Down Expand Up @@ -103,7 +102,6 @@ class SentryFlutterPlugin :
"displayRefreshRate" -> displayRefreshRate(result)
"nativeCrash" -> crash()
"setReplayConfig" -> setReplayConfig(call, result)
"addReplayScreenshot" -> addReplayScreenshot(call.argument("path"), call.argument("timestamp"), result)
"captureReplay" -> captureReplay(call.argument("isCrash"), result)
else -> result.notImplemented()
}
Expand Down Expand Up @@ -164,15 +162,13 @@ class SentryFlutterPlugin :
private fun setupReplay(options: SentryAndroidOptions) {
// Replace the default ReplayIntegration with a Flutter-specific recorder.
options.integrations.removeAll { it is ReplayIntegration }
val cacheDirPath = options.cacheDirPath
val replayOptions = options.sessionReplay
val isReplayEnabled = replayOptions.isSessionReplayEnabled || replayOptions.isSessionReplayForErrorsEnabled
if (cacheDirPath != null && isReplayEnabled) {
if (replayOptions.isSessionReplayEnabled || replayOptions.isSessionReplayForErrorsEnabled) {
replay =
ReplayIntegration(
context,
context.applicationContext,
dateProvider = CurrentDateProvider.getInstance(),
recorderProvider = { SentryFlutterReplayRecorder(channel, replay) },
recorderProvider = { SentryFlutterReplayRecorder(channel, replay!!) },
recorderConfigProvider = {
Log.i(
"Sentry",
Expand All @@ -187,8 +183,8 @@ class SentryFlutterPlugin :
},
replayCacheProvider = null,
)
replay.breadcrumbConverter = SentryFlutterReplayBreadcrumbConverter()
options.addIntegration(replay)
replay!!.breadcrumbConverter = SentryFlutterReplayBreadcrumbConverter()
options.addIntegration(replay!!)
options.setReplayController(replay)
} else {
options.setReplayController(null)
Expand Down Expand Up @@ -517,8 +513,13 @@ class SentryFlutterPlugin :
}

companion object {
@SuppressLint("StaticFieldLeak")
private var replay: ReplayIntegration? = null

private const val NATIVE_CRASH_WAIT_TIME = 500L

@JvmStatic fun privateSentryGetReplayIntegration(): ReplayIntegration? = replay

private fun crash() {
val exception = RuntimeException("FlutterSentry Native Integration: Sample RuntimeException")
val mainThread = Looper.getMainLooper().thread
Expand Down Expand Up @@ -552,19 +553,6 @@ class SentryFlutterPlugin :
result.success(serializedScope)
}

private fun addReplayScreenshot(
path: String?,
timestamp: Long?,
result: Result,
) {
if (path == null || timestamp == null) {
result.error("5", "Arguments are null", null)
return
}
replay.onScreenshotRecorded(File(path), timestamp)
result.success("")
}

private fun setReplayConfig(
call: MethodCall,
result: Result,
Expand Down Expand Up @@ -614,7 +602,7 @@ class SentryFlutterPlugin :
replayConfig.bitRate,
),
)
replay.onConfigurationChanged(Configuration())
replay!!.onConfigurationChanged(Configuration())
result.success("")
}

Expand All @@ -626,7 +614,7 @@ class SentryFlutterPlugin :
result.error("5", "Arguments are null", null)
return
}
replay.captureReplay(isCrash)
result.success(replay.getReplayId().toString())
replay!!.captureReplay(isCrash)
result.success(replay!!.getReplayId().toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,11 @@ internal class SentryFlutterReplayRecorder(
return
}

val cacheDirPath = integration.replayCacheDir?.absolutePath
if (cacheDirPath == null) {
Log.w("Sentry", "Replay cache directory is null, can't start replay recorder.")
return
}
Handler(Looper.getMainLooper()).post {
try {
channel.invokeMethod(
"ReplayRecorder.start",
mapOf(
"directory" to cacheDirPath,
"width" to recorderConfig.recordingWidth,
"height" to recorderConfig.recordingHeight,
"frameRate" to recorderConfig.frameRate,
Expand Down
18 changes: 18 additions & 0 deletions flutter/ffi-jni.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
android_sdk_config:
add_gradle_deps: true
android_example: 'example/'

# summarizer:
# backend: asm

output:
dart:
path: lib/src/native/java/binding.dart
structure: single_file

log_level: all

classes:
- io.sentry.android.replay.ReplayIntegration
- io.sentry.flutter.SentryFlutterPlugin
- android.graphics.Bitmap
Loading
Loading