diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc2a3fab..2570181f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next +- recording: detect swiftui images not too agressively ([#181](https://github.com/PostHog/posthog-ios/pull/181)) + ## 3.9.0 - 2024-09-06 - chore: add SwiftUI View extensions to capture screen view and views in general (postHogViewEvent, postHogScreenView) ([#180](https://github.com/PostHog/posthog-ios/pull/180)) diff --git a/PostHog/Replay/PostHogReplayIntegration.swift b/PostHog/Replay/PostHogReplayIntegration.swift index f128e18ef..164646066 100644 --- a/PostHog/Replay/PostHogReplayIntegration.swift +++ b/PostHog/Replay/PostHogReplayIntegration.swift @@ -24,11 +24,12 @@ // SwiftUI image types // https://stackoverflow.com/questions/57554590/how-to-get-all-the-subviews-of-a-window-or-view-in-latest-swiftui-app // https://stackoverflow.com/questions/58336045/how-to-detect-swiftui-usage-programmatically-in-an-ios-application - private let swiftUIImageTypes = ["_TtCOCV7SwiftUI11DisplayList11ViewUpdater8Platform13CGDrawingView", - "_TtC7SwiftUIP33_A34643117F00277B93DEBAB70EC0697122_UIShapeHitTestingView", - "SwiftUI._UIGraphicsView", + private let swiftUIImageTypes = ["SwiftUI._UIGraphicsView", "SwiftUI.ImageLayer"].compactMap { NSClassFromString($0) } + private let swiftUIGenericTypes = ["_TtCOCV7SwiftUI11DisplayList11ViewUpdater8Platform13CGDrawingView", + "_TtC7SwiftUIP33_A34643117F00277B93DEBAB70EC0697122_UIShapeHitTestingView"].compactMap { NSClassFromString($0) } + static let dispatchQueue = DispatchQueue(label: "com.posthog.PostHogReplayIntegration", target: .global(qos: .utility)) @@ -214,7 +215,15 @@ } if swiftUIImageTypes.contains(where: { view.isKind(of: $0) }) { - if isAnyInputSensitive(view) { + if isSwiftUIImageSensitive(view) { + maskableWidgets.append(view.toAbsoluteRect(parent)) + return + } + } + + // this can be anything, so better to be conservative + if swiftUIGenericTypes.contains(where: { view.isKind(of: $0) }) { + if isTextInputSensitive(view) { maskableWidgets.append(view.toAbsoluteRect(parent)) return } @@ -306,6 +315,15 @@ } } + private func isSwiftUIImageSensitive(_ view: UIView) -> Bool { + // the raw type _UIGraphicsView is always something like Color.white or similar + // never contains PII and should not be masked + let type = type(of: view) + + let rawGraphicsView = String(describing: type) == "_UIGraphicsView" + return (config.sessionReplayConfig.maskAllImages || view.isNoCapture()) && !rawGraphicsView + } + private func isImageViewSensitive(_ view: UIImageView) -> Bool { var isAsset = false if let image = view.image {