Skip to content

Commit

Permalink
feat: Add beforeCaptureScreenshotCallback
Browse files Browse the repository at this point in the history
Add a callback to the options to decide if the SDK should capture a
screenshot or not.

Fixes GH-3137
  • Loading branch information
philipphofmann committed May 27, 2024
1 parent b189fbf commit cdbc68e
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Add start time to network request breadcrumbs (#4008)
- Add C++ exception support for `__cxa_rethrow` (#3996)
- Add beforeCaptureScreenshot callback (#4016)

### Improvements

Expand Down
3 changes: 3 additions & 0 deletions Samples/iOS-Swift/iOS-Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
options.beforeSend = { event in
return event
}
options.beforeCaptureScreenshot = { _ in
return true
}
options.debug = true

if #available(iOS 16.0, *) {
Expand Down
6 changes: 6 additions & 0 deletions Sources/Sentry/Public/SentryDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ typedef SentryBreadcrumb *_Nullable (^SentryBeforeBreadcrumbCallback)(
*/
typedef SentryEvent *_Nullable (^SentryBeforeSendEventCallback)(SentryEvent *_Nonnull event);

/**
* Block can be used to decide if the SDK should capture a screenshot or not. Return @c true if the
* SDK should capture a screenshot, return @c false if not. This callback doesn't work for crashes.
*/
typedef BOOL (^SentryBeforeCaptureScreenshotCallback)(SentryEvent *_Nonnull event);

/**
* A callback to be notified when the last program execution terminated with a crash.
*/
Expand Down
7 changes: 7 additions & 0 deletions Sources/Sentry/Public/SentryOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ NS_SWIFT_NAME(Options)
*/
@property (nullable, nonatomic, copy) SentryBeforeBreadcrumbCallback beforeBreadcrumb;

/**
* You can use this callback to decide if the SDK should capture a screenshot or not. Return @c true
* if the SDK should capture a screenshot, return @c false if not. This callback doesn't work for
* crashes.
*/
@property (nullable, nonatomic, copy) SentryBeforeCaptureScreenshotCallback beforeCaptureScreenshot;

/**
* A block called shortly after the initialization of the SDK when the last program execution
* terminated with a crash.
Expand Down
4 changes: 4 additions & 0 deletions Sources/Sentry/SentryOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ - (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options
self.beforeBreadcrumb = options[@"beforeBreadcrumb"];
}

if ([self isBlock:options[@"beforeCaptureScreenshot"]]) {
self.beforeCaptureScreenshot = options[@"beforeCaptureScreenshot"];
}

if ([self isBlock:options[@"onCrashedLastRun"]]) {
self.onCrashedLastRun = options[@"onCrashedLastRun"];
}
Expand Down
14 changes: 14 additions & 0 deletions Sources/Sentry/SentryScreenshotIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# import "SentryEvent+Private.h"
# import "SentryException.h"
# import "SentryHub+Private.h"
# import "SentryOptions.h"
# import "SentrySDK+Private.h"

# if SENTRY_HAS_METRIC_KIT
Expand All @@ -21,10 +22,19 @@
[SentryDependencyContainer.sharedInstance.screenshot saveScreenShots:reportPath];
}

@interface
SentryScreenshotIntegration ()

@property (nonatomic, strong) SentryOptions *options;

@end

@implementation SentryScreenshotIntegration

- (BOOL)installWithOptions:(nonnull SentryOptions *)options
{
self.options = options;

if (![super installWithOptions:options]) {
return NO;
}
Expand Down Expand Up @@ -70,6 +80,10 @@ - (void)uninstall
return attachments;
}

if (self.options.beforeCaptureScreenshot && !self.options.beforeCaptureScreenshot(event)) {
return attachments;
}

NSArray *screenshot =
[SentryDependencyContainer.sharedInstance.screenshot appScreenshotsFromMainThread];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,26 @@ class SentryScreenshotIntegrationTests: XCTestCase {
}
#endif // os(iOS) || targetEnvironment(macCatalyst)

func test_NoScreenShot_WhenDiscardedInCallback() {
let sut = fixture.getSut()

let expectation = expectation(description: "BeforeCaptureScreenshot must be called.")

let options = Options()
options.beforeCaptureScreenshot = { _ in
expectation.fulfill()
return false
}

sut.install(with: options)

let newAttachmentList = sut.processAttachments([], for: Event(error: NSError(domain: "", code: -1)))

wait(for: [expectation], timeout: 1.0)

XCTAssertEqual(newAttachmentList?.count, 0)
}

func test_noScreenshot_keepAttachment() {
let sut = fixture.getSut()
let event = Event()
Expand Down
21 changes: 21 additions & 0 deletions Tests/SentryTests/SentryOptionsTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,27 @@ - (void)testDefaultBeforeBreadcrumb
XCTAssertNil(options.beforeBreadcrumb);
}

- (void)testBeforeCaptureScreenshot
{
SentryBeforeCaptureScreenshotCallback callback = ^(SentryEvent *event) {
if (event.level == kSentryLevelFatal) {
return NO;

Check warning on line 317 in Tests/SentryTests/SentryOptionsTest.m

View check run for this annotation

Codecov / codecov/patch

Tests/SentryTests/SentryOptionsTest.m#L317

Added line #L317 was not covered by tests
}

return YES;
};
SentryOptions *options = [self getValidOptions:@{ @"beforeCaptureScreenshot" : callback }];

XCTAssertEqual(callback, options.beforeCaptureScreenshot);
}

- (void)testDefaultBeforeCaptureScreenshot
{
SentryOptions *options = [self getValidOptions:@{}];

XCTAssertNil(options.beforeCaptureScreenshot);
}

- (void)testTracePropagationTargets
{
SentryOptions *options =
Expand Down

0 comments on commit cdbc68e

Please sign in to comment.