Skip to content

Commit b3d4f09

Browse files
committed
Merge branch 'main' into feat/spm
# Conflicts: # flutter/ios/sentry_flutter.podspec
2 parents cf145b9 + dd25e43 commit b3d4f09

File tree

13 files changed

+321
-207
lines changed

13 files changed

+321
-207
lines changed

CHANGELOG.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,25 @@
22

33
## Unreleased
44

5-
### Deprecate
5+
### Deprecations
66

77
- Manual TTID ([#2477](https://github.com/getsentry/sentry-dart/pull/2477))
88

9-
### Improvements
9+
### Fixes
1010

11-
- Check `SentryTracer` type in TTFD tracker ([#2508](https://github.com/getsentry/sentry-dart/pull/2508))
11+
- Missing replay gestures on Android ([#2515](https://github.com/getsentry/sentry-dart/pull/2515))
1212

1313
### Enhancements
1414

15+
- Check `SentryTracer` type in TTFD tracker ([#2508](https://github.com/getsentry/sentry-dart/pull/2508))
1516
- Warning (in a debug build) if a potentially sensitive widget is not masked or unmasked explicitly ([#2375](https://github.com/getsentry/sentry-dart/pull/2375))
1617
- SPM Support ([#2280](https://github.com/getsentry/sentry-dart/pull/2280))
1718

1819
### Dependencies
1920

20-
- Bump Native SDK from v0.7.15 to v0.7.16 ([#2465](https://github.com/getsentry/sentry-dart/pull/2465))
21-
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0716)
22-
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.15...0.7.16)
21+
- Bump Native SDK from v0.7.15 to v0.7.17 ([#2465](https://github.com/getsentry/sentry-dart/pull/2465), [#2516](https://github.com/getsentry/sentry-dart/pull/2516))
22+
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0717)
23+
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.15...0.7.17)
2324
- Bump Android SDK from v7.18.1 to v7.19.0 ([#2488](https://github.com/getsentry/sentry-dart/pull/2488))
2425
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7190)
2526
- [diff](https://github.com/getsentry/sentry-java/compare/7.18.1...7.19.0)

flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ package io.sentry.flutter
33
import android.app.Activity
44
import android.content.Context
55
import android.content.res.Configuration
6+
import android.graphics.Point
7+
import android.graphics.Rect
68
import android.os.Build
9+
import android.os.Build.VERSION
10+
import android.os.Build.VERSION_CODES
711
import android.os.Looper
812
import android.util.Log
13+
import android.view.WindowManager
914
import io.flutter.embedding.engine.plugins.FlutterPlugin
1015
import io.flutter.embedding.engine.plugins.activity.ActivityAware
1116
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
@@ -638,12 +643,23 @@ class SentryFlutterPlugin :
638643
height = newHeight
639644
}
640645

646+
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
647+
val screenBounds =
648+
if (VERSION.SDK_INT >= VERSION_CODES.R) {
649+
wm.currentWindowMetrics.bounds
650+
} else {
651+
val screenBounds = Point()
652+
@Suppress("DEPRECATION")
653+
wm.defaultDisplay.getRealSize(screenBounds)
654+
Rect(0, 0, screenBounds.x, screenBounds.y)
655+
}
656+
641657
replayConfig =
642658
ScreenshotRecorderConfig(
643659
recordingWidth = width.roundToInt(),
644660
recordingHeight = height.roundToInt(),
645-
scaleFactorX = 1.0f,
646-
scaleFactorY = 1.0f,
661+
scaleFactorX = width.toFloat() / screenBounds.width().toFloat(),
662+
scaleFactorY = height.toFloat() / screenBounds.height().toFloat(),
647663
frameRate = call.argument("frameRate") as? Int ?: 0,
648664
bitRate = call.argument("bitRate") as? Int ?: 0,
649665
)

flutter/lib/src/event_processor/screenshot_event_processor.dart

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class ScreenshotEventProcessor implements EventProcessor {
2525
height: targetResolution,
2626
),
2727
_options,
28-
isReplayRecorder: false,
2928
);
3029
_debouncer = Debouncer(
3130
// ignore: invalid_use_of_internal_member
@@ -126,15 +125,8 @@ class ScreenshotEventProcessor implements EventProcessor {
126125
}
127126

128127
@internal
129-
Future<Uint8List?> createScreenshot() async {
130-
Uint8List? screenshotData;
131-
132-
await _recorder.capture((Image image) async {
133-
screenshotData = await _convertImageToUint8List(image);
134-
});
135-
136-
return screenshotData;
137-
}
128+
Future<Uint8List?> createScreenshot() =>
129+
_recorder.capture(_convertImageToUint8List);
138130

139131
Future<Uint8List?> _convertImageToUint8List(Image image) async {
140132
final byteData = await image.toByteData(format: ImageByteFormat.png);

flutter/lib/src/native/cocoa/binding.dart

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30136,112 +30136,91 @@ class SentryCocoa {
3013630136
ffi.Pointer<ObjCObject> Function(
3013730137
ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
3013830138

30139-
late final _sel_setEmpty_1 = _registerName1("setEmpty:");
30140-
void _objc_msgSend_1063(
30141-
ffi.Pointer<ObjCObject> obj,
30142-
ffi.Pointer<ObjCSel> sel,
30143-
ffi.Pointer<ObjCObject> value,
30144-
) {
30145-
return __objc_msgSend_1063(
30146-
obj,
30147-
sel,
30148-
value,
30149-
);
30150-
}
30151-
30152-
late final __objc_msgSend_1063Ptr = _lookup<
30153-
ffi.NativeFunction<
30154-
ffi.Void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
30155-
ffi.Pointer<ObjCObject>)>>('objc_msgSend');
30156-
late final __objc_msgSend_1063 = __objc_msgSend_1063Ptr.asFunction<
30157-
void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
30158-
ffi.Pointer<ObjCObject>)>();
30159-
3016030139
late final _sel_sentryIdString1 = _registerName1("sentryIdString");
3016130140
late final _class_NSUUID1 = _getClass1("NSUUID");
3016230141
late final _sel_UUID1 = _registerName1("UUID");
3016330142
late final _sel_initWithUUIDString_1 = _registerName1("initWithUUIDString:");
3016430143
late final _sel_initWithUUIDBytes_1 = _registerName1("initWithUUIDBytes:");
30165-
instancetype _objc_msgSend_1064(
30144+
instancetype _objc_msgSend_1063(
3016630145
ffi.Pointer<ObjCObject> obj,
3016730146
ffi.Pointer<ObjCSel> sel,
3016830147
ffi.Pointer<ffi.UnsignedChar> bytes,
3016930148
) {
30170-
return __objc_msgSend_1064(
30149+
return __objc_msgSend_1063(
3017130150
obj,
3017230151
sel,
3017330152
bytes,
3017430153
);
3017530154
}
3017630155

30177-
late final __objc_msgSend_1064Ptr = _lookup<
30156+
late final __objc_msgSend_1063Ptr = _lookup<
3017830157
ffi.NativeFunction<
3017930158
instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3018030159
ffi.Pointer<ffi.UnsignedChar>)>>('objc_msgSend');
30181-
late final __objc_msgSend_1064 = __objc_msgSend_1064Ptr.asFunction<
30160+
late final __objc_msgSend_1063 = __objc_msgSend_1063Ptr.asFunction<
3018230161
instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3018330162
ffi.Pointer<ffi.UnsignedChar>)>();
3018430163

3018530164
late final _sel_getUUIDBytes_1 = _registerName1("getUUIDBytes:");
30186-
void _objc_msgSend_1065(
30165+
void _objc_msgSend_1064(
3018730166
ffi.Pointer<ObjCObject> obj,
3018830167
ffi.Pointer<ObjCSel> sel,
3018930168
ffi.Pointer<ffi.UnsignedChar> uuid,
3019030169
) {
30191-
return __objc_msgSend_1065(
30170+
return __objc_msgSend_1064(
3019230171
obj,
3019330172
sel,
3019430173
uuid,
3019530174
);
3019630175
}
3019730176

30198-
late final __objc_msgSend_1065Ptr = _lookup<
30177+
late final __objc_msgSend_1064Ptr = _lookup<
3019930178
ffi.NativeFunction<
3020030179
ffi.Void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3020130180
ffi.Pointer<ffi.UnsignedChar>)>>('objc_msgSend');
30202-
late final __objc_msgSend_1065 = __objc_msgSend_1065Ptr.asFunction<
30181+
late final __objc_msgSend_1064 = __objc_msgSend_1064Ptr.asFunction<
3020330182
void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3020430183
ffi.Pointer<ffi.UnsignedChar>)>();
3020530184

30206-
int _objc_msgSend_1066(
30185+
int _objc_msgSend_1065(
3020730186
ffi.Pointer<ObjCObject> obj,
3020830187
ffi.Pointer<ObjCSel> sel,
3020930188
ffi.Pointer<ObjCObject> otherUUID,
3021030189
) {
30211-
return __objc_msgSend_1066(
30190+
return __objc_msgSend_1065(
3021230191
obj,
3021330192
sel,
3021430193
otherUUID,
3021530194
);
3021630195
}
3021730196

30218-
late final __objc_msgSend_1066Ptr = _lookup<
30197+
late final __objc_msgSend_1065Ptr = _lookup<
3021930198
ffi.NativeFunction<
3022030199
ffi.Int32 Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3022130200
ffi.Pointer<ObjCObject>)>>('objc_msgSend');
30222-
late final __objc_msgSend_1066 = __objc_msgSend_1066Ptr.asFunction<
30201+
late final __objc_msgSend_1065 = __objc_msgSend_1065Ptr.asFunction<
3022330202
int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3022430203
ffi.Pointer<ObjCObject>)>();
3022530204

3022630205
late final _sel_UUIDString1 = _registerName1("UUIDString");
3022730206
late final _sel_initWithUuid_1 = _registerName1("initWithUuid:");
30228-
instancetype _objc_msgSend_1067(
30207+
instancetype _objc_msgSend_1066(
3022930208
ffi.Pointer<ObjCObject> obj,
3023030209
ffi.Pointer<ObjCSel> sel,
3023130210
ffi.Pointer<ObjCObject> uuid,
3023230211
) {
30233-
return __objc_msgSend_1067(
30212+
return __objc_msgSend_1066(
3023430213
obj,
3023530214
sel,
3023630215
uuid,
3023730216
);
3023830217
}
3023930218

30240-
late final __objc_msgSend_1067Ptr = _lookup<
30219+
late final __objc_msgSend_1066Ptr = _lookup<
3024130220
ffi.NativeFunction<
3024230221
instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3024330222
ffi.Pointer<ObjCObject>)>>('objc_msgSend');
30244-
late final __objc_msgSend_1067 = __objc_msgSend_1067Ptr.asFunction<
30223+
late final __objc_msgSend_1066 = __objc_msgSend_1066Ptr.asFunction<
3024530224
instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
3024630225
ffi.Pointer<ObjCObject>)>();
3024730226

@@ -71230,11 +71209,6 @@ class SentryId1 extends NSObject {
7123071209
: SentryId1._(_ret, _lib, retain: true, release: true);
7123171210
}
7123271211

71233-
static void setEmpty(SentryCocoa _lib, SentryId1? value) {
71234-
return _lib._objc_msgSend_1063(_lib._class_SentryId11, _lib._sel_setEmpty_1,
71235-
value?._id ?? ffi.nullptr);
71236-
}
71237-
7123871212
/// Returns a 32 lowercase character hexadecimal string description of the @c SentryId, such as
7123971213
/// “12c2d058d58442709aa2eca08bf20986”.
7124071214
NSString? get sentryIdString {
@@ -71253,7 +71227,7 @@ class SentryId1 extends NSObject {
7125371227

7125471228
/// Creates a SentryId with the given UUID.
7125571229
SentryId1 initWithUuid_(NSUUID? uuid) {
71256-
final _ret = _lib._objc_msgSend_1067(
71230+
final _ret = _lib._objc_msgSend_1066(
7125771231
_id, _lib._sel_initWithUuid_1, uuid?._id ?? ffi.nullptr);
7125871232
return SentryId1._(_ret, _lib, retain: true, release: true);
7125971233
}
@@ -71408,16 +71382,16 @@ class NSUUID extends NSObject {
7140871382

7140971383
NSUUID initWithUUIDBytes_(ffi.Pointer<ffi.UnsignedChar> bytes) {
7141071384
final _ret =
71411-
_lib._objc_msgSend_1064(_id, _lib._sel_initWithUUIDBytes_1, bytes);
71385+
_lib._objc_msgSend_1063(_id, _lib._sel_initWithUUIDBytes_1, bytes);
7141271386
return NSUUID._(_ret, _lib, retain: true, release: true);
7141371387
}
7141471388

7141571389
void getUUIDBytes_(ffi.Pointer<ffi.UnsignedChar> uuid) {
71416-
_lib._objc_msgSend_1065(_id, _lib._sel_getUUIDBytes_1, uuid);
71390+
_lib._objc_msgSend_1064(_id, _lib._sel_getUUIDBytes_1, uuid);
7141771391
}
7141871392

7141971393
int compare_(NSUUID? otherUUID) {
71420-
return _lib._objc_msgSend_1066(
71394+
return _lib._objc_msgSend_1065(
7142171395
_id, _lib._sel_compare_1, otherUUID?._id ?? ffi.nullptr);
7142271396
}
7142371397

flutter/lib/src/native/cocoa/sentry_native_cocoa.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import 'dart:async';
22
import 'dart:ffi';
3-
import 'dart:typed_data';
43
import 'dart:ui';
54

65
import 'package:meta/meta.dart';
76

87
import '../../../sentry_flutter.dart';
98
import '../../replay/replay_config.dart';
9+
import '../../replay/replay_recorder.dart';
1010
import '../../screenshot/recorder.dart';
1111
import '../../screenshot/recorder_config.dart';
1212
import '../sentry_native_channel.dart';
@@ -32,7 +32,8 @@ class SentryNativeCocoa extends SentryNativeChannel {
3232
switch (call.method) {
3333
case 'captureReplayScreenshot':
3434
_replayRecorder ??=
35-
ScreenshotRecorder(ScreenshotRecorderConfig(), options);
35+
ReplayScreenshotRecorder(ScreenshotRecorderConfig(), options);
36+
3637
final replayId = call.arguments['replayId'] == null
3738
? null
3839
: SentryId.fromId(call.arguments['replayId'] as String);
@@ -44,8 +45,7 @@ class SentryNativeCocoa extends SentryNativeChannel {
4445
});
4546
}
4647

47-
Uint8List? imageBytes;
48-
await _replayRecorder?.capture((image) async {
48+
return _replayRecorder?.capture((image) async {
4949
final imageData =
5050
await image.toByteData(format: ImageByteFormat.png);
5151
if (imageData != null) {
@@ -54,13 +54,12 @@ class SentryNativeCocoa extends SentryNativeChannel {
5454
'Replay: captured screenshot ('
5555
'${image.width}x${image.height} pixels, '
5656
'${imageData.lengthInBytes} bytes)');
57-
imageBytes = imageData.buffer.asUint8List();
57+
return imageData.buffer.asUint8List();
5858
} else {
5959
options.logger(SentryLevel.warning,
6060
'Replay: failed to convert screenshot to PNG');
6161
}
6262
});
63-
return imageBytes;
6463
default:
6564
throw UnimplementedError('Method ${call.method} not implemented');
6665
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'dart:async';
2+
import 'dart:developer';
3+
4+
import 'package:flutter/scheduler.dart';
5+
import 'package:meta/meta.dart';
6+
7+
import '../screenshot/recorder.dart';
8+
9+
var _instanceCounter = 0;
10+
11+
@internal
12+
class ReplayScreenshotRecorder extends ScreenshotRecorder {
13+
ReplayScreenshotRecorder(super.config, super.options)
14+
: super(
15+
privacyOptions: options.experimental.privacyForReplay,
16+
logName: 'ReplayRecorder #${++_instanceCounter}');
17+
18+
@override
19+
@protected
20+
Future<void> executeTask(void Function() task, Flow flow) {
21+
// Schedule the task to run between frames, when the app is idle.
22+
return options.bindingUtils.instance
23+
?.scheduleTask<void>(task, Priority.idle, flow: flow) ??
24+
Future.sync(task);
25+
}
26+
}

flutter/lib/src/replay/scheduled_recorder.dart

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dart:ui';
55
import 'package:meta/meta.dart';
66

77
import '../../sentry_flutter.dart';
8-
import '../screenshot/recorder.dart';
8+
import 'replay_recorder.dart';
99
import 'scheduled_recorder_config.dart';
1010
import 'scheduler.dart';
1111

@@ -14,7 +14,7 @@ typedef ScheduledScreenshotRecorderCallback = Future<void> Function(
1414
ScreenshotPng screenshot, bool isNewlyCaptured);
1515

1616
@internal
17-
class ScheduledScreenshotRecorder extends ScreenshotRecorder {
17+
class ScheduledScreenshotRecorder extends ReplayScreenshotRecorder {
1818
late final Scheduler _scheduler;
1919
late final ScheduledScreenshotRecorderCallback _callback;
2020
var _status = _Status.running;
@@ -28,8 +28,8 @@ class ScheduledScreenshotRecorder extends ScreenshotRecorder {
2828

2929
ScheduledScreenshotRecorder(
3030
ScheduledScreenshotRecorderConfig config, SentryFlutterOptions options,
31-
[ScheduledScreenshotRecorderCallback? callback, String? logName])
32-
: super(config, options, logName: logName) {
31+
[ScheduledScreenshotRecorderCallback? callback])
32+
: super(config, options) {
3333
assert(config.frameRate > 0);
3434
_frameDuration = Duration(milliseconds: 1000 ~/ config.frameRate);
3535
assert(_frameDuration.inMicroseconds > 0);
@@ -93,8 +93,7 @@ class ScheduledScreenshotRecorder extends ScreenshotRecorder {
9393
}
9494
}
9595

96-
Future<void> _capture(Duration sinceSchedulerEpoch) async =>
97-
capture(_onImageCaptured);
96+
void _capture(Duration sinceSchedulerEpoch) => capture(_onImageCaptured);
9897

9998
Future<void> _onImageCaptured(Image image) async {
10099
if (_status == _Status.running) {
@@ -169,13 +168,13 @@ class _IdleFrameFiller {
169168
await scheduled;
170169
}
171170

172-
void pause() async {
171+
void pause() {
173172
if (_status == _Status.running) {
174173
_status = _Status.paused;
175174
}
176175
}
177176

178-
void resume() async {
177+
void resume() {
179178
if (_status == _Status.paused) {
180179
_status = _Status.running;
181180
}

0 commit comments

Comments
 (0)