Skip to content

Commit fed421b

Browse files
authored
Merge branch 'main' into antonis/rn-0.83.1
2 parents 414e1c4 + b1c9f15 commit fed421b

File tree

6 files changed

+122
-7
lines changed

6 files changed

+122
-7
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@
66
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
77
<!-- prettier-ignore-end -->
88
9+
## Unreleased
10+
11+
### Features
12+
13+
- Expose iOS options to ignore views from subtree traversal in version 8 ([#5663](https://github.com/getsentry/sentry-react-native/pull/5663))
14+
- Use `includedViewClasses` to only traverse specific view classes, or `excludedViewClasses` to skip problematic view classes during session replay and screenshot capture
15+
```js
16+
import * as Sentry from '@sentry/react-native';
17+
18+
Sentry.init({
19+
replaysSessionSampleRate: 1.0,
20+
integrations: [
21+
Sentry.mobileReplayIntegration({
22+
includedViewClasses: ['UILabel', 'UIView', 'MyCustomView'],
23+
excludedViewClasses: ['WKWebView', 'UIWebView'],
24+
}),
25+
],
26+
});
27+
```
28+
929
## 8.0.0
1030

1131
### Upgrading from 7.x to 8.0

packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ final class RNSentryReplayOptions: XCTestCase {
4848
}
4949

5050
func assertAllDefaultReplayOptionsAreNotNil(replayOptions: [String: Any]) {
51-
XCTAssertEqual(replayOptions.count, 9)
51+
XCTAssertEqual(replayOptions.count, 11)
5252
XCTAssertNotNil(replayOptions["sessionSampleRate"])
5353
XCTAssertNotNil(replayOptions["errorSampleRate"])
5454
XCTAssertNotNil(replayOptions["maskAllImages"])
@@ -58,6 +58,8 @@ final class RNSentryReplayOptions: XCTestCase {
5858
XCTAssertNotNil(replayOptions["enableViewRendererV2"])
5959
XCTAssertNotNil(replayOptions["enableFastViewRendering"])
6060
XCTAssertNotNil(replayOptions["quality"])
61+
XCTAssertNotNil(replayOptions["includedViewClasses"])
62+
XCTAssertNotNil(replayOptions["excludedViewClasses"])
6163
}
6264

6365
func testSessionSampleRate() {
@@ -318,4 +320,64 @@ final class RNSentryReplayOptions: XCTestCase {
318320

319321
XCTAssertEqual(actualOptions.sessionReplay.quality, SentryReplayOptions.SentryReplayQuality.medium)
320322
}
323+
324+
func testIncludedViewClasses() {
325+
let optionsDict = ([
326+
"dsn": "https://abc@def.ingest.sentry.io/1234567",
327+
"replaysOnErrorSampleRate": 0.75,
328+
"mobileReplayOptions": [ "includedViewClasses": ["UILabel", "UIView", "UITextView"] ]
329+
] as NSDictionary).mutableCopy() as! NSMutableDictionary
330+
331+
RNSentryReplay.updateOptions(optionsDict)
332+
333+
let actualOptions = try! PrivateSentrySDKOnly.options(with: optionsDict as! [String: Any])
334+
335+
let includedViewClasses = actualOptions.sessionReplay.includedViewClasses
336+
XCTAssertEqual(includedViewClasses.count, 3)
337+
XCTAssertTrue(includedViewClasses.contains("UILabel"))
338+
XCTAssertTrue(includedViewClasses.contains("UIView"))
339+
XCTAssertTrue(includedViewClasses.contains("UITextView"))
340+
}
341+
342+
func testExcludedViewClasses() {
343+
let optionsDict = ([
344+
"dsn": "https://abc@def.ingest.sentry.io/1234567",
345+
"replaysOnErrorSampleRate": 0.75,
346+
"mobileReplayOptions": [ "excludedViewClasses": ["UICollectionView", "UITableView", "UIScrollView"] ]
347+
] as NSDictionary).mutableCopy() as! NSMutableDictionary
348+
349+
RNSentryReplay.updateOptions(optionsDict)
350+
351+
let actualOptions = try! PrivateSentrySDKOnly.options(with: optionsDict as! [String: Any])
352+
353+
let excludedViewClasses = actualOptions.sessionReplay.excludedViewClasses
354+
XCTAssertEqual(excludedViewClasses.count, 3)
355+
XCTAssertTrue(excludedViewClasses.contains("UICollectionView"))
356+
XCTAssertTrue(excludedViewClasses.contains("UITableView"))
357+
XCTAssertTrue(excludedViewClasses.contains("UIScrollView"))
358+
}
359+
360+
func testIncludedAndExcludedViewClasses() {
361+
let optionsDict = ([
362+
"dsn": "https://abc@def.ingest.sentry.io/1234567",
363+
"replaysOnErrorSampleRate": 0.75,
364+
"mobileReplayOptions": [
365+
"includedViewClasses": ["UILabel", "UIView"],
366+
"excludedViewClasses": ["UICollectionView"]
367+
]
368+
] as NSDictionary).mutableCopy() as! NSMutableDictionary
369+
370+
RNSentryReplay.updateOptions(optionsDict)
371+
372+
let actualOptions = try! PrivateSentrySDKOnly.options(with: optionsDict as! [String: Any])
373+
374+
let includedViewClasses = actualOptions.sessionReplay.includedViewClasses
375+
XCTAssertEqual(includedViewClasses.count, 2)
376+
XCTAssertTrue(includedViewClasses.contains("UILabel"))
377+
XCTAssertTrue(includedViewClasses.contains("UIView"))
378+
379+
let excludedViewClasses = actualOptions.sessionReplay.excludedViewClasses
380+
XCTAssertEqual(excludedViewClasses.count, 1)
381+
XCTAssertTrue(excludedViewClasses.contains("UICollectionView"))
382+
}
321383
}

packages/core/ios/RNSentryReplay.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ + (BOOL)updateOptions:(NSMutableDictionary *)options
2727

2828
NSString *qualityString = options[@"replaysSessionQuality"];
2929

30+
NSArray *includedViewClasses = replayOptions[@"includedViewClasses"];
31+
NSArray *excludedViewClasses = replayOptions[@"excludedViewClasses"];
32+
3033
[options setValue:@{
3134
@"sessionSampleRate" : sessionSampleRate ?: [NSNull null],
3235
@"errorSampleRate" : errorSampleRate ?: [NSNull null],
@@ -36,6 +39,8 @@ + (BOOL)updateOptions:(NSMutableDictionary *)options
3639
@"enableViewRendererV2" : replayOptions[@"enableViewRendererV2"] ?: [NSNull null],
3740
@"enableFastViewRendering" : replayOptions[@"enableFastViewRendering"] ?: [NSNull null],
3841
@"maskedViewClasses" : [RNSentryReplay getReplayRNRedactClasses:replayOptions],
42+
@"includedViewClasses" : includedViewClasses ?: [NSNull null],
43+
@"excludedViewClasses" : excludedViewClasses ?: [NSNull null],
3944
@"sdkInfo" :
4045
@ { @"name" : REACT_NATIVE_SDK_NAME, @"version" : REACT_NATIVE_SDK_PACKAGE_VERSION }
4146
}

packages/core/src/js/replay/mobilereplay.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@ export interface MobileReplayOptions {
8181
*/
8282
enableFastViewRendering?: boolean;
8383

84+
/**
85+
* Array of view class names to include in subtree traversal during session replay and screenshot capture on iOS.
86+
*
87+
* Only views that are instances of these classes (or subclasses) will be traversed.
88+
* This helps prevent crashes when traversing problematic view hierarchies by allowing you to explicitly include only safe view classes.
89+
*
90+
* If both `includedViewClasses` and `excludedViewClasses` are set, `excludedViewClasses` takes precedence:
91+
* views matching excluded classes won't be traversed even if they match an included class.
92+
*
93+
* @default undefined
94+
* @platform ios
95+
*/
96+
includedViewClasses?: string[];
97+
98+
/**
99+
* Array of view class names to exclude from subtree traversal during session replay and screenshot capture on iOS.
100+
*
101+
* Views of these classes (or subclasses) will be skipped entirely, including all their children.
102+
* This helps prevent crashes when traversing problematic view hierarchies by allowing you to explicitly exclude problematic view classes.
103+
*
104+
* If both `includedViewClasses` and `excludedViewClasses` are set, `excludedViewClasses` takes precedence:
105+
* views matching excluded classes won't be traversed even if they match an included class.
106+
*
107+
* @default undefined
108+
* @platform ios
109+
*/
110+
excludedViewClasses?: string[];
111+
84112
/**
85113
* Sets the screenshot strategy used by the Session Replay integration on Android.
86114
*

performance-tests/Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ GEM
4646
dotenv (2.8.1)
4747
emoji_regex (3.2.3)
4848
excon (0.112.0)
49-
faraday (1.10.4)
49+
faraday (1.10.5)
5050
faraday-em_http (~> 1.0)
5151
faraday-em_synchrony (~> 1.0)
5252
faraday-excon (~> 1.1)
@@ -65,7 +65,7 @@ GEM
6565
faraday-em_synchrony (1.0.1)
6666
faraday-excon (1.1.0)
6767
faraday-httpclient (1.0.1)
68-
faraday-multipart (1.1.1)
68+
faraday-multipart (1.2.0)
6969
multipart-post (~> 2.0)
7070
faraday-net_http (1.0.2)
7171
faraday-net_http_persistent (1.2.0)

samples/react-native/Gemfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ GEM
9797
ethon (0.16.0)
9898
ffi (>= 1.15.0)
9999
excon (0.109.0)
100-
faraday (1.10.4)
100+
faraday (1.10.5)
101101
faraday-em_http (~> 1.0)
102102
faraday-em_synchrony (~> 1.0)
103103
faraday-excon (~> 1.1)
@@ -113,11 +113,11 @@ GEM
113113
faraday (>= 0.8.0)
114114
http-cookie (~> 1.0.0)
115115
faraday-em_http (1.0.0)
116-
faraday-em_synchrony (1.0.0)
116+
faraday-em_synchrony (1.0.1)
117117
faraday-excon (1.1.0)
118118
faraday-httpclient (1.0.1)
119-
faraday-multipart (1.0.4)
120-
multipart-post (~> 2)
119+
faraday-multipart (1.2.0)
120+
multipart-post (~> 2.0)
121121
faraday-net_http (1.0.2)
122122
faraday-net_http_persistent (1.2.0)
123123
faraday-patron (1.0.0)

0 commit comments

Comments
 (0)