-
-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: iOS replay support #2209
Merged
+593
−182
Merged
feat: iOS replay support #2209
Changes from 119 commits
Commits
Show all changes
120 commits
Select commit
Hold shift + click to select a range
294317b
minor gradle fixes
vaind 861ebab
tmp: local sentry-java build
vaind 2f55619
tmp: use relative path to sentry-java
vaind 209ca41
tmp: local java build patches
vaind a282fad
replay options
vaind 7d8d4e8
replay recorder
vaind c887e6d
Merge branch 'main' into feat/replay
vaind 3444961
wip: JNI native bindings
vaind ca03c95
use compatible jnigen
vaind 0b06dd5
add missing gradlew to flutter/android
vaind 314665d
Merge branch 'feat/jni-ffi' into feat/replay
vaind 8bf52d8
replay recorder JNI binding code
vaind a4e056a
replay recorder binding jni code
vaind 1cde833
jni 0.6
vaind 010f575
wip: android jni replay
vaind 4c4f132
replay binding
vaind 87d18e7
glue code for jni
vaind 2eaaa28
Merge branch 'main' into feat/replay
vaind afa9f50
chore: update to cocoa 8.24.1-alpha.0
vaind 3df2523
wip: cocoa integration
vaind 179b5d4
wip: ios replay
vaind 9284db8
Merge branch 'main' into feat/replay
vaind 6432b98
cleanup
vaind 25fd690
formatting
vaind 658a132
android fixes
vaind fb8bbb4
move native setup to the native sdk integration
vaind 7c8fd42
cleanup & improvements
vaind 0570f35
improve widget filter and implement redact options
vaind 5c08b21
fix image scaling
vaind c00788a
Merge branch 'main' into feat/replay
vaind 0c55dc6
ktlint format
vaind f136795
ci fixes
vaind 2aa129c
fix tests
vaind 698276d
add jnigen scripts
vaind c6c3a17
use android 7.9.0 alpha.1
vaind cf8ed52
move native init & close to SentryNative
vaind 55c7056
cleanup
vaind ff2a8ed
add macOS integration link
vaind 46a96b0
Merge branch 'main' into feat/replay
vaind c3b60aa
rollback cocoa changes
vaind 3f6d05e
remove jni/jnigen
vaind af22a59
wip: methodchannel based android recorder
vaind 6bf1f00
callback
vaind 9dc14aa
linter issues
vaind 9daf297
Merge branch 'main' into feat/android-replay
vaind 3639f00
minor fixes
vaind 14ba742
more fixes
vaind 585386e
linter issues
vaind ee1dbd6
cleanup
vaind 266a85a
improve logging
vaind 509c15f
move replay to experimental, same as in other SDKs
vaind 960f2da
improve tree shaking
vaind b5c935f
Merge branch 'main' into feat/android-replay
vaind 95e3a34
test: scheduler
vaind aa28200
support browser test
vaind 16f3677
fix compat with old flutter
vaind 86db5c4
cleanup
vaind 942044a
rename recorder_widget_filter.dart
vaind 9efae7b
fixup scheduler test
vaind 35ed86b
improve test coverage
vaind 63af017
pr cleanup
vaind 12f5774
test: widget filter
vaind 50a13f6
cleanup
vaind 725fd02
test widget filter visibility
vaind 4bda0ab
cleanup
vaind afb65f6
always add screenshot widget
vaind f6b9266
recorder test
vaind 5dc1255
cleanup
vaind 225c0c0
limit recorder test to vm
vaind 46527a3
wip: integration test
vaind 0bc8fff
cleanup
vaind 571dfbc
Merge branch 'main' into feat/android-replay
vaind 81f4689
ktlint format
vaind 0f6764b
detekt suppression
vaind d35f630
ktlint format
vaind fee9580
improve scheduler stop behavior
vaind 8be8d20
wip: error replay mapping
vaind c7b166d
Merge branch 'main' into feat/android-replay
vaind f3057cd
suppress detekt TooGenericExceptionThrown
vaind 943acea
Update flutter/lib/src/replay/recorder.dart
vaind 0d82f13
Update flutter/lib/src/native/java/sentry_native_java.dart
vaind 49d4239
improve comments
vaind 8ef5d15
Merge branch 'main' into feat/android-replay
vaind a93da0b
Merge branch 'main' into feat/android-replay
vaind 114ed86
feat: associate dart errors with replays (#2070)
vaind 5014d1c
Merge branch 'main' into feat/android-replay
vaind 5baab7c
Merge branch 'main' into feat/android-replay
vaind c26a8a2
chote: remove path dependency
vaind 09392a8
wip: ios replay
vaind 6f9e741
fix result callback
vaind 35cba3d
iOS related refactorings
vaind f88ce8b
logs
vaind e4c0654
Merge branch 'main' into feat/android-replay
vaind 8919fff
Merge branch 'main' into feat/android-replay
vaind 087d894
Merge branch 'feat/android-replay' into feat/ios-replay
vaind 3f12988
fix tests
vaind 1706c68
Merge branch 'main' into feat/android-replay
vaind 320c245
Merge branch 'feat/android-replay' into feat/ios-replay
vaind cc0194a
call captureReplay on iOS & set
vaind f1c94a7
ios replay breadcrumbs
vaind 5dc8bd6
feat: replay breadcrumbs (android) (#2163)
vaind 26d7b9c
Merge branch 'main' into feat/android-replay
vaind 8cd2d63
test: native replay integration binding (#2189)
vaind 4883e14
Merge branch 'main' into feat/android-replay
vaind 8bcde3d
Merge branch 'main' into feat/android-replay
vaind f1157fc
chore: update changelog
vaind 93293f7
fix publishing
vaind 87971db
release: 8.6.0-alpha.2
getsentry-bot 3bf3cca
Merge branch 'release/8.6.0-alpha.2' into feat/android-replay
fb0dc4f
Merge branch 'feat/android-replay' into feat/ios-replay
vaind bf85993
Merge branch 'feat/replay' into feat/ios-replay
vaind 51f3181
cleanup
vaind f54faee
Merge branch 'feat/replay' into feat/ios-replay
vaind 17f5d9b
fix macos compilation
vaind 7eaafe1
test: iOS support
vaind 97b0b7b
linter issues
vaind e610e26
linter issues
vaind d496e49
Merge branch 'feat/replay' into feat/ios-replay
vaind cfefe5b
chore: update changelog
vaind 87ef33a
Update flutter/lib/src/native/cocoa/sentry_native_cocoa.dart
vaind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
flutter/ios/Classes/SentryFlutterReplayBreadcrumbConverter.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
@import Sentry; | ||
|
||
#if SENTRY_TARGET_REPLAY_SUPPORTED | ||
@class SentryRRWebEvent; | ||
|
||
@interface SentryFlutterReplayBreadcrumbConverter | ||
: NSObject <SentryReplayBreadcrumbConverter> | ||
|
||
- (instancetype _Nonnull)init; | ||
|
||
- (id<SentryRRWebEvent> _Nullable)convertFrom: | ||
(SentryBreadcrumb *_Nonnull)breadcrumb; | ||
|
||
@end | ||
#endif |
117 changes: 117 additions & 0 deletions
117
flutter/ios/Classes/SentryFlutterReplayBreadcrumbConverter.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#import "SentryFlutterReplayBreadcrumbConverter.h" | ||
|
||
@import Sentry; | ||
|
||
#if SENTRY_TARGET_REPLAY_SUPPORTED | ||
|
||
@implementation SentryFlutterReplayBreadcrumbConverter { | ||
SentrySRDefaultBreadcrumbConverter *defaultConverter; | ||
} | ||
|
||
- (instancetype _Nonnull)init { | ||
if (self = [super init]) { | ||
self->defaultConverter = | ||
[SentrySessionReplayIntegration createDefaultBreadcrumbConverter]; | ||
} | ||
return self; | ||
} | ||
|
||
- (id<SentryRRWebEvent> _Nullable)convertFrom: | ||
(SentryBreadcrumb *_Nonnull)breadcrumb { | ||
assert(breadcrumb.timestamp != nil); | ||
|
||
if (breadcrumb.category == nil | ||
// Do not add Sentry Event breadcrumbs to replay | ||
|| [breadcrumb.category isEqualToString:@"sentry.event"] || | ||
[breadcrumb.category isEqualToString:@"sentry.transaction"]) { | ||
return nil; | ||
} | ||
|
||
if ([breadcrumb.category isEqualToString:@"http"]) { | ||
return [self convertNetwork:breadcrumb]; | ||
} | ||
|
||
if ([breadcrumb.category isEqualToString:@"navigation"]) { | ||
return [self convertFrom:breadcrumb withCategory:nil andMessage:nil]; | ||
} | ||
|
||
if ([breadcrumb.category isEqualToString:@"ui.click"]) { | ||
return [self convertFrom:breadcrumb | ||
withCategory:@"ui.tap" | ||
andMessage:breadcrumb.data[@"path"]]; | ||
} | ||
|
||
SentryRRWebEvent *nativeBreadcrumb = | ||
[self->defaultConverter convertFrom:breadcrumb]; | ||
|
||
// ignore native navigation breadcrumbs | ||
if (nativeBreadcrumb && nativeBreadcrumb.data && | ||
nativeBreadcrumb.data[@"payload"] && | ||
nativeBreadcrumb.data[@"payload"][@"category"] && | ||
[nativeBreadcrumb.data[@"payload"][@"category"] | ||
isEqualToString:@"navigation"]) { | ||
return nil; | ||
} | ||
|
||
return nativeBreadcrumb; | ||
} | ||
|
||
- (id<SentryRRWebEvent> _Nullable)convertFrom: | ||
(SentryBreadcrumb *_Nonnull)breadcrumb | ||
withCategory:(NSString *)category | ||
andMessage:(NSString *)message { | ||
return [SentrySessionReplayIntegration | ||
createBreadcrumbwithTimestamp:breadcrumb.timestamp | ||
category:category ?: breadcrumb.category | ||
message:message ?: breadcrumb.message | ||
level:breadcrumb.level | ||
data:breadcrumb.data]; | ||
} | ||
|
||
- (id<SentryRRWebEvent> _Nullable)convertNetwork: | ||
(SentryBreadcrumb *_Nonnull)breadcrumb { | ||
NSNumber *startTimestamp = | ||
[breadcrumb.data[@"start_timestamp"] isKindOfClass:[NSNumber class]] | ||
? breadcrumb.data[@"start_timestamp"] | ||
: nil; | ||
NSNumber *endTimestamp = | ||
[breadcrumb.data[@"end_timestamp"] isKindOfClass:[NSNumber class]] | ||
? breadcrumb.data[@"end_timestamp"] | ||
: nil; | ||
NSString *url = [breadcrumb.data[@"url"] isKindOfClass:[NSString class]] | ||
? breadcrumb.data[@"url"] | ||
: nil; | ||
|
||
if (startTimestamp == nil || endTimestamp == nil || url == nil) { | ||
return nil; | ||
} | ||
|
||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; | ||
if ([breadcrumb.data[@"method"] isKindOfClass:[NSString class]]) { | ||
data[@"method"] = breadcrumb.data[@"method"]; | ||
} | ||
if ([breadcrumb.data[@"status_code"] isKindOfClass:[NSNumber class]]) { | ||
data[@"statusCode"] = breadcrumb.data[@"status_code"]; | ||
} | ||
if ([breadcrumb.data[@"request_body_size"] isKindOfClass:[NSNumber class]]) { | ||
data[@"requestBodySize"] = breadcrumb.data[@"request_body_size"]; | ||
} | ||
if ([breadcrumb.data[@"response_body_size"] isKindOfClass:[NSNumber class]]) { | ||
data[@"responseBodySize"] = breadcrumb.data[@"response_body_size"]; | ||
} | ||
|
||
return [SentrySessionReplayIntegration | ||
createNetworkBreadcrumbWithTimestamp:[self dateFrom:startTimestamp] | ||
endTimestamp:[self dateFrom:endTimestamp] | ||
operation:@"resource.http" | ||
description:url | ||
data:data]; | ||
} | ||
|
||
- (NSDate *_Nonnull)dateFrom:(NSNumber *_Nonnull)timestamp { | ||
return [NSDate dateWithTimeIntervalSince1970:(timestamp.doubleValue / 1000)]; | ||
} | ||
|
||
@end | ||
|
||
#endif |
12 changes: 12 additions & 0 deletions
12
flutter/ios/Classes/SentryFlutterReplayScreenshotProvider.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
@import Sentry; | ||
|
||
#if SENTRY_TARGET_REPLAY_SUPPORTED | ||
@class SentryRRWebEvent; | ||
|
||
@interface SentryFlutterReplayScreenshotProvider | ||
: NSObject <SentryViewScreenshotProvider> | ||
|
||
- (instancetype)initWithChannel:(id)FlutterMethodChannel; | ||
|
||
@end | ||
#endif |
46 changes: 46 additions & 0 deletions
46
flutter/ios/Classes/SentryFlutterReplayScreenshotProvider.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
@import Sentry; | ||
|
||
#if SENTRY_TARGET_REPLAY_SUPPORTED | ||
#import "SentryFlutterReplayScreenshotProvider.h" | ||
#import <Flutter/Flutter.h> | ||
|
||
@implementation SentryFlutterReplayScreenshotProvider { | ||
FlutterMethodChannel *channel; | ||
} | ||
|
||
- (instancetype _Nonnull)initWithChannel: | ||
(FlutterMethodChannel *_Nonnull)channel { | ||
if (self = [super init]) { | ||
self->channel = channel; | ||
} | ||
return self; | ||
} | ||
|
||
buenaflor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- (void)imageWithView:(UIView *_Nonnull)view | ||
options:(id<SentryRedactOptions> _Nonnull)options | ||
onComplete:(void (^_Nonnull)(UIImage *_Nonnull))onComplete { | ||
[self->channel | ||
invokeMethod:@"captureReplayScreenshot" | ||
arguments:@{@"replayId" : [PrivateSentrySDKOnly getReplayId]} | ||
result:^(id value) { | ||
if (value == nil) { | ||
NSLog(@"SentryFlutterReplayScreenshotProvider received null " | ||
@"result. " | ||
@"Cannot capture a replay screenshot."); | ||
} else if ([value | ||
isKindOfClass:[FlutterStandardTypedData class]]) { | ||
FlutterStandardTypedData *typedData = | ||
(FlutterStandardTypedData *)value; | ||
UIImage *image = [UIImage imageWithData:typedData.data]; | ||
onComplete(image); | ||
} else { | ||
NSLog(@"SentryFlutterReplayScreenshotProvider received an " | ||
@"unexpected result. " | ||
@"Cannot capture a replay screenshot."); | ||
} | ||
}]; | ||
} | ||
|
||
@end | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|| os(tvOS)
we also support replay for tvos?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no (it's not even supported by Flutter officially AFAIK), the condition is exactly the same as in cocoa core code