Skip to content

Commit

Permalink
Merge branch 'v9' into v9-remove-max-response-body-size
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor authored Feb 13, 2025
2 parents 1a10873 + 793410d commit d2bc90a
Show file tree
Hide file tree
Showing 38 changed files with 4,773 additions and 162 deletions.
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"
17 changes: 17 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 @@ -15,6 +17,10 @@
- Responses are now only attached if size is below ~15mb
- Responses are attached to the `Hint` object, which can be read in `beforeSend`/`beforeSendTransaction` callbacks.

### 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 All @@ -23,6 +29,14 @@

## Unreleased

### Features

- Disable `ScreenshotIntegration`, `WidgetsBindingIntegration` and `SentryWidget` in multi-view apps #2366 ([#2366](https://github.com/getsentry/sentry-dart/pull/2366))

### Fixes

- Reference to `SentryWidgetsFlutterBinding` in warning message in `FramesTrackingIntegration` ([#2704](https://github.com/getsentry/sentry-dart/pull/2704))

### Deprecations

- Deprecate `autoAppStart` and `setAppStartEnd` ([#2681](https://github.com/getsentry/sentry-dart/pull/2681))
Expand All @@ -35,6 +49,9 @@

### Dependencies

- Bump Android SDK from v7.20.1 to v7.22.0 ([#2660](https://github.com/getsentry/sentry-dart/pull/2660))
- [changelog](https://github.com/getsentry/sentry-java/blob/7.x.x/CHANGELOG.md#7220)
- [diff](https://github.com/getsentry/sentry-java/compare/7.20.1...7.22.0)
- Bump Native SDK from v0.7.19 to v0.7.20 ([#2652](https://github.com/getsentry/sentry-dart/pull/2652))
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0720)
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.19...0.7.20)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore: deprecated_member_use
import 'dart:html' as html show window, Window;

import '../../../sentry.dart';
Expand Down
1 change: 1 addition & 0 deletions dart/lib/src/origin_html.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore: deprecated_member_use
import 'dart:html';

/// request origin, used for browser stacktrace
Expand Down
2 changes: 2 additions & 0 deletions dart/lib/src/platform/_html_platform.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// ignore: deprecated_member_use
import 'dart:html' as html;

import 'platform.dart';

const Platform instance = WebPlatform();
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
35 changes: 35 additions & 0 deletions flutter/example/integration_test/web_sdk_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,41 @@ void main() {
// sent in the JS layer
expect(jsEventJson, equals(dartEventJson));
});

testWidgets('includes single-view supporting integrations',
(tester) async {
SentryFlutterOptions? confOptions;

await restoreFlutterOnErrorAfter(() async {
await SentryFlutter.init((options) {
options.enableSentryJs = true;
options.dsn = fakeDsn;
options.attachScreenshot = true;

confOptions = options;
}, appRunner: () async {
await tester.pumpWidget(
SentryWidget(child: const app.MyApp()),
);
});
});
expect(
confOptions?.sdk.integrations.contains("screenshotIntegration"),
isTrue,
);
expect(
confOptions?.sdk.integrations.contains("widgetsBindingIntegration"),
isTrue,
);
expect(
find.byType(SentryScreenshotWidget),
findsOneWidget,
);
expect(
find.byType(SentryUserInteractionWidget),
findsOneWidget,
);
});
});

group('disabled', () {
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
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// ignore: deprecated_member_use
import 'dart:html' as html show window, Window;

import '../../../sentry_flutter.dart';
import 'url_filter_event_processor.dart';
// ignore: implementation_imports
import 'package:sentry/src/utils/regex_utils.dart';

import '../../../sentry_flutter.dart';
import 'url_filter_event_processor.dart';

// ignore_for_file: invalid_use_of_internal_member

UrlFilterEventProcessor urlFilterEventProcessor(SentryFlutterOptions options) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
// ignore: deprecated_member_use
import 'dart:html' as html;

import 'connectivity_provider.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class FramesTrackingIntegration implements Integration<SentryFlutterOptions> {
if (widgetsBinding == null ||
widgetsBinding is! SentryWidgetsBindingMixin) {
return options.logger(SentryLevel.warning,
'$FramesTrackingIntegration disabled: incompatible binding, SentryFlutterWidgetsBinding has not been instantiated. Please, use SentryFlutterWidgetsBinding.ensureInitialized() instead of FlutterWidgetsBinding.ensureInitialized()');
'$FramesTrackingIntegration disabled: incompatible binding, SentryWidgetsFlutterBinding has not been instantiated. Please, use SentryWidgetsFlutterBinding.ensureInitialized() instead of WidgetsFlutterBinding.ensureInitialized()');
}
_widgetsBinding = widgetsBinding;

Expand Down
22 changes: 3 additions & 19 deletions flutter/lib/src/integrations/on_error_integration.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import 'dart:ui';

import 'package:flutter/widgets.dart';
import 'package:sentry/sentry.dart';
import '../sentry_flutter_options.dart';

// ignore: implementation_imports
import 'package:sentry/src/utils/stacktrace_utils.dart';

import '../sentry_flutter_options.dart';
import '../utils/platform_dispatcher_wrapper.dart';

typedef ErrorCallback = bool Function(Object exception, StackTrace stackTrace);

/// Integration which captures `PlatformDispatcher.onError`
Expand Down Expand Up @@ -104,17 +102,3 @@ class OnErrorIntegration implements Integration<SentryFlutterOptions> {
}
}
}

/// Wrapper to make this testable. Should not become public API.
@visibleForTesting
class PlatformDispatcherWrapper {
PlatformDispatcherWrapper(this._dispatcher);

final PlatformDispatcher? _dispatcher;

ErrorCallback? get onError => _dispatcher?.onError;

set onError(ErrorCallback? callback) {
_dispatcher?.onError = callback;
}
}
8 changes: 8 additions & 0 deletions flutter/lib/src/integrations/screenshot_integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ class ScreenshotIntegration implements Integration<SentryFlutterOptions> {

@override
void call(Hub hub, SentryFlutterOptions options) {
if (options.isMultiViewApp) {
// ignore: invalid_use_of_internal_member
options.logger(
SentryLevel.debug,
'`ScreenshotIntegration` is not available in multi-view applications.',
);
return;
}
if (options.attachScreenshot) {
_options = options;
final screenshotEventProcessor = ScreenshotEventProcessor(options);
Expand Down
8 changes: 8 additions & 0 deletions flutter/lib/src/integrations/widgets_binding_integration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ class WidgetsBindingIntegration implements Integration<SentryFlutterOptions> {

@override
void call(Hub hub, SentryFlutterOptions options) {
if (options.isMultiViewApp) {
// ignore: invalid_use_of_internal_member
options.logger(
SentryLevel.debug,
'`WidgetsBindingIntegration` is not available in multi-view applications.',
);
return;
}
_options = options;
final observer = SentryWidgetsBindingObserver(
hub: hub,
Expand Down
Loading

0 comments on commit d2bc90a

Please sign in to comment.