From 627757d9ab65fbe97048db4d3fbe224c53f2a71a Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Thu, 26 Sep 2024 15:29:34 +0200 Subject: [PATCH 01/15] ref: redact renamed to mask --- .../iOS-ObjectiveC/AppDelegate.m | 4 ++-- Samples/iOS-Swift/iOS-Swift/AppDelegate.swift | 2 +- .../iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift | 4 ++-- Sources/Sentry/Public/SentryReplayApi.h | 9 ++++----- Sources/Sentry/SentryReplayApi.m | 8 ++++---- Sources/SentrySwiftUI/SentryReplayView.swift | 2 +- .../Swift/Extensions/UIViewExtensions.swift | 8 ++++---- .../SessionReplay/SentryReplayOptions.swift | 20 +++++++++---------- .../Swift/Protocol/SentryRedactOptions.swift | 8 ++++---- Sources/Swift/Tools/UIRedactBuilder.swift | 20 +++++++++---------- .../SentrySessionReplayIntegrationTests.swift | 4 ++-- Tests/SentryTests/UIRedactBuilderTests.swift | 16 +++++++-------- 12 files changed, 52 insertions(+), 53 deletions(-) diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m index a46b3a19b6..1b1ea1dac5 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m @@ -29,8 +29,8 @@ - (BOOL)application:(UIApplication *)application options.failedRequestStatusCodes = @[ httpStatusCodeRange ]; options.experimental.sessionReplay.quality = SentryReplayQualityMedium; - options.experimental.sessionReplay.redactAllText = true; - options.experimental.sessionReplay.redactAllImages = true; + options.experimental.sessionReplay.maskAllText = true; + options.experimental.sessionReplay.maskAllImages = true; options.experimental.sessionReplay.sessionSampleRate = 0; options.experimental.sessionReplay.onErrorSampleRate = 1; diff --git a/Samples/iOS-Swift/iOS-Swift/AppDelegate.swift b/Samples/iOS-Swift/iOS-Swift/AppDelegate.swift index 8345293395..ff01f04398 100644 --- a/Samples/iOS-Swift/iOS-Swift/AppDelegate.swift +++ b/Samples/iOS-Swift/iOS-Swift/AppDelegate.swift @@ -44,7 +44,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { options.debug = true if #available(iOS 16.0, *), !args.contains("--disable-session-replay") { - options.experimental.sessionReplay = SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1, redactAllText: true, redactAllImages: true) + options.experimental.sessionReplay = SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1, maskAllText: true, maskAllImages: true) options.experimental.sessionReplay.quality = .high } diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift index 502e719f66..5a490cd286 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift @@ -11,8 +11,8 @@ struct SwiftUIApp: App { options.tracesSampleRate = 1.0 options.profilesSampleRate = 1.0 options.experimental.sessionReplay.sessionSampleRate = 1.0 - options.experimental.sessionReplay.redactAllImages = false - options.experimental.sessionReplay.redactAllText = false + options.experimental.sessionReplay.maskAllImages = false + options.experimental.sessionReplay.maskAllText = false options.initialScope = { scope in scope.injectGitInformation() return scope diff --git a/Sources/Sentry/Public/SentryReplayApi.h b/Sources/Sentry/Public/SentryReplayApi.h index ecbb58872a..800dbb0c97 100644 --- a/Sources/Sentry/Public/SentryReplayApi.h +++ b/Sources/Sentry/Public/SentryReplayApi.h @@ -15,19 +15,18 @@ NS_ASSUME_NONNULL_BEGIN @interface SentryReplayApi : NSObject /** - * Marks this view to be redacted during replays. + * Marks this view to be masked during replays. * * @warning This is an experimental feature and may still have bugs. */ -- (void)redactView:(UIView *)view NS_SWIFT_NAME(redactView(_:)); +- (void)maskView:(UIView *)view NS_SWIFT_NAME(maskView(_:)); /** - * Marks this view to be ignored during redact step of session replay. - * All its content will be visible in the replay. + * Marks this view to not be masked during redact step of session replay. * * @warning This is an experimental feature and may still have bugs. */ -- (void)ignoreView:(UIView *)view NS_SWIFT_NAME(ignoreView(_:)); +- (void)unmaskView:(UIView *)view NS_SWIFT_NAME(unmaskView(_:)); /** * Pauses the replay. diff --git a/Sources/Sentry/SentryReplayApi.m b/Sources/Sentry/SentryReplayApi.m index e9ce39b34a..9d2e7ba4b1 100644 --- a/Sources/Sentry/SentryReplayApi.m +++ b/Sources/Sentry/SentryReplayApi.m @@ -10,14 +10,14 @@ @implementation SentryReplayApi -- (void)redactView:(UIView *)view +- (void)maskView:(UIView *)view { - [SentryRedactViewHelper redactView:view]; + [SentryRedactViewHelper maskView:view]; } -- (void)ignoreView:(UIView *)view +- (void)unmaskView:(UIView *)view { - [SentryRedactViewHelper ignoreView:view]; + [SentryRedactViewHelper unmaskView:view]; } - (void)pause diff --git a/Sources/SentrySwiftUI/SentryReplayView.swift b/Sources/SentrySwiftUI/SentryReplayView.swift index fa24d3f4e2..395a4f7a94 100644 --- a/Sources/SentrySwiftUI/SentryReplayView.swift +++ b/Sources/SentrySwiftUI/SentryReplayView.swift @@ -10,7 +10,7 @@ struct SentryReplayView: UIViewRepresentable { func makeUIView(context: Context) -> UIView { let result = SentryRedactView() - result.sentryReplayRedact() + result.sentryReplayMask() return result } diff --git a/Sources/Swift/Extensions/UIViewExtensions.swift b/Sources/Swift/Extensions/UIViewExtensions.swift index 61ca12e2b2..83bf0ade79 100644 --- a/Sources/Swift/Extensions/UIViewExtensions.swift +++ b/Sources/Swift/Extensions/UIViewExtensions.swift @@ -9,8 +9,8 @@ public extension UIView { * Marks this view to be redacted during replays. * - experiment: This is an experimental feature and may still have bugs. */ - func sentryReplayRedact() { - SentryRedactViewHelper.redactView(self) + func sentryReplayMask() { + SentryRedactViewHelper.maskView(self) } /** @@ -18,8 +18,8 @@ public extension UIView { * of session replay. All its content will be visible in the replay. * - experiment: This is an experimental feature and may still have bugs. */ - func sentryReplayIgnore() { - SentryRedactViewHelper.ignoreView(self) + func sentryReplayUnmask() { + SentryRedactViewHelper.unmaskView(self) } } diff --git a/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift b/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift index 35b20553ee..a29b3a050b 100644 --- a/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift +++ b/Sources/Swift/Integrations/SessionReplay/SentryReplayOptions.swift @@ -51,7 +51,7 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions { * * - note: The default is true */ - public var redactAllText = true + public var maskAllText = true /** * Indicates whether session replay should redact all non-bundled image @@ -59,7 +59,7 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions { * * - note: The default is true */ - public var redactAllImages = true + public var maskAllImages = true /** * Indicates the quality of the replay. @@ -73,7 +73,7 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions { * By default Sentry already mask text and image elements from UIKit * Every child of a view that is redacted will also be redacted. */ - public var redactViewClasses = [AnyClass]() + public var maskedViewClasses = [AnyClass]() /** * A list of custom UIView subclasses to be ignored @@ -81,7 +81,7 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions { * The views of given classes will not be redacted but their children may be. * This property has precedence over `redactViewTypes`. */ - public var ignoreViewClasses = [AnyClass]() + public var unmaskedViewClasses = [AnyClass]() /** * Defines the quality of the session replay. @@ -139,18 +139,18 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions { * - errorSampleRate Indicates the percentage in which a 30 seconds replay will be send with * error events. */ - public init(sessionSampleRate: Float = 0, onErrorSampleRate: Float = 0, redactAllText: Bool = true, redactAllImages: Bool = true) { + public init(sessionSampleRate: Float = 0, onErrorSampleRate: Float = 0, maskAllText: Bool = true, maskAllImages: Bool = true) { self.sessionSampleRate = sessionSampleRate self.onErrorSampleRate = onErrorSampleRate - self.redactAllText = redactAllText - self.redactAllImages = redactAllImages + self.maskAllText = maskAllText + self.maskAllImages = maskAllImages } convenience init(dictionary: [String: Any]) { let sessionSampleRate = (dictionary["sessionSampleRate"] as? NSNumber)?.floatValue ?? 0 let onErrorSampleRate = (dictionary["errorSampleRate"] as? NSNumber)?.floatValue ?? 0 - let redactAllText = (dictionary["redactAllText"] as? NSNumber)?.boolValue ?? true - let redactAllImages = (dictionary["redactAllImages"] as? NSNumber)?.boolValue ?? true - self.init(sessionSampleRate: sessionSampleRate, onErrorSampleRate: onErrorSampleRate, redactAllText: redactAllText, redactAllImages: redactAllImages) + let maskAllText = (dictionary["maskAllText"] as? NSNumber)?.boolValue ?? true + let maskAllImages = (dictionary["maskAllImages"] as? NSNumber)?.boolValue ?? true + self.init(sessionSampleRate: sessionSampleRate, onErrorSampleRate: onErrorSampleRate, maskAllText: maskAllText, maskAllImages: maskAllImages) } } diff --git a/Sources/Swift/Protocol/SentryRedactOptions.swift b/Sources/Swift/Protocol/SentryRedactOptions.swift index dc0e05c973..24560dddea 100644 --- a/Sources/Swift/Protocol/SentryRedactOptions.swift +++ b/Sources/Swift/Protocol/SentryRedactOptions.swift @@ -2,8 +2,8 @@ import Foundation @objc protocol SentryRedactOptions { - var redactAllText: Bool { get } - var redactAllImages: Bool { get } - var redactViewClasses: [AnyClass] { get } - var ignoreViewClasses: [AnyClass] { get } + var maskAllText: Bool { get } + var maskAllImages: Bool { get } + var maskedViewClasses: [AnyClass] { get } + var unmaskedViewClasses: [AnyClass] { get } } diff --git a/Sources/Swift/Tools/UIRedactBuilder.swift b/Sources/Swift/Tools/UIRedactBuilder.swift index 2ec380441d..8c6555f769 100644 --- a/Sources/Swift/Tools/UIRedactBuilder.swift +++ b/Sources/Swift/Tools/UIRedactBuilder.swift @@ -62,11 +62,11 @@ class UIRedactBuilder { init(options: SentryRedactOptions) { var redactClasses = [AnyClass]() - if options.redactAllText { + if options.maskAllText { redactClasses += [ UILabel.self, UITextView.self, UITextField.self ] } - if options.redactAllImages { + if options.maskAllImages { //this classes are used by SwiftUI to display images. redactClasses += ["_TtCOCV7SwiftUI11DisplayList11ViewUpdater8Platform13CGDrawingView", "_TtC7SwiftUIP33_A34643117F00277B93DEBAB70EC0697122_UIShapeHitTestingView", @@ -89,11 +89,11 @@ class UIRedactBuilder { redactClassesIdentifiers = Set(redactClasses.map({ ObjectIdentifier($0) })) - for type in options.ignoreViewClasses { + for type in options.unmaskedViewClasses { self.ignoreClassesIdentifiers.insert(ObjectIdentifier(type)) } - for type in options.redactViewClasses { + for type in options.maskedViewClasses { self.redactClassesIdentifiers.insert(ObjectIdentifier(type)) } } @@ -159,11 +159,11 @@ class UIRedactBuilder { } private func shouldIgnore(view: UIView) -> Bool { - return SentryRedactViewHelper.shouldIgnoreView(view) || containsIgnoreClass(type(of: view)) + return SentryRedactViewHelper.shouldUnmask(view) || containsIgnoreClass(type(of: view)) } private func shouldRedact(view: UIView) -> Bool { - if SentryRedactViewHelper.shouldRedactView(view) { + if SentryRedactViewHelper.shouldMaskView(view) { return true } if let imageView = view as? UIImageView, containsRedactClass(UIImageView.self) { @@ -257,19 +257,19 @@ class SentryRedactViewHelper: NSObject { private static var associatedRedactObjectHandle: UInt8 = 0 private static var associatedIgnoreObjectHandle: UInt8 = 0 - static func shouldRedactView(_ view: UIView) -> Bool { + static func shouldMaskView(_ view: UIView) -> Bool { (objc_getAssociatedObject(view, &associatedRedactObjectHandle) as? NSNumber)?.boolValue ?? false } - static func shouldIgnoreView(_ view: UIView) -> Bool { + static func shouldUnmask(_ view: UIView) -> Bool { (objc_getAssociatedObject(view, &associatedIgnoreObjectHandle) as? NSNumber)?.boolValue ?? false } - static func redactView(_ view: UIView) { + static func maskView(_ view: UIView) { objc_setAssociatedObject(view, &associatedRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } - static func ignoreView(_ view: UIView) { + static func unmaskView(_ view: UIView) { objc_setAssociatedObject(view, &associatedIgnoreObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } } diff --git a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift index 2b2b2a8aeb..a308c8eb2e 100644 --- a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift @@ -288,7 +288,7 @@ class SentrySessionReplayIntegrationTests: XCTestCase { } startSDK(sessionSampleRate: 1, errorSampleRate: 1) { options in - options.experimental.sessionReplay.redactViewClasses = [AnotherLabel.self] + options.experimental.sessionReplay.maskedViewClasses = [AnotherLabel.self] } let sut = try getSut() @@ -301,7 +301,7 @@ class SentrySessionReplayIntegrationTests: XCTestCase { } startSDK(sessionSampleRate: 1, errorSampleRate: 1) { options in - options.experimental.sessionReplay.ignoreViewClasses = [AnotherLabel.self] + options.experimental.sessionReplay.unmaskedViewClasses = [AnotherLabel.self] } let sut = try getSut() diff --git a/Tests/SentryTests/UIRedactBuilderTests.swift b/Tests/SentryTests/UIRedactBuilderTests.swift index 1711973ca9..4d1f8e4493 100644 --- a/Tests/SentryTests/UIRedactBuilderTests.swift +++ b/Tests/SentryTests/UIRedactBuilderTests.swift @@ -6,16 +6,16 @@ import UIKit import XCTest class RedactOptions: SentryRedactOptions { - var redactViewClasses: [AnyClass] - var ignoreViewClasses: [AnyClass] - var redactAllText: Bool - var redactAllImages: Bool + var maskedViewClasses: [AnyClass] + var unmaskedViewClasses: [AnyClass] + var maskAllText: Bool + var maskAllImages: Bool init(redactAllText: Bool = true, redactAllImages: Bool = true) { - self.redactAllText = redactAllText - self.redactAllImages = redactAllImages - redactViewClasses = [] - ignoreViewClasses = [] + self.maskAllText = redactAllText + self.maskAllImages = redactAllImages + maskedViewClasses = [] + unmaskedViewClasses = [] } } From ac592671b85b6a89ebe08ffadf3de62504d2896d Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Thu, 26 Sep 2024 15:30:30 +0200 Subject: [PATCH 02/15] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 847b582ecd..38f29f2432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Speed up HTTP tracking for multiple requests in parallel (#4366) - Slightly speed up SentryInAppLogic (#4370) +- Rename session replay `redact` options and APIs to `mask` () ## 8.37.0-beta.1 From 68c872dd4626a18f30487a8ab8d01e9c5605aed9 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Thu, 26 Sep 2024 15:46:13 +0200 Subject: [PATCH 03/15] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38f29f2432..110d412a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ - Speed up HTTP tracking for multiple requests in parallel (#4366) - Slightly speed up SentryInAppLogic (#4370) -- Rename session replay `redact` options and APIs to `mask` () +- Rename session replay `redact` options and APIs to `mask` (#4373) ## 8.37.0-beta.1 From c082abc13b7d52e1a6bc5195b2a63556d2fe7819 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Fri, 27 Sep 2024 09:40:20 +0200 Subject: [PATCH 04/15] Update SRRedactSampleViewController.swift --- .../ViewControllers/SRRedactSampleViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/iOS-Swift/iOS-Swift/ViewControllers/SRRedactSampleViewController.swift b/Samples/iOS-Swift/iOS-Swift/ViewControllers/SRRedactSampleViewController.swift index e7a23a5e85..d14416638d 100644 --- a/Samples/iOS-Swift/iOS-Swift/ViewControllers/SRRedactSampleViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ViewControllers/SRRedactSampleViewController.swift @@ -12,6 +12,6 @@ class SRRedactSampleViewController: UIViewController { notRedactedView.backgroundColor = .green notRedactedView.transform = CGAffineTransform(rotationAngle: 45 * .pi / 180.0) - SentrySDK.replay.ignoreView(notRedactedView) + SentrySDK.replay.maskView(notRedactedView) } } From 8cbee68c9ad8f486469d5238a4913fae5fd43ed0 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Fri, 27 Sep 2024 10:15:06 +0200 Subject: [PATCH 05/15] Update UIRedactBuilderTests.swift --- Tests/SentryTests/UIRedactBuilderTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/SentryTests/UIRedactBuilderTests.swift b/Tests/SentryTests/UIRedactBuilderTests.swift index 4d1f8e4493..856a58f4f1 100644 --- a/Tests/SentryTests/UIRedactBuilderTests.swift +++ b/Tests/SentryTests/UIRedactBuilderTests.swift @@ -197,7 +197,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let label = AnotherLabel(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - SentrySDK.replay.ignoreView(label) + SentrySDK.replay.maskView(label) rootView.addSubview(label) let result = sut.redactRegionsFor(view: rootView) @@ -210,7 +210,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let view = AnotherView(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - SentrySDK.replay.redactView(view) + SentrySDK.replay.maskView(view) rootView.addSubview(view) let result = sut.redactRegionsFor(view: rootView) @@ -223,7 +223,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let label = AnotherLabel(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - label.sentryReplayIgnore() + label.sentryReplayMask() rootView.addSubview(label) let result = sut.redactRegionsFor(view: rootView) @@ -236,7 +236,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let view = AnotherView(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - view.sentryReplayRedact() + view.sentryReplayMask() rootView.addSubview(view) let result = sut.redactRegionsFor(view: rootView) From fb3c2a73061559bf3c061449296c93c27db33b70 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Fri, 27 Sep 2024 10:40:27 +0200 Subject: [PATCH 06/15] Update UIRedactBuilderTests.swift --- Tests/SentryTests/UIRedactBuilderTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SentryTests/UIRedactBuilderTests.swift b/Tests/SentryTests/UIRedactBuilderTests.swift index 856a58f4f1..19d810de43 100644 --- a/Tests/SentryTests/UIRedactBuilderTests.swift +++ b/Tests/SentryTests/UIRedactBuilderTests.swift @@ -197,7 +197,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let label = AnotherLabel(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - SentrySDK.replay.maskView(label) + SentrySDK.replay.unmaskView(label) rootView.addSubview(label) let result = sut.redactRegionsFor(view: rootView) @@ -223,7 +223,7 @@ class UIRedactBuilderTests: XCTestCase { let sut = getSut() let label = AnotherLabel(frame: CGRect(x: 20, y: 20, width: 40, height: 40)) - label.sentryReplayMask() + label.sentryReplayUnmask() rootView.addSubview(label) let result = sut.redactRegionsFor(view: rootView) From 77ce3137fd897f533ec4559179b136d0dab40188 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Fri, 27 Sep 2024 15:20:46 +0200 Subject: [PATCH 07/15] Update SentryReplayView.swift --- Sources/SentrySwiftUI/SentryReplayView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SentrySwiftUI/SentryReplayView.swift b/Sources/SentrySwiftUI/SentryReplayView.swift index 395a4f7a94..e35db36e51 100644 --- a/Sources/SentrySwiftUI/SentryReplayView.swift +++ b/Sources/SentrySwiftUI/SentryReplayView.swift @@ -29,15 +29,15 @@ struct SentryReplayModifier: ViewModifier { @available(iOS 13, macOS 10.15, tvOS 13, *) public extension View { - /// Marks the view as containing sensitive information that should be redacted during replays. + /// Marks the view as containing sensitive information that should be masked during replays. /// - /// When this modifier is applied, any sensitive content within the view will be hidden or masked + /// When this modifier is applied, any sensitive content within the view will be masked /// during session replays to ensure user privacy. This is useful for views containing personal /// data or confidential information that shouldn't be visible when the replay is reviewed. /// /// - Returns: A modifier that redacts sensitive information during session replays. /// - Experiment: This is an experimental feature and may still have bugs. - func sentryReplayRedact() -> some View { + func sentryReplayMask() -> some View { modifier(SentryReplayModifier()) } } From 77f3933f3219d2500d67cebe653993420fd00b5a Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Tue, 1 Oct 2024 08:44:40 +0200 Subject: [PATCH 08/15] Wip --- .../iOS-SwiftUI/iOS-SwiftUI/ContentView.swift | 5 +- .../iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift | 4 +- Sources/SentrySwiftUI/SentryReplayView.swift | 37 ++++++++++---- .../Swift/Extensions/UIViewExtensions.swift | 18 +++++++ .../Swift/Tools/SentryViewPhotographer.swift | 2 +- Sources/Swift/Tools/UIRedactBuilder.swift | 50 ++++++++++++++++--- 6 files changed, 94 insertions(+), 22 deletions(-) diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift index 280f2c20ef..16cfddc9a1 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift @@ -189,7 +189,7 @@ struct ContentView: View { NavigationLink(destination: LoremIpsumView()) { Text("Lorem Ipsum") - } + }.sentryReplayMask() NavigationLink(destination: UIKitScreen()) { Text("UIKit Screen") @@ -199,7 +199,8 @@ struct ContentView: View { Text("Form Screen") } } - .sentryReplayRedact() + .background(Color.white) + .sentryReplayUnmask() } SecondView() } diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift index 5a490cd286..86c274df1c 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/SwiftUIApp.swift @@ -11,8 +11,8 @@ struct SwiftUIApp: App { options.tracesSampleRate = 1.0 options.profilesSampleRate = 1.0 options.experimental.sessionReplay.sessionSampleRate = 1.0 - options.experimental.sessionReplay.maskAllImages = false - options.experimental.sessionReplay.maskAllText = false + options.experimental.sessionReplay.maskAllImages = true + options.experimental.sessionReplay.maskAllText = true options.initialScope = { scope in scope.injectGitInformation() return scope diff --git a/Sources/SentrySwiftUI/SentryReplayView.swift b/Sources/SentrySwiftUI/SentryReplayView.swift index 395a4f7a94..1a799f51c1 100644 --- a/Sources/SentrySwiftUI/SentryReplayView.swift +++ b/Sources/SentrySwiftUI/SentryReplayView.swift @@ -3,42 +3,61 @@ import Sentry import SwiftUI import UIKit +enum MaskBehaviour { + case mask + case unmask +} + @available(iOS 13, macOS 10.15, tvOS 13, *) struct SentryReplayView: UIViewRepresentable { + let maskBehaviour: MaskBehaviour + class SentryRedactView: UIView { } func makeUIView(context: Context) -> UIView { - let result = SentryRedactView() - result.sentryReplayMask() - return result + return SentryRedactView() } func updateUIView(_ uiView: UIView, context: Context) { - // This is blank on purpose. UIViewRepresentable requires this function. + switch maskBehaviour { + case .mask: uiView.sentryReplayMaskSwiftUI() + case .unmask: uiView.sentryReplayClipOut() + } } } @available(iOS 13, macOS 10.15, tvOS 13, *) struct SentryReplayModifier: ViewModifier { + let behaviour: MaskBehaviour func body(content: Content) -> some View { - content.background(SentryReplayView()) + content.overlay(SentryReplayView(maskBehaviour: behaviour)) } } @available(iOS 13, macOS 10.15, tvOS 13, *) public extension View { - /// Marks the view as containing sensitive information that should be redacted during replays. + /// Marks the view as containing sensitive information that should be masked during replays. /// - /// When this modifier is applied, any sensitive content within the view will be hidden or masked + /// When this modifier is applied, any sensitive content within the view will be masked /// during session replays to ensure user privacy. This is useful for views containing personal /// data or confidential information that shouldn't be visible when the replay is reviewed. /// /// - Returns: A modifier that redacts sensitive information during session replays. /// - Experiment: This is an experimental feature and may still have bugs. - func sentryReplayRedact() -> some View { - modifier(SentryReplayModifier()) + func sentryReplayMask() -> some View { + modifier(SentryReplayModifier(behaviour: .mask)) + } + + /// Marks the view as safe to not be masked during session replay. + /// + /// Anything that is behind this view will also not be masked anymore. + /// + /// - Returns: A modifier that prevents a view from being masked in the session replay. + /// - Experiment: This is an experimental feature and may still have bugs. + func sentryReplayUnmask() -> some View { + modifier(SentryReplayModifier(behaviour: .unmask)) } } #endif diff --git a/Sources/Swift/Extensions/UIViewExtensions.swift b/Sources/Swift/Extensions/UIViewExtensions.swift index 83bf0ade79..5e84f75ecb 100644 --- a/Sources/Swift/Extensions/UIViewExtensions.swift +++ b/Sources/Swift/Extensions/UIViewExtensions.swift @@ -21,6 +21,24 @@ public extension UIView { func sentryReplayUnmask() { SentryRedactViewHelper.unmaskView(self) } + + /** + * Marks this view to create a region in the session replay + * where nothing behind it will be masked. + * This can be used to unmask non PII region inside SwiftUI + * - experiment: This is an experimental feature and may still have bugs. + */ + func sentryReplayClipOut() { + SentryRedactViewHelper.clipOutView(self) + } + + /** + * Marks this view as comming from SwiftUI and needs to be redacted. + * - experiment: This is an experimental feature and may still have bugs. + */ + func sentryReplayMaskSwiftUI() { + SentryRedactViewHelper.maskSwiftUI(self) + } } #endif diff --git a/Sources/Swift/Tools/SentryViewPhotographer.swift b/Sources/Swift/Tools/SentryViewPhotographer.swift index 192585ff21..322a7017a8 100644 --- a/Sources/Swift/Tools/SentryViewPhotographer.swift +++ b/Sources/Swift/Tools/SentryViewPhotographer.swift @@ -58,7 +58,7 @@ class SentryViewPhotographer: NSObject, SentryViewScreenshotProvider { let path = CGPath(rect: rect, transform: &transform) switch region.type { - case .redact: + case .redact, .redactSwiftUI: (region.color ?? UIImageHelper.averageColor(of: context.currentImage, at: rect.applying(region.transform))).setFill() context.cgContext.addPath(path) context.cgContext.fillPath() diff --git a/Sources/Swift/Tools/UIRedactBuilder.swift b/Sources/Swift/Tools/UIRedactBuilder.swift index 8c6555f769..a105694c91 100644 --- a/Sources/Swift/Tools/UIRedactBuilder.swift +++ b/Sources/Swift/Tools/UIRedactBuilder.swift @@ -22,6 +22,9 @@ enum RedactRegionType { /// Pop the last Pushed region from the drawing context. /// Used after prossing every child of a view that clip to its bounds. case clipEnd + + /// These regions are redacted first, there is no way to avoid it. + case redactSwiftUI } struct RedactRegion { @@ -155,7 +158,19 @@ class UIRedactBuilder { rootFrame: view.frame, transform: CGAffineTransform.identity) - return redactingRegions.reversed() + var swiftUIRedact = [RedactRegion]() + var otherRegions = [RedactRegion]() + + for region in redactingRegions { + if region.type == .redactSwiftUI { + swiftUIRedact.append(region) + } else { + otherRegions.append(region) + } + } + + //The swiftUI type needs to appear first in the list so it always get masked + return swiftUIRedact + otherRegions.reversed() } private func shouldIgnore(view: UIView) -> Bool { @@ -187,11 +202,12 @@ class UIRedactBuilder { let newTransform = concatenateTranform(transform, with: layer) let ignore = !forceRedact && shouldIgnore(view: view) - let redact = forceRedact || shouldRedact(view: view) + let swiftUI = SentryRedactViewHelper.shouldRedactSwiftUI(view) + let redact = forceRedact || shouldRedact(view: view) || swiftUI var enforceRedact = forceRedact if !ignore && redact { - redacting.append(RedactRegion(size: layer.bounds.size, transform: newTransform, type: .redact, color: self.color(for: view))) + redacting.append(RedactRegion(size: layer.bounds.size, transform: newTransform, type: swiftUI ? .redactSwiftUI : .redact, color: self.color(for: view))) guard !view.clipsToBounds else { return } enforceRedact = true @@ -248,7 +264,7 @@ class UIRedactBuilder { Indicates whether the view is opaque and will block other view behind it */ private func isOpaque(_ view: UIView) -> Bool { - return view.alpha == 1 && view.backgroundColor != nil && (view.backgroundColor?.cgColor.alpha ?? 0) == 1 + return SentryRedactViewHelper.shouldClipOut(view) || (view.alpha == 1 && view.backgroundColor != nil && (view.backgroundColor?.cgColor.alpha ?? 0) == 1) } } @@ -256,6 +272,12 @@ class UIRedactBuilder { class SentryRedactViewHelper: NSObject { private static var associatedRedactObjectHandle: UInt8 = 0 private static var associatedIgnoreObjectHandle: UInt8 = 0 + private static var associatedClipOutObjectHandle: UInt8 = 0 + private static var associatedSwiftUIRedactObjectHandle: UInt8 = 0 + + static func maskView(_ view: UIView) { + objc_setAssociatedObject(view, &associatedRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) + } static func shouldMaskView(_ view: UIView) -> Bool { (objc_getAssociatedObject(view, &associatedRedactObjectHandle) as? NSNumber)?.boolValue ?? false @@ -265,13 +287,25 @@ class SentryRedactViewHelper: NSObject { (objc_getAssociatedObject(view, &associatedIgnoreObjectHandle) as? NSNumber)?.boolValue ?? false } - static func maskView(_ view: UIView) { - objc_setAssociatedObject(view, &associatedRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) - } - static func unmaskView(_ view: UIView) { objc_setAssociatedObject(view, &associatedIgnoreObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } + + static func shouldClipOut(_ view: UIView) -> Bool { + (objc_getAssociatedObject(view, &associatedClipOutObjectHandle) as? NSNumber)?.boolValue ?? false + } + + static func clipOutView(_ view: UIView) { + objc_setAssociatedObject(view, &associatedClipOutObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) + } + + static func shouldRedactSwiftUI(_ view: UIView) -> Bool { + (objc_getAssociatedObject(view, &associatedSwiftUIRedactObjectHandle) as? NSNumber)?.boolValue ?? false + } + + static func maskSwiftUI(_ view: UIView) { + objc_setAssociatedObject(view, &associatedSwiftUIRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) + } } #endif From 122dba29715b63f60122d0579951d9f0a9ccd0ec Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Wed, 2 Oct 2024 12:16:28 +0200 Subject: [PATCH 09/15] SwiftUI control --- .../SentryInternal/SentryInternal.h | 15 +++++++++++++++ Sources/SentrySwiftUI/SentryReplayView.swift | 8 ++++++-- .../Swift/Extensions/UIViewExtensions.swift | 19 +------------------ Sources/Swift/Tools/UIRedactBuilder.swift | 3 +++ 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h b/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h index ce265ced39..7ca487a888 100644 --- a/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h +++ b/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSInteger, SentryTransactionNameSource); +@class UIView; @class SentrySpanId; @protocol SentrySpan; @@ -56,4 +57,18 @@ typedef NS_ENUM(NSUInteger, SentrySpanStatus); @end +// Exposing SentryRedactViewHelper for our SentrySwiftUI external module +@interface SentryRedactViewHelper : NSObject +- (nonnull instancetype)init; ++ (nonnull instancetype)new; ++ (void)maskView:(UIView *_Nonnull)view; ++ (BOOL)shouldMaskView:(UIView *_Nonnull)view; ++ (BOOL)shouldUnmask:(UIView *_Nonnull)view; ++ (void)unmaskView:(UIView *_Nonnull)view; ++ (BOOL)shouldClipOut:(UIView *_Nonnull)view; ++ (void)clipOutView:(UIView *_Nonnull)view; ++ (BOOL)shouldRedactSwiftUI:(UIView *_Nonnull)view; ++ (void)maskSwiftUI:(UIView *_Nonnull)view; +@end + NS_ASSUME_NONNULL_END diff --git a/Sources/SentrySwiftUI/SentryReplayView.swift b/Sources/SentrySwiftUI/SentryReplayView.swift index 1a799f51c1..fe096b6263 100644 --- a/Sources/SentrySwiftUI/SentryReplayView.swift +++ b/Sources/SentrySwiftUI/SentryReplayView.swift @@ -3,6 +3,10 @@ import Sentry import SwiftUI import UIKit +#if CARTHAGE || SWIFT_PACKAGE +@_implementationOnly import SentryInternal +#endif + enum MaskBehaviour { case mask case unmask @@ -21,8 +25,8 @@ struct SentryReplayView: UIViewRepresentable { func updateUIView(_ uiView: UIView, context: Context) { switch maskBehaviour { - case .mask: uiView.sentryReplayMaskSwiftUI() - case .unmask: uiView.sentryReplayClipOut() + case .mask: SentryRedactViewHelper.maskSwiftUI(uiView) + case .unmask: SentryRedactViewHelper.clipOutView(uiView) } } } diff --git a/Sources/Swift/Extensions/UIViewExtensions.swift b/Sources/Swift/Extensions/UIViewExtensions.swift index 5e84f75ecb..7c5e8cf27c 100644 --- a/Sources/Swift/Extensions/UIViewExtensions.swift +++ b/Sources/Swift/Extensions/UIViewExtensions.swift @@ -21,24 +21,7 @@ public extension UIView { func sentryReplayUnmask() { SentryRedactViewHelper.unmaskView(self) } - - /** - * Marks this view to create a region in the session replay - * where nothing behind it will be masked. - * This can be used to unmask non PII region inside SwiftUI - * - experiment: This is an experimental feature and may still have bugs. - */ - func sentryReplayClipOut() { - SentryRedactViewHelper.clipOutView(self) - } - - /** - * Marks this view as comming from SwiftUI and needs to be redacted. - * - experiment: This is an experimental feature and may still have bugs. - */ - func sentryReplayMaskSwiftUI() { - SentryRedactViewHelper.maskSwiftUI(self) - } + } #endif diff --git a/Sources/Swift/Tools/UIRedactBuilder.swift b/Sources/Swift/Tools/UIRedactBuilder.swift index a105694c91..574653d862 100644 --- a/Sources/Swift/Tools/UIRedactBuilder.swift +++ b/Sources/Swift/Tools/UIRedactBuilder.swift @@ -268,6 +268,7 @@ class UIRedactBuilder { } } +@objc(SentryRedactViewHelper) @objcMembers class SentryRedactViewHelper: NSObject { private static var associatedRedactObjectHandle: UInt8 = 0 @@ -275,6 +276,8 @@ class SentryRedactViewHelper: NSObject { private static var associatedClipOutObjectHandle: UInt8 = 0 private static var associatedSwiftUIRedactObjectHandle: UInt8 = 0 + override private init() {} + static func maskView(_ view: UIView) { objc_setAssociatedObject(view, &associatedRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } From 483145472cd1fb3251b7f91e15e78a646a8319ba Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Wed, 2 Oct 2024 12:35:17 +0200 Subject: [PATCH 10/15] wip --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c02a8f01..7549bc7454 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Features - Added breadcrumb.origin private field (#4358) -- Custom redact modifier for SwiftUI (#4362) +- Custom redact modifier for SwiftUI (#4362, #4392) ### Improvements From 6a3fee84d90cb8fa4047501310c9020b3179737a Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Wed, 2 Oct 2024 12:41:57 +0200 Subject: [PATCH 11/15] Update SentryRedactModifierTests.swift --- .../SwiftUI/SentryRedactModifierTests.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift b/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift index a6023705e5..48caa3246a 100644 --- a/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift +++ b/Tests/SentryTests/SwiftUI/SentryRedactModifierTests.swift @@ -6,9 +6,16 @@ import XCTest class SentryRedactModifierTests: XCTestCase { - func testViewRedacted() throws { + func testViewMask() throws { let text = Text("Hello, World!") - let redactedText = text.sentryReplayRedact() + let redactedText = text.sentryReplayMask() + + XCTAssertTrue(redactedText is ModifiedContent) + } + + func testViewUnmask() throws { + let text = Text("Hello, World!") + let redactedText = text.sentryReplayUnmask() XCTAssertTrue(redactedText is ModifiedContent) } From 2cad7efae14599bdec176ad9f2d66db235ecaa7b Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Wed, 2 Oct 2024 13:33:06 +0200 Subject: [PATCH 12/15] expose SentryRedactViewHelper --- .../SentrySwiftUI/SentryInternal/SentryInternal.h | 14 -------------- Sources/Swift/Tools/UIRedactBuilder.swift | 7 +++---- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h b/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h index 7ca487a888..76b6188f29 100644 --- a/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h +++ b/Sources/SentrySwiftUI/SentryInternal/SentryInternal.h @@ -57,18 +57,4 @@ typedef NS_ENUM(NSUInteger, SentrySpanStatus); @end -// Exposing SentryRedactViewHelper for our SentrySwiftUI external module -@interface SentryRedactViewHelper : NSObject -- (nonnull instancetype)init; -+ (nonnull instancetype)new; -+ (void)maskView:(UIView *_Nonnull)view; -+ (BOOL)shouldMaskView:(UIView *_Nonnull)view; -+ (BOOL)shouldUnmask:(UIView *_Nonnull)view; -+ (void)unmaskView:(UIView *_Nonnull)view; -+ (BOOL)shouldClipOut:(UIView *_Nonnull)view; -+ (void)clipOutView:(UIView *_Nonnull)view; -+ (BOOL)shouldRedactSwiftUI:(UIView *_Nonnull)view; -+ (void)maskSwiftUI:(UIView *_Nonnull)view; -@end - NS_ASSUME_NONNULL_END diff --git a/Sources/Swift/Tools/UIRedactBuilder.swift b/Sources/Swift/Tools/UIRedactBuilder.swift index 574653d862..5e55914af1 100644 --- a/Sources/Swift/Tools/UIRedactBuilder.swift +++ b/Sources/Swift/Tools/UIRedactBuilder.swift @@ -268,9 +268,8 @@ class UIRedactBuilder { } } -@objc(SentryRedactViewHelper) @objcMembers -class SentryRedactViewHelper: NSObject { +public class SentryRedactViewHelper: NSObject { private static var associatedRedactObjectHandle: UInt8 = 0 private static var associatedIgnoreObjectHandle: UInt8 = 0 private static var associatedClipOutObjectHandle: UInt8 = 0 @@ -298,7 +297,7 @@ class SentryRedactViewHelper: NSObject { (objc_getAssociatedObject(view, &associatedClipOutObjectHandle) as? NSNumber)?.boolValue ?? false } - static func clipOutView(_ view: UIView) { + static public func clipOutView(_ view: UIView) { objc_setAssociatedObject(view, &associatedClipOutObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } @@ -306,7 +305,7 @@ class SentryRedactViewHelper: NSObject { (objc_getAssociatedObject(view, &associatedSwiftUIRedactObjectHandle) as? NSNumber)?.boolValue ?? false } - static func maskSwiftUI(_ view: UIView) { + static public func maskSwiftUI(_ view: UIView) { objc_setAssociatedObject(view, &associatedSwiftUIRedactObjectHandle, true, .OBJC_ASSOCIATION_ASSIGN) } } From 5a9010e3bb0fb988aa5e559090b572cd5a82b11c Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Wed, 2 Oct 2024 15:08:46 +0200 Subject: [PATCH 13/15] Update SentryReplayView.swift --- Sources/SentrySwiftUI/SentryReplayView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/SentrySwiftUI/SentryReplayView.swift b/Sources/SentrySwiftUI/SentryReplayView.swift index fe096b6263..ebc1fbc471 100644 --- a/Sources/SentrySwiftUI/SentryReplayView.swift +++ b/Sources/SentrySwiftUI/SentryReplayView.swift @@ -20,7 +20,9 @@ struct SentryReplayView: UIViewRepresentable { } func makeUIView(context: Context) -> UIView { - return SentryRedactView() + let view = SentryRedactView() + view.isUserInteractionEnabled = false + return view } func updateUIView(_ uiView: UIView, context: Context) { From 0b11da7018149a991e5460081e65951133f2d670 Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Thu, 3 Oct 2024 08:30:04 +0200 Subject: [PATCH 14/15] Update ContentView.swift --- .../iOS-SwiftUI/iOS-SwiftUI/ContentView.swift | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift index 16cfddc9a1..be7b0b0f7f 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift @@ -118,14 +118,16 @@ struct ContentView: View { return SentryTracedView("Content View Body") { NavigationView { VStack(alignment: HorizontalAlignment.center, spacing: 16) { - Text(getCurrentTracer()?.transactionContext.name ?? "NO SPAN") - .accessibilityIdentifier("TRANSACTION_NAME") - Text(getCurrentTracer()?.transactionContext.spanId.sentrySpanIdString ?? "NO ID") - .accessibilityIdentifier("TRANSACTION_ID") - - Text(getCurrentTracer()?.transactionContext.origin ?? "NO ORIGIN") - .accessibilityIdentifier("TRACE_ORIGIN") - + Group { + Text(getCurrentTracer()?.transactionContext.name ?? "NO SPAN") + .accessibilityIdentifier("TRANSACTION_NAME") + Text(getCurrentTracer()?.transactionContext.spanId.sentrySpanIdString ?? "NO ID") + .accessibilityIdentifier("TRANSACTION_ID") + .sentryReplayMask() + + Text(getCurrentTracer()?.transactionContext.origin ?? "NO ORIGIN") + .accessibilityIdentifier("TRACE_ORIGIN") + }.sentryReplayUnmask() SentryTracedView("Child Span") { VStack { Text(getCurrentSpan()?.spanDescription ?? "NO SPAN") @@ -189,7 +191,7 @@ struct ContentView: View { NavigationLink(destination: LoremIpsumView()) { Text("Lorem Ipsum") - }.sentryReplayMask() + } NavigationLink(destination: UIKitScreen()) { Text("UIKit Screen") @@ -200,7 +202,6 @@ struct ContentView: View { } } .background(Color.white) - .sentryReplayUnmask() } SecondView() } From 5bc4277a965f390c5dace2d7198925a8d5a43cfc Mon Sep 17 00:00:00 2001 From: Dhiogo Brustolin Date: Fri, 4 Oct 2024 13:41:32 +0200 Subject: [PATCH 15/15] Update ContentView.swift --- Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift index 374b7bf137..be7b0b0f7f 100644 --- a/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift +++ b/Samples/iOS-SwiftUI/iOS-SwiftUI/ContentView.swift @@ -202,7 +202,6 @@ struct ContentView: View { } } .background(Color.white) - .sentryReplayMask() } SecondView() }