-
-
Notifications
You must be signed in to change notification settings - Fork 410
Expand file tree
/
Copy pathSentryScreenshotOptions.swift
More file actions
268 lines (249 loc) · 15.6 KB
/
Copy pathSentryScreenshotOptions.swift
File metadata and controls
268 lines (249 loc) · 15.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// swiftlint:disable missing_docs
import Foundation
@objcMembers
public final class SentryViewScreenshotOptions: NSObject, SentryRedactOptions {
/**
* Default values for the screenshot options.
*
* - Note: These values are used to ensure the different initializers use the same default values.
*/
public final class DefaultValues {
public static let enableViewRendererV2: Bool = true
public static let enableFastViewRendering: Bool = false
public static let maskAllText: Bool = true
public static let maskAllImages: Bool = true
public static let maskedViewClasses: [AnyClass] = []
public static let unmaskedViewClasses: [AnyClass] = []
public static let excludedViewClasses: Set<String> = []
public static let includedViewClasses: Set<String> = []
}
// MARK: - Rendering
/**
* Enables the up to 5x faster new view renderer.
*
* Enabling this flag will reduce the amount of time it takes to render the screenshot on the main thread, therefore reducing
* interruptions and visual lag. [Our benchmarks](https://github.com/getsentry/sentry-cocoa/pull/4940) have shown a significant improvement of
* **up to 4-5x faster rendering** (reducing `~160ms` to `~36ms`) on older devices.
*
* - Experiment: In case you are noticing issues with the new view renderer, please report the issue on [GitHub](https://github.com/getsentry/sentry-cocoa).
* Eventually, we will remove this feature flag and use the new view renderer by default.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var enableViewRendererV2: Bool
/**
* Enables up to 5x faster but incomplete view rendering.
*
* Enabling this flag will reduce the amount of time it takes to render the screenshot, therefore reducing
* interruptions and visual lag. [Our benchmarks](https://github.com/getsentry/sentry-cocoa/pull/4940) have shown a significant improvement of
* up to **5x faster render times** (reducing `~160ms` to `~30ms`) on older devices.
*
* This flag controls the way the view hierarchy is drawn into a graphics context. By default, the view hierarchy is drawn using
* the `UIView.drawHierarchy(in:afterScreenUpdates:)` method, which is the most complete way to render the view hierarchy. However,
* this method can be slow, especially when rendering complex views, therefore enabling this flag will switch to render the underlying `CALayer` instead.
*
* - Note: This flag can only be used together with `enableViewRendererV2` with up to 20% faster render times.
* - Warning: Rendering the view hierarchy using the `CALayer.render(in:)` method can lead to rendering issues, especially when using custom views.
* For complete rendering, it is recommended to set this option to `false`. In case you prefer performance over completeness, you can
* set this option to `true`.
* - Experiment: This is an experimental feature and is therefore disabled by default. In case you are noticing issues with the experimental
* view renderer, please report the issue on [GitHub](https://github.com/getsentry/sentry-cocoa). Eventually, we will
* mark this feature as stable and remove the experimental flag, but will keep it disabled by default.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var enableFastViewRendering: Bool
// MARK: - Masking
/**
* Indicates whether the screenshot should redact all non-bundled image
* in the app by drawing a black rectangle over it.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var maskAllImages: Bool
/**
* Indicates whether the screenshot should redact all text in the app
* by drawing a black rectangle over it.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var maskAllText: Bool
/**
* A list of custom UIView subclasses that need
* to be masked during the screenshot.
* By default Sentry already mask text and image elements from UIKit
* Every child of a view that is redacted will also be redacted.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var maskedViewClasses: [AnyClass]
/**
* A list of custom UIView subclasses to be ignored
* during masking step of the screenshot.
* The views of given classes will not be redacted but their children may be.
* This property has precedence over `redactViewTypes`.
*
* - Note: See ``SentryViewScreenshotOptions.init`` for the default value.
*/
public var unmaskedViewClasses: [AnyClass]
/**
* A set of view type identifier strings that should be excluded from subtree traversal.
*
* Views matching these types will have their subtrees skipped during redaction to avoid crashes
* caused by traversing problematic view hierarchies (e.g., views that activate internal CoreAnimation
* animations when their layers are accessed).
*
* Matching uses partial string containment: if a view's class name (from `type(of: view).description()`)
* contains any of these strings, the subtree will be ignored. For example, "MyView" will match
* "MyApp.MyView", "MyViewSubclass", "Some.MyView.Container", etc.
*
* - Note: You should use the methods ``excludeViewTypeFromSubtreeTraversal(_:)`` and ``includeViewTypeInSubtreeTraversal(_:)``
* to add and remove view types, so you do not accidentally remove our defaults.
* - Note: The final set of excluded view types is computed by `SentryViewSubtreeTraversal` using the formula:
* **Default View Classes + Excluded View Classes - Included View Classes**
* Default view classes are defined in `SentryViewSubtreeTraversal` (e.g., `CameraUI.ChromeSwiftUIView` on iOS 26+).
*/
public private(set) var excludedViewClasses: Set<String>
/**
* A set of view type identifier strings that should be included in subtree traversal.
*
* View types exactly matching these strings will be removed from the excluded set, allowing their subtrees
* to be traversed even if they would otherwise be excluded by default or via `excludedViewClasses`.
*
* Matching uses exact string matching: the view's class name (from `type(of: view).description()`)
* must exactly equal one of these strings. For example, "MyApp.MyView" will only match exactly "MyApp.MyView",
* not "MyApp.MyViewSubclass".
*
* - Note: You should use the methods ``excludeViewTypeFromSubtreeTraversal(_:)`` and ``includeViewTypeInSubtreeTraversal(_:)``
* to add and remove view types, so you do not accidentally remove our defaults.
* - Note: The final set of excluded view types is computed by `SentryViewSubtreeTraversal` using the formula:
* **Default View Classes + Excluded View Classes - Included View Classes**
* Default view classes are defined in `SentryViewSubtreeTraversal` (e.g., `CameraUI.ChromeSwiftUIView` on iOS 26+).
* For example, you can use this to re-enable traversal for `CameraUI.ChromeSwiftUIView` on iOS 26+
* by calling ``includeViewTypeInSubtreeTraversal("CameraUI.ChromeSwiftUIView")``.
* - Note: Included patterns use exact matching (not partial) to prevent accidental matches. For example,
* if "ChromeCameraUI" is excluded and "Camera" is included, "ChromeCameraUI" will still be excluded
* because "Camera" doesn't exactly match "ChromeCameraUI".
*/
public private(set) var includedViewClasses: Set<String>
/**
* Adds a view type pattern to the excluded set, preventing matching views' subtrees from being traversed.
*
* - Parameter viewType: The view type identifier pattern (as a string) to exclude from subtree traversal.
* Matching uses partial string containment: if a view's class name contains this string,
* the subtree will be ignored. For example, "MyView" will match "MyApp.MyView",
* "MyViewSubclass", etc.
*
* - Note: This method adds the pattern to `excludedViewClasses`, which is then combined with
* default excluded types (defined in `SentryViewSubtreeTraversal`) and filtered by `includedViewClasses`
* to produce the final set.
*/
public func excludeViewTypeFromSubtreeTraversal(_ viewType: String) {
excludedViewClasses.insert(viewType)
}
/**
* Adds a view type to the included set, allowing its subtree to be traversed.
*
* - Parameter viewType: The view type identifier (as a string) to include in subtree traversal.
* Must exactly match the result of `type(of: view).description()`.
* For example, "MyApp.MyView" will only match exactly "MyApp.MyView".
*
* - Note: This method adds the view type to `includedViewClasses`, which filters the combined set
* of default excluded types (defined in `SentryViewSubtreeTraversal`) and `excludedViewClasses`.
* For example, you can use this to re-enable traversal for `CameraUI.ChromeSwiftUIView` on iOS 26+.
* - Note: Included patterns use exact matching (not partial) to prevent accidental matches.
*/
public func includeViewTypeInSubtreeTraversal(_ viewType: String) {
includedViewClasses.insert(viewType)
}
/**
* Initialize screenshot options disabled
*
* - Note: This initializer is added for Objective-C compatibility, as constructors with default values
* are not supported in Objective-C.
* - Note: See ``SentryViewScreenshotOptions.DefaultValues`` for the default values of each parameter.
*/
public convenience override init() {
// Setting all properties to nil will fallback to the default values in the init method.
self.init(
enableViewRendererV2: DefaultValues.enableViewRendererV2,
enableFastViewRendering: DefaultValues.enableFastViewRendering,
maskAllText: DefaultValues.maskAllText,
maskAllImages: DefaultValues.maskAllImages,
maskedViewClasses: DefaultValues.maskedViewClasses,
unmaskedViewClasses: DefaultValues.unmaskedViewClasses,
excludedViewClasses: DefaultValues.excludedViewClasses,
includedViewClasses: DefaultValues.includedViewClasses
)
}
/**
* Initializes a new instance of ``SentryViewScreenshotOptions`` using a dictionary.
*
* - Parameter dictionary: A dictionary containing the configuration options for the screenshot.
*
* - Warning: This initializer is primarily used by Hybrid SDKs and is not intended for public use.
*/
convenience init(dictionary: [String: Any]) {
// This initializer is calling the one with optional parameters, so that defaults can be applied
// for absent values.
self.init(
enableViewRendererV2: (dictionary["enableViewRendererV2"] as? NSNumber)?.boolValue ?? DefaultValues.enableViewRendererV2,
enableFastViewRendering: (dictionary["enableFastViewRendering"] as? NSNumber)?.boolValue ?? DefaultValues.enableFastViewRendering,
maskAllText: (dictionary["maskAllText"] as? NSNumber)?.boolValue ?? DefaultValues.maskAllText,
maskAllImages: (dictionary["maskAllImages"] as? NSNumber)?.boolValue ?? DefaultValues.maskAllImages,
maskedViewClasses: (dictionary["maskedViewClasses"] as? NSArray)?.compactMap({ element in
NSClassFromString((element as? String) ?? "")
}) ?? DefaultValues.maskedViewClasses,
unmaskedViewClasses: (dictionary["unmaskedViewClasses"] as? NSArray)?.compactMap({ element in
NSClassFromString((element as? String) ?? "")
}) ?? DefaultValues.unmaskedViewClasses,
excludedViewClasses: (dictionary["excludedViewClasses"] as? [String]).map { Set($0) } ?? DefaultValues.excludedViewClasses,
includedViewClasses: (dictionary["includedViewClasses"] as? [String]).map { Set($0) } ?? DefaultValues.includedViewClasses
)
}
/**
* Initializes a new instance of ``SentryViewScreenshotOptions`` with the specified parameters.
*
* - Parameters:
* - enableViewRendererV2: Enables the up to 5x faster view renderer.
* - enableFastViewRendering: Enables faster but incomplete view rendering. See ``SentryViewScreenshotOptions.enableFastViewRendering`` for more information.
* - maskAllText: Flag to redact all text in the app by drawing a rectangle over it.
* - maskAllImages: Flag to redact all images in the app by drawing a rectangle over it.
* - maskedViewClasses: A list of custom UIView subclasses that need to be masked during the screenshot.
* - unmaskedViewClasses: A list of custom UIView subclasses to be ignored during masking step of the screenshot.
* - excludedViewClasses: A set of view type identifiers that should be excluded from subtree traversal.
* - includedViewClasses: A set of view type identifiers that should be included in subtree traversal.
*
* - Note: See ``SentryViewScreenshotOptions.DefaultValues`` for the default values of each parameter.
*/
public init(
enableViewRendererV2: Bool = DefaultValues.enableViewRendererV2,
enableFastViewRendering: Bool = DefaultValues.enableFastViewRendering,
maskAllText: Bool = DefaultValues.maskAllText,
maskAllImages: Bool = DefaultValues.maskAllImages,
maskedViewClasses: [AnyClass] = DefaultValues.maskedViewClasses,
unmaskedViewClasses: [AnyClass] = DefaultValues.unmaskedViewClasses,
excludedViewClasses: Set<String> = DefaultValues.excludedViewClasses,
includedViewClasses: Set<String> = DefaultValues.includedViewClasses
) {
// - This initializer is publicly available for Swift, but not for Objective-C, because automatically bridged Swift initializers
// with default values result in a single initializer requiring all parameters.
// - Each parameter has a default value, so the parameter can be omitted, which is not possible for Objective-C.
// - Parameter values are not optional, because SDK users should not be able to set them to nil.
// - The publicly available property `quality` is omitted in this initializer, because adding it would break backwards compatibility
// with the automatically bridged Objective-C initializer.
self.enableViewRendererV2 = enableViewRendererV2
self.enableFastViewRendering = enableFastViewRendering
self.maskAllText = maskAllText
self.maskAllImages = maskAllImages
self.maskedViewClasses = maskedViewClasses
self.unmaskedViewClasses = unmaskedViewClasses
self.excludedViewClasses = excludedViewClasses
self.includedViewClasses = includedViewClasses
super.init()
}
public override var description: String {
return "SentryViewScreenshotOptions(enableViewRendererV2: \(enableViewRendererV2), enableFastViewRendering: \(enableFastViewRendering), maskAllText: \(maskAllText), maskAllImages: \(maskAllImages), maskedViewClasses: \(maskedViewClasses), unmaskedViewClasses: \(unmaskedViewClasses), excludedViewClasses: \(excludedViewClasses), includedViewClasses: \(includedViewClasses))"
}
}
// swiftlint:enable missing_docs