From 0fc1b429022d4c0edf8c2539b653bee47cb4e58b Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 31 Oct 2024 17:13:31 +0100 Subject: [PATCH 01/39] feat(replay): Add SentryMask and SentryUnmask native components --- packages/core/ios/RNSentryReplay.m | 2 ++ packages/core/ios/Replay/RNSentryReplayMask.h | 8 +++++ packages/core/ios/Replay/RNSentryReplayMask.m | 16 +++++++++ .../core/ios/Replay/RNSentryReplayUnmask.h | 8 +++++ .../core/ios/Replay/RNSentryReplayUnmask.m | 16 +++++++++ packages/core/src/js/index.ts | 2 ++ packages/core/src/js/replay/customRedact.tsx | 34 +++++++++++++++++++ .../src/Screens/PlaygroundScreen.tsx | 10 ++++++ 8 files changed, 96 insertions(+) create mode 100644 packages/core/ios/Replay/RNSentryReplayMask.h create mode 100644 packages/core/ios/Replay/RNSentryReplayMask.m create mode 100644 packages/core/ios/Replay/RNSentryReplayUnmask.h create mode 100644 packages/core/ios/Replay/RNSentryReplayUnmask.m create mode 100644 packages/core/src/js/replay/customRedact.tsx diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index de6a0c240e..d52a4908f1 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -1,5 +1,6 @@ #import "RNSentryReplay.h" #import "RNSentryReplayBreadcrumbConverter.h" +#import "React/RCTTextView.h" #if SENTRY_TARGET_REPLAY_SUPPORTED @@ -53,6 +54,7 @@ + (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { } } if ([replayOptions[@"maskAllText"] boolValue] == YES) { + [classesToRedact addObject:[RCTTextView self]]; Class _Nullable maybeRCTTextClass = NSClassFromString(@"RCTTextView"); if (maybeRCTTextClass != nil) { [classesToRedact addObject:maybeRCTTextClass]; diff --git a/packages/core/ios/Replay/RNSentryReplayMask.h b/packages/core/ios/Replay/RNSentryReplayMask.h new file mode 100644 index 0000000000..a5d46bc477 --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayMask.h @@ -0,0 +1,8 @@ +#import +#import + +@interface RNSentryReplayMaskManager : RCTViewManager +@end + +@interface RNSentryReplayMask : RCTView +@end diff --git a/packages/core/ios/Replay/RNSentryReplayMask.m b/packages/core/ios/Replay/RNSentryReplayMask.m new file mode 100644 index 0000000000..4f0cb7f1cc --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayMask.m @@ -0,0 +1,16 @@ +#import "RNSentryReplayMask.h" + +@implementation RNSentryReplayMaskManager + +RCT_EXPORT_MODULE(RNSentryReplayMask) + +- (UIView *)view +{ + return [RNSentryReplayMask new]; +} + +@end + +@implementation RNSentryReplayMask + +@end diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.h b/packages/core/ios/Replay/RNSentryReplayUnmask.h new file mode 100644 index 0000000000..9c4268b526 --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.h @@ -0,0 +1,8 @@ +#import +#import + +@interface RNSentryReplayUnmaskManager : RCTViewManager +@end + +@interface RNSentryReplayUnmask : RCTView +@end diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.m b/packages/core/ios/Replay/RNSentryReplayUnmask.m new file mode 100644 index 0000000000..f0a018a82b --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.m @@ -0,0 +1,16 @@ +#import "RNSentryReplayUnmask.h" + +@implementation RNSentryReplayUnmaskManager + +RCT_EXPORT_MODULE(RNSentryReplayUnmask) + +- (UIView *)view +{ + return [RNSentryReplayUnmask new]; +} + +@end + +@implementation RNSentryReplayUnmask + +@end diff --git a/packages/core/src/js/index.ts b/packages/core/src/js/index.ts index f3053cca3b..f3112a86aa 100644 --- a/packages/core/src/js/index.ts +++ b/packages/core/src/js/index.ts @@ -74,3 +74,5 @@ export { } from './tracing'; export type { TimeToDisplayProps } from './tracing'; + +export { SentryMask, SentryUnmask } from './replay/customRedact'; diff --git a/packages/core/src/js/replay/customRedact.tsx b/packages/core/src/js/replay/customRedact.tsx new file mode 100644 index 0000000000..b5ff2b058b --- /dev/null +++ b/packages/core/src/js/replay/customRedact.tsx @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { UIManager, View, ViewProps } from 'react-native'; +import { logger } from '@sentry/utils'; + +import { ReactNativeLibraries } from '../utils/rnlibraries'; +import { HostComponent } from '../vendor/react-native'; + +function requireNativeComponent(viewName: string): HostComponent | null { + if (!UIManager.hasViewManagerConfig) { + logger.warn(`[SentrySessionReplay] Can't load ${viewName}. UIManager.hasViewManagerConfig is not available`); + return null; + } + + if (!UIManager.hasViewManagerConfig(viewName)) { + logger.warn(`[SentrySessionReplay] Can't load ${viewName}. UIManager.hasViewManagerConfig(${viewName}) is not available`); + return null; + } + + if (!ReactNativeLibraries.ReactNative?.requireNativeComponent) { + logger.warn(`[SentrySessionReplay] Can't load ${viewName}. requireNativeComponent from 'react-native' is not available`); + return null; + } + + return ReactNativeLibraries.ReactNative.requireNativeComponent(viewName); +} + +const NativeSentryMask = requireNativeComponent('RNSentryReplayMask'); +const NativeSentryUnmask = requireNativeComponent('RNSentryReplayUnmask'); + +const FallbackSentryMask = (props: ViewProps) => ; +const FallbackSentryUnmask = (props: ViewProps) => ; + +export const SentryMask = NativeSentryMask || FallbackSentryMask; +export const SentryUnmask = NativeSentryUnmask || FallbackSentryUnmask; diff --git a/samples/react-native/src/Screens/PlaygroundScreen.tsx b/samples/react-native/src/Screens/PlaygroundScreen.tsx index 1a128eb9e6..3c336dae27 100644 --- a/samples/react-native/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native/src/Screens/PlaygroundScreen.tsx @@ -16,6 +16,7 @@ import { } from 'react-native'; import SvgGraphic from '../components/SvgGraphic'; import { StackNavigationProp } from '@react-navigation/stack'; +import { SentryMask, SentryUnmask } from '@sentry/react-native'; const multilineText = `This is @@ -42,6 +43,15 @@ const PlaygroundScreen = (props: Props) => { props.navigation.navigate('Webview'); }} /> + Custom Mask: + + + This is masked + + This is unmasked + + + Text: {'This is '} From 9933a86fb676867feca828f7bf38c9d5702b7786 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 4 Nov 2024 14:53:45 +0100 Subject: [PATCH 02/39] add clang-format --- .clang-format | 6 ++++++ package.json | 8 +++++-- scripts/clang-format.sh | 47 +++++++++++++++++++++++++++++++++++++++++ yarn.lock | 18 +++++++++++++++- 4 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 .clang-format create mode 100755 scripts/clang-format.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..45e033d570 --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +BasedOnStyle: WebKit +IndentWidth: 4 +IndentPPDirectives: AfterHash +ColumnLimit: 100 +AlwaysBreakAfterDefinitionReturnType: All +PointerAlignment: Right diff --git a/package.json b/package.json index 9d48508851..7dfaed4c81 100644 --- a/package.json +++ b/package.json @@ -7,20 +7,24 @@ "clean": "lerna run clean", "circularDepCheck": "lerna run circularDepCheck", "test": "lerna run test", - "fix": "run-s fix:lerna fix:android", + "fix": "run-s fix:lerna fix:android fix:clang", "fix:lerna": "lerna run fix", "fix:android": "run-s 'java:format fix' java:pmd", - "lint": "run-s lint:lerna lint:android", + "fix:clang": "run-s 'clang:format fix'", + "lint": "run-s lint:lerna lint:android lint:clang", "lint:lerna": "lerna run lint", "lint:android": "run-s 'java:format lint' java:pmd", + "lint:clang": "run-s 'clang:format lint'", "java:format": "./scripts/google-java-format.sh", "java:pmd": "./scripts/pmd.sh", + "clang:format": "./scripts/clang-format.sh", "run-ios": "cd samples/react-native && yarn react-native run-ios", "run-android": "cd samples/react-native && yarn react-native run-android", "set-version-samples": "lerna run set-version" }, "devDependencies": { "@sentry/cli": "2.38.1", + "clang-format": "^1.8.0", "downlevel-dts": "^0.11.0", "google-java-format": "^1.4.0", "lerna": "^8.1.8", diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh new file mode 100755 index 0000000000..9f6aef5ec2 --- /dev/null +++ b/scripts/clang-format.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -eo pipefail + +# Check if an argument is provided +if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Set the mode based on the first argument +mode=$1 + +# Base command +cmd="find . -type f \( \ + -name \"*.h\" -or \ + -name \"*.hpp\" -or \ + -name \"*.c\" -or \ + -name \"*.cpp\" -or \ + -name \"*.m\" -or \ + -name \"*.mm\" \) -and \ + ! \( \ + -path \"**.build/*\" -or \ + -path \"**Build/*\" -or \ + -path \"**ios/build/**\" -or \ + -path \"**android/build/**\" -or \ + -path \"**build/generated/**\" -or \ + -path \"**/Carthage/Checkouts/*\" -or \ + -path \"**/libs/**\" -or \ + -path \"**/.yalc/**\" -or \ + -path \"**/node_modules/**\" -or \ + -path \"**/gems/**\" -or \ + -path \"**/Pods/**\" \) \ + | xargs npx clang-format --Werror --verbose -i -style=file" + +# Add --replace flag if mode is 'fix' +if [ "$mode" = "fix" ]; then + echo "clang-format fixing files..." +elif [ "$mode" = "lint" ]; then + echo "clang-format lint files..." + cmd+=" --dry-run" +else + echo "Invalid mode. Use 'fix' or 'lint'." + exit 1 +fi + +eval $cmd diff --git a/yarn.lock b/yarn.lock index e46db0e1e9..8dd14c4875 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10230,6 +10230,21 @@ __metadata: languageName: node linkType: hard +"clang-format@npm:^1.8.0": + version: 1.8.0 + resolution: "clang-format@npm:1.8.0" + dependencies: + async: ^3.2.3 + glob: ^7.0.0 + resolve: ^1.1.6 + bin: + check-clang-format: bin/check-clang-format.js + clang-format: index.js + git-clang-format: bin/git-clang-format + checksum: 8e4198e976e8ca1dcb6f7eba09db89db44ce39c326a249b1a28ea2b3fd7dc5ece389d328bb9781424a708e63044b1432d85b9d8f65c46d3d5c13d2b6bf745a50 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -22267,7 +22282,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.22.8#~builtin, resolve@patch:resolve@npm%3A^1.1.6#~builtin, resolve@patch:resolve@npm%3A^1.10.0#~builtin, resolve@patch:resolve@npm%3A^1.14.2#~builtin, resolve@patch:resolve@npm%3A^1.20.0#~builtin, resolve@patch:resolve@npm%3A^1.21.0#~builtin, resolve@patch:resolve@npm%3A^1.22.2#~builtin, resolve@patch:resolve@npm%3A^1.22.4#~builtin, resolve@patch:resolve@npm%3A^1.22.8#~builtin": +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.10.1#~builtin, resolve@patch:resolve@^1.22.8#~builtin, resolve@patch:resolve@npm%3A^1.1.6#~builtin, resolve@patch:resolve@npm%3A^1.10.0#~builtin, resolve@patch:resolve@npm%3A^1.14.2#~builtin, resolve@patch:resolve@npm%3A^1.20.0#~builtin, resolve@patch:resolve@npm%3A^1.21.0#~builtin, resolve@patch:resolve@npm%3A^1.22.2#~builtin, resolve@patch:resolve@npm%3A^1.22.4#~builtin, resolve@patch:resolve@npm%3A^1.22.8#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -22877,6 +22892,7 @@ __metadata: resolution: "sentry-react-native@workspace:." dependencies: "@sentry/cli": 2.38.1 + clang-format: ^1.8.0 downlevel-dts: ^0.11.0 google-java-format: ^1.4.0 lerna: ^8.1.8 From e17ac3150e2254898eba98b327fa2e37ff53b431 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 4 Nov 2024 15:07:01 +0100 Subject: [PATCH 03/39] apply the formatter --- ...RNSentryCocoaTesterTests-Bridging-Header.h | 2 +- .../RNSentryDependencyContainerTests.h | 4 +- .../RNSentryDependencyContainerTests.m | 21 +- .../RNSentryFramesTrackerListenerTests.h | 4 +- .../RNSentryFramesTrackerListenerTests.m | 74 +- .../RNSentryOnDrawReporterTests.m | 6 +- .../RNSentryCocoaTesterTests/RNSentryTests.h | 2 +- .../RNSentryCocoaTesterTests/RNSentryTests.mm | 476 +++++++------ packages/core/ios/RNSentry.h | 23 +- packages/core/ios/RNSentry.mm | 662 ++++++++++-------- packages/core/ios/RNSentryBreadcrumb.h | 4 +- packages/core/ios/RNSentryBreadcrumb.m | 13 +- .../core/ios/RNSentryDependencyContainer.h | 4 +- .../core/ios/RNSentryDependencyContainer.m | 13 +- .../core/ios/RNSentryFramesTrackerListener.h | 12 +- .../core/ios/RNSentryFramesTrackerListener.m | 18 +- packages/core/ios/RNSentryId.m | 3 +- packages/core/ios/RNSentryOnDrawReporter.h | 10 +- packages/core/ios/RNSentryOnDrawReporter.m | 50 +- packages/core/ios/RNSentryRNSScreen.h | 2 +- packages/core/ios/RNSentryRNSScreen.m | 36 +- packages/core/ios/RNSentryReplay.m | 105 +-- .../ios/RNSentryReplayBreadcrumbConverter.h | 7 +- .../ios/RNSentryReplayBreadcrumbConverter.m | 271 +++---- packages/core/ios/RNSentryTimeToDisplay.m | 43 +- .../jni/MainApplicationModuleProvider.cpp | 40 +- .../main/jni/MainApplicationModuleProvider.h | 5 +- ...nApplicationTurboModuleManagerDelegate.cpp | 65 +- ...ainApplicationTurboModuleManagerDelegate.h | 49 +- .../src/main/jni/MainComponentsRegistry.cpp | 81 ++- .../app/src/main/jni/MainComponentsRegistry.h | 27 +- .../android/app/src/main/jni/OnLoad.cpp | 15 +- .../ios/TestAppPlain/AppDelegate.mm | 121 ++-- .../TestAppPlain/ios/TestAppPlain/main.m | 9 +- .../ios/TestAppPlainTests/TestAppPlainTests.m | 64 +- .../jni/MainApplicationModuleProvider.cpp | 40 +- .../main/jni/MainApplicationModuleProvider.h | 5 +- ...nApplicationTurboModuleManagerDelegate.cpp | 65 +- ...ainApplicationTurboModuleManagerDelegate.h | 49 +- .../src/main/jni/MainComponentsRegistry.cpp | 81 ++- .../app/src/main/jni/MainComponentsRegistry.h | 27 +- .../android/app/src/main/jni/OnLoad.cpp | 15 +- .../ios/TestAppSentry/AppDelegate.mm | 121 ++-- .../TestAppSentry/ios/TestAppSentry/main.m | 9 +- .../TestAppSentryTests/TestAppSentryTests.m | 64 +- .../AppDelegate.h | 2 +- .../AppDelegate.mm | 18 +- .../sentry-react-native-sample-macOS/main.m | 6 +- .../android/app/src/main/jni/OnLoad.cpp | 138 ++-- .../sentryreactnativesample/AppDelegate.mm | 102 +-- .../NativePlatformSampleModule.h | 2 +- .../NativePlatformSampleModule.mm | 15 +- .../sentryreactnativesample/RCTAssetsModule.m | 27 +- .../ios/sentryreactnativesample/main.m | 9 +- .../sentryreactnativesampleTests.m | 64 +- .../react-native/tm/NativeSampleModule.cpp | 16 +- samples/react-native/tm/NativeSampleModule.h | 14 +- 57 files changed, 1686 insertions(+), 1544 deletions(-) diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h index e177d453fb..6b949b5967 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h @@ -2,5 +2,5 @@ // Use this file to import your target's public headers that you would like to expose to Swift. // -#import "RNSentryReplayBreadcrumbConverter.h" #import "RNSentryBreadcrumb.h" +#import "RNSentryReplayBreadcrumbConverter.h" diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.h index 9d98d08b4a..3b3055e2f3 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.h @@ -1,10 +1,10 @@ +#import "SentryFramesTracker.h" #import #import -#import "SentryFramesTracker.h" @interface SentrySDK (PrivateTests) -- (nullable SentryOptions *) options; +- (nullable SentryOptions *)options; @end @interface SentryDependencyContainer : NSObject diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.m b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.m index 4bed149b72..ab81eb658b 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.m +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.m @@ -1,8 +1,8 @@ #import "RNSentryDependencyContainerTests.h" +#import "RNSentryDependencyContainer.h" #import #import #import -#import "RNSentryDependencyContainer.h" @interface RNSentryDependencyContainerTests : XCTestCase @@ -12,17 +12,20 @@ @implementation RNSentryDependencyContainerTests - (void)testRNSentryDependencyContainerInitializesFrameTracker { - XCTAssertNil([[RNSentryDependencyContainer sharedInstance] framesTrackerListener]); + XCTAssertNil([[RNSentryDependencyContainer sharedInstance] framesTrackerListener]); - id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); - OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])).andReturn(sentryDependencyContainerMock); + id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); + OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])) + .andReturn(sentryDependencyContainerMock); - id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); - OCMStub([(SentryDependencyContainer*) sentryDependencyContainerMock framesTracker]).andReturn(frameTrackerMock); + id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); + OCMStub([(SentryDependencyContainer *)sentryDependencyContainerMock framesTracker]) + .andReturn(frameTrackerMock); - RNSentryEmitNewFrameEvent emitNewFrameEvent = ^(NSNumber *newFrameTimestampInSeconds) {}; - [[RNSentryDependencyContainer sharedInstance] initializeFramesTrackerListenerWith: emitNewFrameEvent]; - XCTAssertNotNil([[RNSentryDependencyContainer sharedInstance] framesTrackerListener]); + RNSentryEmitNewFrameEvent emitNewFrameEvent = ^(NSNumber *newFrameTimestampInSeconds) {}; + [[RNSentryDependencyContainer sharedInstance] + initializeFramesTrackerListenerWith:emitNewFrameEvent]; + XCTAssertNotNil([[RNSentryDependencyContainer sharedInstance] framesTrackerListener]); } @end diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.h index 9d98d08b4a..3b3055e2f3 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.h @@ -1,10 +1,10 @@ +#import "SentryFramesTracker.h" #import #import -#import "SentryFramesTracker.h" @interface SentrySDK (PrivateTests) -- (nullable SentryOptions *) options; +- (nullable SentryOptions *)options; @end @interface SentryDependencyContainer : NSObject diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.m b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.m index 2a3336fb25..ee33d109e4 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.m +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.m @@ -1,8 +1,8 @@ #import "RNSentryFramesTrackerListenerTests.h" +#import "RNSentryDependencyContainer.h" #import #import #import -#import "RNSentryDependencyContainer.h" @interface RNSentryFramesTrackerListenerTests : XCTestCase @@ -12,58 +12,68 @@ @implementation RNSentryFramesTrackerListenerTests - (void)testRNSentryFramesTrackerCallsGivenEventEmitterOnNewFrame { - id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); - OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])).andReturn(sentryDependencyContainerMock); + id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); + OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])) + .andReturn(sentryDependencyContainerMock); - id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); - OCMStub([(SentryDependencyContainer*) sentryDependencyContainerMock framesTracker]).andReturn(frameTrackerMock); + id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); + OCMStub([(SentryDependencyContainer *)sentryDependencyContainerMock framesTracker]) + .andReturn(frameTrackerMock); - XCTestExpectation *blockExpectation = [self expectationWithDescription:@"Block Expectation"]; + XCTestExpectation *blockExpectation = [self expectationWithDescription:@"Block Expectation"]; - RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) { - XCTAssertTrue([newFrameTimestampInSeconds isKindOfClass:[NSNumber class]], @"The variable should be of type NSNumber."); - [blockExpectation fulfill]; - }; + RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) { + XCTAssertTrue([newFrameTimestampInSeconds isKindOfClass:[NSNumber class]], + @"The variable should be of type NSNumber."); + [blockExpectation fulfill]; + }; - RNSentryFramesTrackerListener* actualListener = [[RNSentryFramesTrackerListener alloc] initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] - andEventEmitter: mockEventEmitter]; + RNSentryFramesTrackerListener *actualListener = [[RNSentryFramesTrackerListener alloc] + initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] + andEventEmitter:mockEventEmitter]; - [actualListener framesTrackerHasNewFrame: [NSDate date]]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [actualListener framesTrackerHasNewFrame:[NSDate date]]; + [self waitForExpectationsWithTimeout:1.0 handler:nil]; } - (void)testRNSentryFramesTrackerIsOneTimeListener { - id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); - OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])).andReturn(sentryDependencyContainerMock); + id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); + OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])) + .andReturn(sentryDependencyContainerMock); - id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); - OCMStub([(SentryDependencyContainer*) sentryDependencyContainerMock framesTracker]).andReturn(frameTrackerMock); + id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); + OCMStub([(SentryDependencyContainer *)sentryDependencyContainerMock framesTracker]) + .andReturn(frameTrackerMock); - RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) {}; + RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) {}; - RNSentryFramesTrackerListener* actualListener = [[RNSentryFramesTrackerListener alloc] initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] - andEventEmitter: mockEventEmitter]; + RNSentryFramesTrackerListener *actualListener = [[RNSentryFramesTrackerListener alloc] + initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] + andEventEmitter:mockEventEmitter]; - [actualListener framesTrackerHasNewFrame: [NSDate date]]; - OCMVerify([frameTrackerMock removeListener:actualListener]); + [actualListener framesTrackerHasNewFrame:[NSDate date]]; + OCMVerify([frameTrackerMock removeListener:actualListener]); } - (void)testRNSentryFramesTrackerAddsItselfAsListener { - id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); - OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])).andReturn(sentryDependencyContainerMock); + id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); + OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])) + .andReturn(sentryDependencyContainerMock); - id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); - OCMStub([(SentryDependencyContainer*) sentryDependencyContainerMock framesTracker]).andReturn(frameTrackerMock); + id frameTrackerMock = OCMClassMock([SentryFramesTracker class]); + OCMStub([(SentryDependencyContainer *)sentryDependencyContainerMock framesTracker]) + .andReturn(frameTrackerMock); - RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) {}; + RNSentryEmitNewFrameEvent mockEventEmitter = ^(NSNumber *newFrameTimestampInSeconds) {}; - RNSentryFramesTrackerListener* actualListener = [[RNSentryFramesTrackerListener alloc] initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] - andEventEmitter: mockEventEmitter]; + RNSentryFramesTrackerListener *actualListener = [[RNSentryFramesTrackerListener alloc] + initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] + andEventEmitter:mockEventEmitter]; - [actualListener startListening]; - OCMVerify([frameTrackerMock addListener:actualListener]); + [actualListener startListening]; + OCMVerify([frameTrackerMock addListener:actualListener]); } @end diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryOnDrawReporterTests.m b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryOnDrawReporterTests.m index 022dc89951..13de6a12c9 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryOnDrawReporterTests.m +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryOnDrawReporterTests.m @@ -1,5 +1,5 @@ -#import #import "RNSentryOnDrawReporter.h" +#import @interface RNSentryOnDrawReporterTests : XCTestCase @@ -9,8 +9,8 @@ @implementation RNSentryOnDrawReporterTests - (void)testRNSentryOnDrawReporterViewIsAvailableWhenUIKitIs { - RNSentryOnDrawReporterView* view = [[RNSentryOnDrawReporterView alloc] init]; - XCTAssertNotNil(view); + RNSentryOnDrawReporterView *view = [[RNSentryOnDrawReporterView alloc] init]; + XCTAssertNotNil(view); } @end diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.h index 47d5e60493..8c2fddad03 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.h @@ -3,7 +3,7 @@ @interface SentrySDK (PrivateTests) -- (nullable SentryOptions *) options; +- (nullable SentryOptions *)options; @end @interface SentryBinaryImageInfo : NSObject diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.mm b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.mm index 1ef91af466..297022311e 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.mm +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.mm @@ -1,8 +1,8 @@ #import "RNSentryTests.h" #import +#import #import #import -#import @interface RNSentryInitNativeSdkTests : XCTestCase @@ -12,176 +12,195 @@ @implementation RNSentryInitNativeSdkTests - (void)testCreateOptionsWithDictionaryRemovesPerformanceProperties { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; - - NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"beforeSend": @"will_be_overwritten", - @"tracesSampleRate": @1, - @"tracesSampler": ^(SentrySamplingContext *_Nonnull samplingContext) { - return @1; - }, - @"enableTracing": @YES, - }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; - - XCTAssertNotNil(actualOptions, @"Did not create sentry options"); - XCTAssertNil(error, @"Should not pass no error"); - XCTAssertNotNil(actualOptions.beforeSend, @"Before send is overwriten by the native RNSentry implementation"); - XCTAssertEqual(actualOptions.tracesSampleRate, nil, @"Traces sample rate should not be passed to native"); - XCTAssertEqual(actualOptions.tracesSampler, nil, @"Traces sampler should not be passed to native"); - XCTAssertEqual(actualOptions.enableTracing, false, @"EnableTracing should not be passed to native"); + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; + + NSDictionary *_Nonnull mockedReactNativeDictionary = + @{ @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"beforeSend" : @"will_be_overwritten", + @"tracesSampleRate" : @1, + @"tracesSampler" : ^(SentrySamplingContext *_Nonnull samplingContext) { return @1; +} +, @"enableTracing" : @YES, +} +; +SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; + +XCTAssertNotNil(actualOptions, @"Did not create sentry options"); +XCTAssertNil(error, @"Should not pass no error"); +XCTAssertNotNil( + actualOptions.beforeSend, @"Before send is overwriten by the native RNSentry implementation"); +XCTAssertEqual( + actualOptions.tracesSampleRate, nil, @"Traces sample rate should not be passed to native"); +XCTAssertEqual(actualOptions.tracesSampler, nil, @"Traces sampler should not be passed to native"); +XCTAssertEqual(actualOptions.enableTracing, false, @"EnableTracing should not be passed to native"); } - (void)testCreateOptionsWithDictionaryNativeCrashHandlingDefault { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], true, @"Did not set native crash handling"); + XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], true, + @"Did not set native crash handling"); } - (void)testCreateOptionsWithDictionaryAutoPerformanceTracingDefault { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual(actualOptions.enableAutoPerformanceTracing, true, @"Did not set Auto Performance Tracing"); + XCTAssertEqual( + actualOptions.enableAutoPerformanceTracing, true, @"Did not set Auto Performance Tracing"); } - (void)testCreateOptionsWithDictionaryNativeCrashHandlingEnabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"enableNativeCrashHandling": @YES, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"enableNativeCrashHandling" : @YES, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], true, @"Did not set native crash handling"); + XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], true, + @"Did not set native crash handling"); } - (void)testCreateOptionsWithDictionaryAutoPerformanceTracingEnabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"enableAutoPerformanceTracing": @YES, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"enableAutoPerformanceTracing" : @YES, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual(actualOptions.enableAutoPerformanceTracing, true, @"Did not set Auto Performance Tracing"); + XCTAssertEqual( + actualOptions.enableAutoPerformanceTracing, true, @"Did not set Auto Performance Tracing"); } - (void)testCreateOptionsWithDictionaryNativeCrashHandlingDisabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"enableNativeCrashHandling": @NO, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"enableNativeCrashHandling" : @NO, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], false, @"Did not disable native crash handling"); + XCTAssertEqual([actualOptions.integrations containsObject:@"SentryCrashIntegration"], false, + @"Did not disable native crash handling"); } - (void)testCreateOptionsWithDictionaryAutoPerformanceTracingDisabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"enableAutoPerformanceTracing": @NO, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"enableAutoPerformanceTracing" : @NO, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertEqual(actualOptions.enableAutoPerformanceTracing, false, @"Did not disable Auto Performance Tracing"); + XCTAssertEqual(actualOptions.enableAutoPerformanceTracing, false, + @"Did not disable Auto Performance Tracing"); } - (void)testCreateOptionsWithDictionarySpotlightEnabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"spotlight": @YES, - @"defaultSidecarUrl": @"http://localhost:8969/teststream", + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"spotlight" : @YES, + @"defaultSidecarUrl" : @"http://localhost:8969/teststream", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertTrue(actualOptions.enableSpotlight , @"Did not enable spotlight"); - XCTAssertEqual(actualOptions.spotlightUrl , @"http://localhost:8969/teststream"); + XCTAssertTrue(actualOptions.enableSpotlight, @"Did not enable spotlight"); + XCTAssertEqual(actualOptions.spotlightUrl, @"http://localhost:8969/teststream"); } - (void)testCreateOptionsWithDictionarySpotlightOne { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"spotlight": @1, - @"defaultSidecarUrl": @"http://localhost:8969/teststream", + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"spotlight" : @1, + @"defaultSidecarUrl" : @"http://localhost:8969/teststream", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertTrue(actualOptions.enableSpotlight , @"Did not enable spotlight"); - XCTAssertEqual(actualOptions.spotlightUrl , @"http://localhost:8969/teststream"); + XCTAssertTrue(actualOptions.enableSpotlight, @"Did not enable spotlight"); + XCTAssertEqual(actualOptions.spotlightUrl, @"http://localhost:8969/teststream"); } - (void)testCreateOptionsWithDictionarySpotlightUrl { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"spotlight": @"http://localhost:8969/teststream", + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"spotlight" : @"http://localhost:8969/teststream", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); - XCTAssertTrue(actualOptions.enableSpotlight , @"Did not enable spotlight"); - XCTAssertEqual(actualOptions.spotlightUrl , @"http://localhost:8969/teststream"); + XCTAssertTrue(actualOptions.enableSpotlight, @"Did not enable spotlight"); + XCTAssertEqual(actualOptions.spotlightUrl, @"http://localhost:8969/teststream"); } - (void)testCreateOptionsWithDictionarySpotlightDisabled { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"spotlight": @NO, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"spotlight" : @NO, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); XCTAssertFalse(actualOptions.enableSpotlight, @"Did not disable spotlight"); @@ -189,14 +208,15 @@ - (void)testCreateOptionsWithDictionarySpotlightDisabled - (void)testCreateOptionsWithDictionarySpotlightZero { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"https://abcd@efgh.ingest.sentry.io/123456", - @"spotlight": @0, + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"spotlight" : @0, }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNotNil(actualOptions, @"Did not create sentry options"); XCTAssertNil(error, @"Should not pass no error"); XCTAssertFalse(actualOptions.enableSpotlight, @"Did not disable spotlight"); @@ -204,13 +224,14 @@ - (void)testCreateOptionsWithDictionarySpotlightZero - (void)testPassesErrorOnWrongDsn { - RNSentry * rnSentry = [[RNSentry alloc] init]; - NSError* error = nil; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSError *error = nil; NSDictionary *_Nonnull mockedReactNativeDictionary = @{ - @"dsn": @"not_a_valid_dsn", + @"dsn" : @"not_a_valid_dsn", }; - SentryOptions* actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + SentryOptions *actualOptions = [rnSentry createOptionsWithDictionary:mockedReactNativeDictionary + error:&error]; XCTAssertNil(actualOptions, @"Created invalid sentry options"); XCTAssertNotNil(error, @"Did not created error on invalid dsn"); @@ -218,154 +239,169 @@ - (void)testPassesErrorOnWrongDsn - (void)testEventFromSentryCocoaReactNativeHasOriginAndEnvironmentTags { - RNSentry* rnSentry = [[RNSentry alloc] init]; - SentryEvent* testEvent = [[SentryEvent alloc] init]; - testEvent.sdk = @{ - @"name": @"sentry.cocoa.react-native", - }; - - [rnSentry setEventOriginTag: testEvent]; - - XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); - XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); + RNSentry *rnSentry = [[RNSentry alloc] init]; + SentryEvent *testEvent = [[SentryEvent alloc] init]; + testEvent.sdk = @{ + @"name" : @"sentry.cocoa.react-native", + }; + + [rnSentry setEventOriginTag:testEvent]; + + XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); + XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); } - (void)testEventFromSentryReactNativeOriginAndEnvironmentTagsAreOverwritten { - RNSentry* rnSentry = [[RNSentry alloc] init]; - SentryEvent* testEvent = [[SentryEvent alloc] init]; - testEvent.sdk = @{ - @"name": @"sentry.cocoa.react-native", - }; - testEvent.tags = @{ - @"event.origin": @"testEventOriginTag", - @"event.environment": @"testEventEnvironmentTag", - }; - - [rnSentry setEventOriginTag: testEvent]; - - XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); - XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); + RNSentry *rnSentry = [[RNSentry alloc] init]; + SentryEvent *testEvent = [[SentryEvent alloc] init]; + testEvent.sdk = @{ + @"name" : @"sentry.cocoa.react-native", + }; + testEvent.tags = @{ + @"event.origin" : @"testEventOriginTag", + @"event.environment" : @"testEventEnvironmentTag", + }; + + [rnSentry setEventOriginTag:testEvent]; + + XCTAssertEqual(testEvent.tags[@"event.origin"], @"ios"); + XCTAssertEqual(testEvent.tags[@"event.environment"], @"native"); } -void (^expectRejecterNotCalled)(NSString*, NSString*, NSError*) = ^(NSString *code, NSString *message, NSError *error) { - @throw [NSException exceptionWithName:@"Promise Rejector should not be called." reason:nil userInfo:nil]; -}; +void (^expectRejecterNotCalled)(NSString *, NSString *, NSError *) + = ^(NSString *code, NSString *message, NSError *error) { + @throw [NSException exceptionWithName:@"Promise Rejector should not be called." + reason:nil + userInfo:nil]; + }; uint64_t MOCKED_SYMBOL_ADDRESS = 123; -char const* MOCKED_SYMBOL_NAME = "symbolicatedname"; +char const *MOCKED_SYMBOL_NAME = "symbolicatedname"; -int sucessfulSymbolicate(const void *, Dl_info *info){ - info->dli_saddr = (void *) MOCKED_SYMBOL_ADDRESS; - info->dli_sname = MOCKED_SYMBOL_NAME; - return 1; +int +sucessfulSymbolicate(const void *, Dl_info *info) +{ + info->dli_saddr = (void *)MOCKED_SYMBOL_ADDRESS; + info->dli_sname = MOCKED_SYMBOL_NAME; + return 1; } -- (void)prepareNativeFrameMocksWithLocalSymbolication: (BOOL) debug +- (void)prepareNativeFrameMocksWithLocalSymbolication:(BOOL)debug { - SentryOptions* sentryOptions = [[SentryOptions alloc] init]; - sentryOptions.debug = debug; //no local symbolication - - id sentrySDKMock = OCMClassMock([SentrySDK class]); - OCMStub([(SentrySDK*) sentrySDKMock options]).andReturn(sentryOptions); - - id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); - OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])).andReturn(sentryDependencyContainerMock); - - id sentryBinaryImageInfoMockOne = OCMClassMock([SentryBinaryImageInfo class]); - OCMStub([(SentryBinaryImageInfo*) sentryBinaryImageInfoMockOne address]).andReturn([@112233 unsignedLongLongValue]); - OCMStub([sentryBinaryImageInfoMockOne name]).andReturn(@"testnameone"); - - id sentryBinaryImageInfoMockTwo = OCMClassMock([SentryBinaryImageInfo class]); - OCMStub([(SentryBinaryImageInfo*) sentryBinaryImageInfoMockTwo address]).andReturn([@112233 unsignedLongLongValue]); - OCMStub([sentryBinaryImageInfoMockTwo name]).andReturn(@"testnametwo"); - - id sentryBinaryImageCacheMock = OCMClassMock([SentryBinaryImageCache class]); - OCMStub([(SentryDependencyContainer*) sentryDependencyContainerMock binaryImageCache]).andReturn(sentryBinaryImageCacheMock); - OCMStub([sentryBinaryImageCacheMock imageByAddress:[@123 unsignedLongLongValue]]).andReturn(sentryBinaryImageInfoMockOne); - OCMStub([sentryBinaryImageCacheMock imageByAddress:[@456 unsignedLongLongValue]]).andReturn(sentryBinaryImageInfoMockTwo); - - NSDictionary* serializedDebugImage = @{ - @"uuid": @"mockuuid", - @"debug_id": @"mockdebugid", - @"type": @"macho", - @"image_addr": @"0x000000000001b669", - }; - id sentryDebugImageMock = OCMClassMock([SentryDebugMeta class]); - OCMStub([sentryDebugImageMock serialize]).andReturn(serializedDebugImage); - - id sentryDebugImageProviderMock = OCMClassMock([SentryDebugImageProvider class]); - OCMStub([sentryDebugImageProviderMock getDebugImagesForAddresses:[NSSet setWithObject:@"0x000000000001b669"] isCrash:false]).andReturn(@[sentryDebugImageMock]); - - OCMStub([sentryDependencyContainerMock debugImageProvider]).andReturn(sentryDebugImageProviderMock); + SentryOptions *sentryOptions = [[SentryOptions alloc] init]; + sentryOptions.debug = debug; // no local symbolication + + id sentrySDKMock = OCMClassMock([SentrySDK class]); + OCMStub([(SentrySDK *)sentrySDKMock options]).andReturn(sentryOptions); + + id sentryDependencyContainerMock = OCMClassMock([SentryDependencyContainer class]); + OCMStub(ClassMethod([sentryDependencyContainerMock sharedInstance])) + .andReturn(sentryDependencyContainerMock); + + id sentryBinaryImageInfoMockOne = OCMClassMock([SentryBinaryImageInfo class]); + OCMStub([(SentryBinaryImageInfo *)sentryBinaryImageInfoMockOne address]) + .andReturn([@112233 unsignedLongLongValue]); + OCMStub([sentryBinaryImageInfoMockOne name]).andReturn(@"testnameone"); + + id sentryBinaryImageInfoMockTwo = OCMClassMock([SentryBinaryImageInfo class]); + OCMStub([(SentryBinaryImageInfo *)sentryBinaryImageInfoMockTwo address]) + .andReturn([@112233 unsignedLongLongValue]); + OCMStub([sentryBinaryImageInfoMockTwo name]).andReturn(@"testnametwo"); + + id sentryBinaryImageCacheMock = OCMClassMock([SentryBinaryImageCache class]); + OCMStub([(SentryDependencyContainer *)sentryDependencyContainerMock binaryImageCache]) + .andReturn(sentryBinaryImageCacheMock); + OCMStub([sentryBinaryImageCacheMock imageByAddress:[@123 unsignedLongLongValue]]) + .andReturn(sentryBinaryImageInfoMockOne); + OCMStub([sentryBinaryImageCacheMock imageByAddress:[@456 unsignedLongLongValue]]) + .andReturn(sentryBinaryImageInfoMockTwo); + + NSDictionary *serializedDebugImage = @{ + @"uuid" : @"mockuuid", + @"debug_id" : @"mockdebugid", + @"type" : @"macho", + @"image_addr" : @"0x000000000001b669", + }; + id sentryDebugImageMock = OCMClassMock([SentryDebugMeta class]); + OCMStub([sentryDebugImageMock serialize]).andReturn(serializedDebugImage); + + id sentryDebugImageProviderMock = OCMClassMock([SentryDebugImageProvider class]); + OCMStub([sentryDebugImageProviderMock + getDebugImagesForAddresses:[NSSet setWithObject:@"0x000000000001b669"] + isCrash:false]) + .andReturn(@[ sentryDebugImageMock ]); + + OCMStub([sentryDependencyContainerMock debugImageProvider]) + .andReturn(sentryDebugImageProviderMock); } - (void)testFetchNativeStackFramesByInstructionsServerSymbolication { - [self prepareNativeFrameMocksWithLocalSymbolication:NO]; - RNSentry* rnSentry = [[RNSentry alloc] init]; - NSDictionary* actual = [rnSentry fetchNativeStackFramesBy: @[@123, @456] - symbolicate: sucessfulSymbolicate]; - - NSDictionary* expected = @{ - @"debugMetaImages": @[ - @{ - @"uuid": @"mockuuid", - @"debug_id": @"mockdebugid", - @"type": @"macho", - @"image_addr": @"0x000000000001b669", - }, - ], - @"frames": @[ - @{ - @"package": @"testnameone", - @"in_app": @NO, - @"platform": @"cocoa", - @"instruction_addr": @"0x000000000000007b", //123 - @"image_addr": @"0x000000000001b669", //112233 - }, - @{ - @"package": @"testnametwo", - @"in_app": @NO, - @"platform": @"cocoa", - @"instruction_addr": @"0x00000000000001c8", //456 - @"image_addr": @"0x000000000001b669", //445566 - }, - ], - }; - XCTAssertTrue([actual isEqualToDictionary:expected]); + [self prepareNativeFrameMocksWithLocalSymbolication:NO]; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSDictionary *actual = [rnSentry fetchNativeStackFramesBy:@[ @123, @456 ] + symbolicate:sucessfulSymbolicate]; + + NSDictionary *expected = @{ + @"debugMetaImages" : @[ + @{ + @"uuid" : @"mockuuid", + @"debug_id" : @"mockdebugid", + @"type" : @"macho", + @"image_addr" : @"0x000000000001b669", + }, + ], + @"frames" : @[ + @{ + @"package" : @"testnameone", + @"in_app" : @NO, + @"platform" : @"cocoa", + @"instruction_addr" : @"0x000000000000007b", // 123 + @"image_addr" : @"0x000000000001b669", // 112233 + }, + @{ + @"package" : @"testnametwo", + @"in_app" : @NO, + @"platform" : @"cocoa", + @"instruction_addr" : @"0x00000000000001c8", // 456 + @"image_addr" : @"0x000000000001b669", // 445566 + }, + ], + }; + XCTAssertTrue([actual isEqualToDictionary:expected]); } - (void)testFetchNativeStackFramesByInstructionsOnDeviceSymbolication { - [self prepareNativeFrameMocksWithLocalSymbolication:YES]; - RNSentry* rnSentry = [[RNSentry alloc] init]; - NSDictionary* actual = [rnSentry fetchNativeStackFramesBy: @[@123, @456] - symbolicate: sucessfulSymbolicate]; - - NSDictionary* expected = @{ - @"frames": @[ - @{ - @"function": @"symbolicatedname", - @"package": @"testnameone", - @"in_app": @NO, - @"platform": @"cocoa", - @"symbol_addr": @"0x000000000000007b", //123 - @"instruction_addr": @"0x000000000000007b", //123 - @"image_addr": @"0x000000000001b669", //112233 - }, - @{ - @"function": @"symbolicatedname", - @"package": @"testnametwo", - @"in_app": @NO, - @"platform": @"cocoa", - @"symbol_addr": @"0x000000000000007b", //123 - @"instruction_addr": @"0x00000000000001c8", //456 - @"image_addr": @"0x000000000001b669", //445566 - }, - ], - }; - XCTAssertTrue([actual isEqualToDictionary:expected]); + [self prepareNativeFrameMocksWithLocalSymbolication:YES]; + RNSentry *rnSentry = [[RNSentry alloc] init]; + NSDictionary *actual = [rnSentry fetchNativeStackFramesBy:@[ @123, @456 ] + symbolicate:sucessfulSymbolicate]; + + NSDictionary *expected = @{ + @"frames" : @[ + @{ + @"function" : @"symbolicatedname", + @"package" : @"testnameone", + @"in_app" : @NO, + @"platform" : @"cocoa", + @"symbol_addr" : @"0x000000000000007b", // 123 + @"instruction_addr" : @"0x000000000000007b", // 123 + @"image_addr" : @"0x000000000001b669", // 112233 + }, + @{ + @"function" : @"symbolicatedname", + @"package" : @"testnametwo", + @"in_app" : @NO, + @"platform" : @"cocoa", + @"symbol_addr" : @"0x000000000000007b", // 123 + @"instruction_addr" : @"0x00000000000001c8", // 456 + @"image_addr" : @"0x000000000001b669", // 445566 + }, + ], + }; + XCTAssertTrue([actual isEqualToDictionary:expected]); } @end diff --git a/packages/core/ios/RNSentry.h b/packages/core/ios/RNSentry.h index 4b5233c985..06e1569a16 100644 --- a/packages/core/ios/RNSentry.h +++ b/packages/core/ios/RNSentry.h @@ -1,20 +1,23 @@ #if __has_include() -#import +# import #else -#import "RCTBridge.h" +# import "RCTBridge.h" #endif -#import #import +#import #import -#import #import +#import typedef int (*SymbolicateCallbackType)(const void *, Dl_info *); -@interface SentryDebugImageProvider () -- (NSArray * _Nonnull)getDebugImagesForAddresses:(NSSet * _Nonnull)addresses isCrash:(BOOL)isCrash; +@interface +SentryDebugImageProvider () +- (NSArray *_Nonnull)getDebugImagesForAddresses: + (NSSet *_Nonnull)addresses + isCrash:(BOOL)isCrash; @end @interface @@ -25,11 +28,11 @@ SentrySDK (Private) @interface RNSentry : RCTEventEmitter - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)options - error:(NSError *_Nullable*_Nonnull)errorPointer; + error:(NSError *_Nullable *_Nonnull)errorPointer; -- (void) setEventOriginTag: (SentryEvent*) event; +- (void)setEventOriginTag:(SentryEvent *)event; -- (NSDictionary*_Nonnull) fetchNativeStackFramesBy: (NSArray*)instructionsAddr - symbolicate: (SymbolicateCallbackType) symbolicate; +- (NSDictionary *_Nonnull)fetchNativeStackFramesBy:(NSArray *)instructionsAddr + symbolicate:(SymbolicateCallbackType)symbolicate; @end diff --git a/packages/core/ios/RNSentry.mm b/packages/core/ios/RNSentry.mm index 98bb3e5ae8..7728a1b70a 100644 --- a/packages/core/ios/RNSentry.mm +++ b/packages/core/ios/RNSentry.mm @@ -1,54 +1,55 @@ -#import #import "RNSentry.h" #import "RNSentryTimeToDisplay.h" +#import #if __has_include() -#import +# import #else -#import "RCTConvert.h" +# import "RCTConvert.h" #endif #if __has_include() && SENTRY_PROFILING_SUPPORTED -#define SENTRY_PROFILING_ENABLED 1 -#import +# define SENTRY_PROFILING_ENABLED 1 +# import #else -#define SENTRY_PROFILING_ENABLED 0 -#define SENTRY_TARGET_PROFILING_SUPPORTED 0 +# define SENTRY_PROFILING_ENABLED 0 +# define SENTRY_TARGET_PROFILING_SUPPORTED 0 #endif +#import "RNSentryBreadcrumb.h" +#import "RNSentryId.h" #import -#import -#import +#import #import #import #import -#import -#import "RNSentryId.h" -#import "RNSentryBreadcrumb.h" +#import +#import // This guard prevents importing Hermes in JSC apps #if SENTRY_PROFILING_ENABLED -#import +# import #endif // Thanks to this guard, we won't import this header when we build for the old architecture. #ifdef RCT_NEW_ARCH_ENABLED -#import "RNSentrySpec.h" +# import "RNSentrySpec.h" #endif -#import "RNSentryEvents.h" #import "RNSentryDependencyContainer.h" +#import "RNSentryEvents.h" #if SENTRY_TARGET_REPLAY_SUPPORTED -#import "RNSentryReplay.h" +# import "RNSentryReplay.h" #endif #if SENTRY_HAS_UIKIT -#import "RNSentryRNSScreen.h" -#import "RNSentryFramesTrackerListener.h" +# import "RNSentryFramesTrackerListener.h" +# import "RNSentryRNSScreen.h" #endif -@interface SentrySDK (RNSentry) +@interface +SentrySDK (RNSentry) + (void)captureEnvelope:(SentryEnvelope *)envelope; @@ -58,7 +59,7 @@ + (void)storeEnvelope:(SentryEnvelope *)envelope; static bool hasFetchedAppStart; -static NSString* const nativeSdkName = @"sentry.cocoa.react-native"; +static NSString *const nativeSdkName = @"sentry.cocoa.react-native"; @implementation RNSentry { bool sentHybridSdkDidBecomeActive; @@ -71,39 +72,44 @@ - (dispatch_queue_t)methodQueue return dispatch_get_main_queue(); } -+ (BOOL)requiresMainQueueSetup { ++ (BOOL)requiresMainQueueSetup +{ return YES; } RCT_EXPORT_MODULE() -RCT_EXPORT_METHOD(initNativeSdk:(NSDictionary *_Nonnull)options - resolve:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(initNativeSdk + : (NSDictionary *_Nonnull)options resolve + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { NSError *error = nil; - SentryOptions* sentryOptions = [self createOptionsWithDictionary:options error:&error]; + SentryOptions *sentryOptions = [self createOptionsWithDictionary:options error:&error]; if (error != nil) { reject(@"SentryReactNative", error.localizedDescription, error); return; } NSString *sdkVersion = [PrivateSentrySDKOnly getSdkVersionString]; - [PrivateSentrySDKOnly setSdkName: nativeSdkName andVersionString: sdkVersion]; + [PrivateSentrySDKOnly setSdkName:nativeSdkName andVersionString:sdkVersion]; [SentrySDK startWithOptions:sentryOptions]; #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST - BOOL appIsActive = [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; + BOOL appIsActive = + [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; #else BOOL appIsActive = [[NSApplication sharedApplication] isActive]; #endif - // If the app is active/in foreground, and we have not sent the SentryHybridSdkDidBecomeActive notification, send it. - if (appIsActive && !sentHybridSdkDidBecomeActive && (PrivateSentrySDKOnly.options.enableAutoSessionTracking || PrivateSentrySDKOnly.options.enableWatchdogTerminationTracking)) { - [[NSNotificationCenter defaultCenter] - postNotificationName:@"SentryHybridSdkDidBecomeActive" - object:nil]; + // If the app is active/in foreground, and we have not sent the SentryHybridSdkDidBecomeActive + // notification, send it. + if (appIsActive && !sentHybridSdkDidBecomeActive + && (PrivateSentrySDKOnly.options.enableAutoSessionTracking + || PrivateSentrySDKOnly.options.enableWatchdogTerminationTracking)) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"SentryHybridSdkDidBecomeActive" + object:nil]; sentHybridSdkDidBecomeActive = true; } @@ -116,13 +122,15 @@ + (BOOL)requiresMainQueueSetup { } - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull)options - error: (NSError *_Nonnull *_Nonnull) errorPointer + error:(NSError *_Nonnull *_Nonnull)errorPointer { - SentryBeforeSendEventCallback beforeSend = ^SentryEvent*(SentryEvent *event) { - // We don't want to send an event after startup that came from a Unhandled JS Exception of react native - // Because we sent it already before the app crashed. + SentryBeforeSendEventCallback beforeSend = ^SentryEvent *(SentryEvent *event) + { + // We don't want to send an event after startup that came from a Unhandled JS Exception of + // react native Because we sent it already before the app crashed. if (nil != event.exceptions.firstObject.type && - [event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) { + [event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location + != NSNotFound) { return nil; } @@ -131,12 +139,12 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) return event; }; - NSMutableDictionary * mutableOptions =[options mutableCopy]; + NSMutableDictionary *mutableOptions = [options mutableCopy]; [mutableOptions setValue:beforeSend forKey:@"beforeSend"]; - // remove performance traces sample rate and traces sampler since we don't want to synchronize these configurations - // to the Native SDKs. - // The user could tho initialize the SDK manually and set themselves. + // remove performance traces sample rate and traces sampler since we don't want to synchronize + // these configurations to the Native SDKs. The user could tho initialize the SDK manually and + // set themselves. [mutableOptions removeObjectForKey:@"tracesSampleRate"]; [mutableOptions removeObjectForKey:@"tracesSampler"]; [mutableOptions removeObjectForKey:@"enableTracing"]; @@ -147,7 +155,8 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) [RNSentryReplay updateOptions:mutableOptions]; #endif - SentryOptions *sentryOptions = [[SentryOptions alloc] initWithDict:mutableOptions didFailWithError:errorPointer]; + SentryOptions *sentryOptions = [[SentryOptions alloc] initWithDict:mutableOptions + didFailWithError:errorPointer]; if (*errorPointer != nil) { return nil; } @@ -161,7 +170,7 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) sentryOptions.integrations = integrations; } } - + // Set spotlight option if ([mutableOptions valueForKey:@"spotlight"] != nil) { id spotlightValue = [mutableOptions valueForKey:@"spotlight"]; @@ -180,7 +189,8 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) // Enable the App start and Frames tracking measurements if ([mutableOptions valueForKey:@"enableAutoPerformanceTracing"] != nil) { - BOOL enableAutoPerformanceTracing = [mutableOptions[@"enableAutoPerformanceTracing"] boolValue]; + BOOL enableAutoPerformanceTracing = + [mutableOptions[@"enableAutoPerformanceTracing"] boolValue]; PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = enableAutoPerformanceTracing; #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode = enableAutoPerformanceTracing; @@ -190,46 +200,47 @@ - (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) return sentryOptions; } -- (void)setEventOriginTag:(SentryEvent *)event { - if (event.sdk != nil) { - NSString *sdkName = event.sdk[@"name"]; +- (void)setEventOriginTag:(SentryEvent *)event +{ + if (event.sdk != nil) { + NSString *sdkName = event.sdk[@"name"]; - // If the event is from react native, it gets set - // there and we do not handle it here. - if ([sdkName isEqual:nativeSdkName]) { - [self setEventEnvironmentTag:event origin:@"ios" environment:@"native"]; + // If the event is from react native, it gets set + // there and we do not handle it here. + if ([sdkName isEqual:nativeSdkName]) { + [self setEventEnvironmentTag:event origin:@"ios" environment:@"native"]; + } } - } } - (void)setEventEnvironmentTag:(SentryEvent *)event origin:(NSString *)origin - environment:(NSString *)environment { - NSMutableDictionary *newTags = [NSMutableDictionary new]; + environment:(NSString *)environment +{ + NSMutableDictionary *newTags = [NSMutableDictionary new]; - if (nil != event.tags && [event.tags count] > 0) { - [newTags addEntriesFromDictionary:event.tags]; - } - if (nil != origin) { - [newTags setValue:origin forKey:@"event.origin"]; - } - if (nil != environment) { - [newTags setValue:environment forKey:@"event.environment"]; - } + if (nil != event.tags && [event.tags count] > 0) { + [newTags addEntriesFromDictionary:event.tags]; + } + if (nil != origin) { + [newTags setValue:origin forKey:@"event.origin"]; + } + if (nil != environment) { + [newTags setValue:environment forKey:@"event.environment"]; + } - event.tags = newTags; + event.tags = newTags; } -RCT_EXPORT_METHOD(initNativeReactNavigationNewFrameTracking:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(initNativeReactNavigationNewFrameTracking + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if SENTRY_HAS_UIKIT if ([[NSThread currentThread] isMainThread]) { [RNSentryRNSScreen swizzleViewDidAppear]; } else { - dispatch_async(dispatch_get_main_queue(), ^{ - [RNSentryRNSScreen swizzleViewDidAppear]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ [RNSentryRNSScreen swizzleViewDidAppear]; }); } [self initFramesTracking]; @@ -237,48 +248,57 @@ - (void)setEventEnvironmentTag:(SentryEvent *)event resolve(nil); } -- (void)initFramesTracking { +- (void)initFramesTracking +{ #if SENTRY_HAS_UIKIT - RNSentryEmitNewFrameEvent emitNewFrameEvent = ^(NSNumber *newFrameTimestampInSeconds) { - if (self->hasListeners) { - [self sendEventWithName:RNSentryNewFrameEvent body:@{ @"newFrameTimestampInSeconds": newFrameTimestampInSeconds }]; - } - }; - [[RNSentryDependencyContainer sharedInstance] initializeFramesTrackerListenerWith: emitNewFrameEvent]; + RNSentryEmitNewFrameEvent emitNewFrameEvent = ^(NSNumber *newFrameTimestampInSeconds) { + if (self->hasListeners) { + [self + sendEventWithName:RNSentryNewFrameEvent + body:@{ @"newFrameTimestampInSeconds" : newFrameTimestampInSeconds }]; + } + }; + [[RNSentryDependencyContainer sharedInstance] + initializeFramesTrackerListenerWith:emitNewFrameEvent]; #endif } // Will be called when this module's first listener is added. --(void)startObserving { +- (void)startObserving +{ hasListeners = YES; } // Will be called when this module's last listener is removed, or on dealloc. --(void)stopObserving { +- (void)stopObserving +{ hasListeners = NO; } -- (NSArray *)supportedEvents { - return @[RNSentryNewFrameEvent]; +- (NSArray *)supportedEvents +{ + return @[ RNSentryNewFrameEvent ]; } -RCT_EXPORT_METHOD(fetchNativeSdkInfo:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchNativeSdkInfo + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { - resolve(@{ - @"name": PrivateSentrySDKOnly.getSdkName, - @"version": PrivateSentrySDKOnly.getSdkVersionString - }); + resolve(@ { + @"name" : PrivateSentrySDKOnly.getSdkName, + @"version" : PrivateSentrySDKOnly.getSdkVersionString + }); } -RCT_EXPORT_METHOD(fetchModules:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchModules + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"modules" ofType:@"json"]; - NSString* modulesString = [NSString stringWithContentsOfFile:filePath - encoding:NSUTF8StringEncoding - error:nil]; + NSString *modulesString = [NSString stringWithContentsOfFile:filePath + encoding:NSUTF8StringEncoding + error:nil]; resolve(modulesString); } @@ -288,79 +308,90 @@ -(void)stopObserving { return packageName; } -- (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAddr - symbolicate: (SymbolicateCallbackType) symbolicate +- (NSDictionary *)fetchNativeStackFramesBy:(NSArray *)instructionsAddr + symbolicate:(SymbolicateCallbackType)symbolicate { - BOOL shouldSymbolicateLocally = [SentrySDK.options debug]; - NSString *appPackageName = [[NSBundle mainBundle] executablePath]; - - NSMutableSet * _Nonnull imagesAddrToRetrieveDebugMetaImages = [[NSMutableSet alloc] init]; - NSMutableArray *> * _Nonnull serializedFrames = [[NSMutableArray alloc] init]; - - for (NSNumber *addr in instructionsAddr) { - SentryBinaryImageInfo * _Nullable image = [[[SentryDependencyContainer sharedInstance] binaryImageCache] imageByAddress:[addr unsignedLongLongValue]]; - if (image != nil) { - NSString * imageAddr = sentry_formatHexAddressUInt64([image address]); - [imagesAddrToRetrieveDebugMetaImages addObject: imageAddr]; - - NSDictionary * _Nonnull nativeFrame = @{ - @"platform": @"cocoa", - @"instruction_addr": sentry_formatHexAddress(addr), - @"package": [image name], - @"image_addr": imageAddr, - @"in_app": [NSNumber numberWithBool:[appPackageName isEqualToString:[image name]]], - }; - - if (shouldSymbolicateLocally) { - Dl_info symbolsBuffer; - bool symbols_succeed = false; - symbols_succeed = symbolicate((void *) [addr unsignedLongLongValue], &symbolsBuffer) != 0; - if (symbols_succeed) { - NSMutableDictionary * _Nonnull symbolicated = nativeFrame.mutableCopy; - symbolicated[@"symbol_addr"] = sentry_formatHexAddressUInt64((uintptr_t)symbolsBuffer.dli_saddr); - symbolicated[@"function"] = [NSString stringWithCString:symbolsBuffer.dli_sname encoding:NSUTF8StringEncoding]; + BOOL shouldSymbolicateLocally = [SentrySDK.options debug]; + NSString *appPackageName = [[NSBundle mainBundle] executablePath]; + + NSMutableSet *_Nonnull imagesAddrToRetrieveDebugMetaImages = + [[NSMutableSet alloc] init]; + NSMutableArray *> *_Nonnull serializedFrames = + [[NSMutableArray alloc] init]; + + for (NSNumber *addr in instructionsAddr) { + SentryBinaryImageInfo *_Nullable image = [[[SentryDependencyContainer sharedInstance] + binaryImageCache] imageByAddress:[addr unsignedLongLongValue]]; + if (image != nil) { + NSString *imageAddr = sentry_formatHexAddressUInt64([image address]); + [imagesAddrToRetrieveDebugMetaImages addObject:imageAddr]; + + NSDictionary *_Nonnull nativeFrame = @{ + @"platform" : @"cocoa", + @"instruction_addr" : sentry_formatHexAddress(addr), + @"package" : [image name], + @"image_addr" : imageAddr, + @"in_app" : [NSNumber numberWithBool:[appPackageName isEqualToString:[image name]]], + }; + + if (shouldSymbolicateLocally) { + Dl_info symbolsBuffer; + bool symbols_succeed = false; + symbols_succeed + = symbolicate((void *)[addr unsignedLongLongValue], &symbolsBuffer) != 0; + if (symbols_succeed) { + NSMutableDictionary *_Nonnull symbolicated + = nativeFrame.mutableCopy; + symbolicated[@"symbol_addr"] + = sentry_formatHexAddressUInt64((uintptr_t)symbolsBuffer.dli_saddr); + symbolicated[@"function"] = [NSString stringWithCString:symbolsBuffer.dli_sname + encoding:NSUTF8StringEncoding]; + + nativeFrame = symbolicated; + } + } - nativeFrame = symbolicated; + [serializedFrames addObject:nativeFrame]; + } else { + [serializedFrames addObject:@{ + @"platform" : @"cocoa", + @"instruction_addr" : sentry_formatHexAddress(addr), + }]; } - } + } - [serializedFrames addObject:nativeFrame]; + if (shouldSymbolicateLocally) { + return @{ + @"frames" : serializedFrames, + }; } else { - [serializedFrames addObject: @{ - @"platform": @"cocoa", - @"instruction_addr": sentry_formatHexAddress(addr), - }]; - } - } + NSMutableArray *> *_Nonnull serializedDebugMetaImages = + [[NSMutableArray alloc] init]; - if (shouldSymbolicateLocally) { - return @{ - @"frames": serializedFrames, - }; - } else { - NSMutableArray *> * _Nonnull serializedDebugMetaImages = [[NSMutableArray alloc] init]; + NSArray *debugMetaImages = [[[SentryDependencyContainer sharedInstance] + debugImageProvider] getDebugImagesForAddresses:imagesAddrToRetrieveDebugMetaImages + isCrash:false]; - NSArray *debugMetaImages = [[[SentryDependencyContainer sharedInstance] debugImageProvider] getDebugImagesForAddresses:imagesAddrToRetrieveDebugMetaImages isCrash:false]; + for (SentryDebugMeta *debugImage in debugMetaImages) { + [serializedDebugMetaImages addObject:[debugImage serialize]]; + } - for (SentryDebugMeta *debugImage in debugMetaImages) { - [serializedDebugMetaImages addObject:[debugImage serialize]]; + return @{ + @"frames" : serializedFrames, + @"debugMetaImages" : serializedDebugMetaImages, + }; } - - return @{ - @"frames": serializedFrames, - @"debugMetaImages": serializedDebugMetaImages, - }; - } } -RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, fetchNativeStackFramesBy:(NSArray *)instructionsAddr) +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, fetchNativeStackFramesBy + : (NSArray *)instructionsAddr) { - return [self fetchNativeStackFramesBy:instructionsAddr - symbolicate:dladdr]; + return [self fetchNativeStackFramesBy:instructionsAddr symbolicate:dladdr]; } -RCT_EXPORT_METHOD(fetchNativeDeviceContexts:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchNativeDeviceContexts + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { if (PrivateSentrySDKOnly.options.debug) { NSLog(@"Bridge call to: deviceContexts"); @@ -368,36 +399,41 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd __block NSMutableDictionary *serializedScope; // Temp work around until sorted out this API in sentry-cocoa. // TODO: If the callback isnt' executed the promise wouldn't be resolved. - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { + [SentrySDK configureScope:^(SentryScope *_Nonnull scope) { serializedScope = [[scope serialize] mutableCopy]; - NSDictionary *user = [serializedScope valueForKey:@"user"]; + NSDictionary *user = [serializedScope valueForKey:@"user"]; if (user == nil) { - [serializedScope - setValue:@{ @"id": PrivateSentrySDKOnly.installationID } - forKey:@"user"]; + [serializedScope setValue:@ { @"id" : PrivateSentrySDKOnly.installationID } + forKey:@"user"]; } if (PrivateSentrySDKOnly.options.debug) { - NSData *data = [NSJSONSerialization dataWithJSONObject:serializedScope options:0 error:nil]; - NSString *debugContext = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSData *data = [NSJSONSerialization dataWithJSONObject:serializedScope + options:0 + error:nil]; + NSString *debugContext = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; NSLog(@"Contexts: %@", debugContext); } }]; NSDictionary *extraContext = [PrivateSentrySDKOnly getExtraContext]; - NSMutableDictionary *> *contexts = [serializedScope[@"context"] mutableCopy]; + NSMutableDictionary *> *contexts = + [serializedScope[@"context"] mutableCopy]; if (extraContext && [extraContext[@"device"] isKindOfClass:[NSDictionary class]]) { - NSMutableDictionary *> *deviceContext = [contexts[@"device"] mutableCopy]; - [deviceContext addEntriesFromDictionary:extraContext[@"device"]]; - [contexts setValue:deviceContext forKey:@"device"]; + NSMutableDictionary *> *deviceContext = + [contexts[@"device"] mutableCopy]; + [deviceContext addEntriesFromDictionary:extraContext[@"device"]]; + [contexts setValue:deviceContext forKey:@"device"]; } if (extraContext && [extraContext[@"app"] isKindOfClass:[NSDictionary class]]) { - NSMutableDictionary *> *appContext = [contexts[@"app"] mutableCopy]; - [appContext addEntriesFromDictionary:extraContext[@"app"]]; - [contexts setValue:appContext forKey:@"app"]; + NSMutableDictionary *> *appContext = + [contexts[@"app"] mutableCopy]; + [appContext addEntriesFromDictionary:extraContext[@"app"]]; + [contexts setValue:appContext forKey:@"app"]; } [serializedScope setValue:contexts forKey:@"contexts"]; @@ -405,18 +441,22 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd resolve(serializedScope); } -RCT_EXPORT_METHOD(fetchNativeAppStart:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchNativeAppStart + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if SENTRY_HAS_UIKIT - NSDictionary *measurements = [PrivateSentrySDKOnly appStartMeasurementWithSpans]; + NSDictionary *measurements = + [PrivateSentrySDKOnly appStartMeasurementWithSpans]; if (measurements == nil) { resolve(nil); return; } - NSMutableDictionary *mutableMeasurements = [[NSMutableDictionary alloc] initWithDictionary:measurements]; - [mutableMeasurements setValue:[NSNumber numberWithBool:hasFetchedAppStart] forKey:@"has_fetched"]; + NSMutableDictionary *mutableMeasurements = + [[NSMutableDictionary alloc] initWithDictionary:measurements]; + [mutableMeasurements setValue:[NSNumber numberWithBool:hasFetchedAppStart] + forKey:@"has_fetched"]; // This is always set to true, as we would only allow an app start fetch to only happen once // in the case of a JS bundle reload, we do not want it to be instrumented again. @@ -428,8 +468,9 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd #endif } -RCT_EXPORT_METHOD(fetchNativeFrames:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchNativeFrames + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST @@ -445,79 +486,82 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd NSNumber *frozen = [NSNumber numberWithLong:frames.frozen]; NSNumber *slow = [NSNumber numberWithLong:frames.slow]; - resolve(@{ - @"totalFrames": total, - @"frozenFrames": frozen, - @"slowFrames": slow, + resolve(@ { + @"totalFrames" : total, + @"frozenFrames" : frozen, + @"slowFrames" : slow, }); } else { - resolve(nil); + resolve(nil); } #else resolve(nil); #endif } -RCT_EXPORT_METHOD(fetchNativeRelease:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchNativeRelease + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; - resolve(@{ - @"id": infoDict[@"CFBundleIdentifier"], - @"version": infoDict[@"CFBundleShortVersionString"], - @"build": infoDict[@"CFBundleVersion"], - }); -} - -RCT_EXPORT_METHOD(captureEnvelope:(NSString * _Nonnull)rawBytes - options: (NSDictionary * _Nonnull)options - resolve:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) + resolve(@ { + @"id" : infoDict[@"CFBundleIdentifier"], + @"version" : infoDict[@"CFBundleShortVersionString"], + @"build" : infoDict[@"CFBundleVersion"], + }); +} + +RCT_EXPORT_METHOD(captureEnvelope + : (NSString *_Nonnull)rawBytes options + : (NSDictionary *_Nonnull)options resolve + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { NSData *data = [[NSData alloc] initWithBase64EncodedString:rawBytes options:0]; SentryEnvelope *envelope = [PrivateSentrySDKOnly envelopeWithData:data]; if (envelope == nil) { - reject(@"SentryReactNative",@"Failed to parse envelope from byte array.", nil); + reject(@"SentryReactNative", @"Failed to parse envelope from byte array.", nil); return; } - #if DEBUG +#if DEBUG + [PrivateSentrySDKOnly captureEnvelope:envelope]; +#else + if ([[options objectForKey:@"hardCrashed"] boolValue]) { + // Storing to disk happens asynchronously with captureEnvelope + [PrivateSentrySDKOnly storeEnvelope:envelope]; + } else { [PrivateSentrySDKOnly captureEnvelope:envelope]; - #else - if ([[options objectForKey:@"hardCrashed"] boolValue]) { - // Storing to disk happens asynchronously with captureEnvelope - [PrivateSentrySDKOnly storeEnvelope:envelope]; - } else { - [PrivateSentrySDKOnly captureEnvelope:envelope]; - } - #endif + } +#endif resolve(@YES); } -RCT_EXPORT_METHOD(captureScreenshot: (RCTPromiseResolveBlock)resolve - rejecter: (RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(captureScreenshot + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST - NSArray* rawScreenshots = [PrivateSentrySDKOnly captureScreenshots]; + NSArray *rawScreenshots = [PrivateSentrySDKOnly captureScreenshots]; NSMutableArray *screenshotsArray = [NSMutableArray arrayWithCapacity:[rawScreenshots count]]; int counter = 1; - for (NSData* raw in rawScreenshots) { + for (NSData *raw in rawScreenshots) { NSMutableArray *screenshot = [NSMutableArray arrayWithCapacity:raw.length]; - const char *bytes = (char*) [raw bytes]; + const char *bytes = (char *)[raw bytes]; for (int i = 0; i < [raw length]; i++) { [screenshot addObject:[[NSNumber alloc] initWithChar:bytes[i]]]; } - NSString* filename = @"screenshot.png"; + NSString *filename = @"screenshot.png"; if (counter > 1) { filename = [NSString stringWithFormat:@"screenshot-%d.png", counter]; } - [screenshotsArray addObject:@{ - @"data": screenshot, - @"contentType": @"image/png", - @"filename": filename, + [screenshotsArray addObject:@ { + @"data" : screenshot, + @"contentType" : @"image/png", + @"filename" : filename, }]; counter++; } @@ -528,14 +572,15 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd #endif } -RCT_EXPORT_METHOD(fetchViewHierarchy: (RCTPromiseResolveBlock)resolve - rejecter: (RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(fetchViewHierarchy + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST - NSData * rawViewHierarchy = [PrivateSentrySDKOnly captureViewHierarchy]; + NSData *rawViewHierarchy = [PrivateSentrySDKOnly captureViewHierarchy]; NSMutableArray *viewHierarchy = [NSMutableArray arrayWithCapacity:rawViewHierarchy.length]; - const char *bytes = (char*) [rawViewHierarchy bytes]; + const char *bytes = (char *)[rawViewHierarchy bytes]; for (int i = 0; i < [rawViewHierarchy length]; i++) { [viewHierarchy addObject:[[NSNumber alloc] initWithChar:bytes[i]]]; } @@ -546,16 +591,13 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd #endif } - -RCT_EXPORT_METHOD(setUser:(NSDictionary *)userKeys - otherUserKeys:(NSDictionary *)userDataKeys -) +RCT_EXPORT_METHOD(setUser : (NSDictionary *)userKeys otherUserKeys : (NSDictionary *)userDataKeys) { - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { + [SentrySDK configureScope:^(SentryScope *_Nonnull scope) { if (nil == userKeys && nil == userDataKeys) { [scope setUser:nil]; } else { - SentryUser* userInstance = [[SentryUser alloc] init]; + SentryUser *userInstance = [[SentryUser alloc] init]; if (nil != userKeys) { [userInstance setUserId:userKeys[@"id"]]; @@ -574,9 +616,9 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd }]; } -RCT_EXPORT_METHOD(addBreadcrumb:(NSDictionary *)breadcrumb) +RCT_EXPORT_METHOD(addBreadcrumb : (NSDictionary *)breadcrumb) { - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { + [SentrySDK configureScope:^(SentryScope *_Nonnull scope) { [scope addBreadcrumb:[RNSentryBreadcrumb from:breadcrumb]]; }]; @@ -585,33 +627,27 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd if (screen != nil) { [PrivateSentrySDKOnly setCurrentScreen:screen]; } -#endif //SENTRY_HAS_UIKIT +#endif // SENTRY_HAS_UIKIT } -RCT_EXPORT_METHOD(clearBreadcrumbs) { - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { - [scope clearBreadcrumbs]; - }]; +RCT_EXPORT_METHOD(clearBreadcrumbs) +{ + [SentrySDK configureScope:^(SentryScope *_Nonnull scope) { [scope clearBreadcrumbs]; }]; } -RCT_EXPORT_METHOD(setExtra:(NSString *)key - extra:(NSString *)extra -) +RCT_EXPORT_METHOD(setExtra : (NSString *)key extra : (NSString *)extra) { - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { - [scope setExtraValue:extra forKey:key]; - }]; + [SentrySDK + configureScope:^(SentryScope *_Nonnull scope) { [scope setExtraValue:extra forKey:key]; }]; } -RCT_EXPORT_METHOD(setContext:(NSString *)key - context:(NSDictionary *)context -) +RCT_EXPORT_METHOD(setContext : (NSString *)key context : (NSDictionary *)context) { if (key == nil) { return; } - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { + [SentrySDK configureScope:^(SentryScope *_Nonnull scope) { if (context == nil) { [scope removeContextForKey:key]; } else { @@ -620,25 +656,20 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd }]; } -RCT_EXPORT_METHOD(setTag:(NSString *)key - value:(NSString *)value -) +RCT_EXPORT_METHOD(setTag : (NSString *)key value : (NSString *)value) { - [SentrySDK configureScope:^(SentryScope * _Nonnull scope) { - [scope setTagValue:value forKey:key]; - }]; + [SentrySDK + configureScope:^(SentryScope *_Nonnull scope) { [scope setTagValue:value forKey:key]; }]; } -RCT_EXPORT_METHOD(crash) -{ - [SentrySDK crash]; -} +RCT_EXPORT_METHOD(crash) { [SentrySDK crash]; } -RCT_EXPORT_METHOD(closeNativeSdk:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(closeNativeSdk + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { - [SentrySDK close]; - resolve(@YES); + [SentrySDK close]; + resolve(@YES); } RCT_EXPORT_METHOD(disableNativeFramesTracking) @@ -654,70 +685,76 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd // the 'tracesSampleRate' or 'tracesSampler' option. } -RCT_EXPORT_METHOD(captureReplay: (BOOL)isHardCrash - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(captureReplay + : (BOOL)isHardCrash resolver + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { #if SENTRY_TARGET_REPLAY_SUPPORTED - [PrivateSentrySDKOnly captureReplay]; - resolve([PrivateSentrySDKOnly getReplayId]); + [PrivateSentrySDKOnly captureReplay]; + resolve([PrivateSentrySDKOnly getReplayId]); #else - resolve(nil); + resolve(nil); #endif } RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getCurrentReplayId) { #if SENTRY_TARGET_REPLAY_SUPPORTED - return [PrivateSentrySDKOnly getReplayId]; + return [PrivateSentrySDKOnly getReplayId]; #else - return nil; + return nil; #endif } -static NSString* const enabledProfilingMessage = @"Enable Hermes to use Sentry Profiling."; -static SentryId* nativeProfileTraceId = nil; +static NSString *const enabledProfilingMessage = @"Enable Hermes to use Sentry Profiling."; +static SentryId *nativeProfileTraceId = nil; static uint64_t nativeProfileStartTime = 0; -RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, startProfiling: (BOOL)platformProfilers) +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSDictionary *, startProfiling : (BOOL)platformProfilers) { #if SENTRY_PROFILING_ENABLED try { facebook::hermes::HermesRuntime::enableSamplingProfiler(); if (nativeProfileTraceId == nil && nativeProfileStartTime == 0 && platformProfilers) { -#if SENTRY_TARGET_PROFILING_SUPPORTED +# if SENTRY_TARGET_PROFILING_SUPPORTED nativeProfileTraceId = [RNSentryId newId]; - nativeProfileStartTime = [PrivateSentrySDKOnly startProfilerForTrace: nativeProfileTraceId]; -#endif + nativeProfileStartTime = + [PrivateSentrySDKOnly startProfilerForTrace:nativeProfileTraceId]; +# endif } else { if (!platformProfilers) { NSLog(@"Native profiling is disabled. Only starting Hermes profiling."); } else { - NSLog(@"Native profiling already in progress. Currently existing trace: %@", nativeProfileTraceId); + NSLog(@"Native profiling already in progress. Currently existing trace: %@", + nativeProfileTraceId); } } - return @{ @"started": @YES }; - } catch (const std::exception& ex) { + return @{@"started" : @YES}; + } catch (const std::exception &ex) { if (nativeProfileTraceId != nil) { -#if SENTRY_TARGET_PROFILING_SUPPORTED - [PrivateSentrySDKOnly discardProfilerForTrace: nativeProfileTraceId]; -#endif +# if SENTRY_TARGET_PROFILING_SUPPORTED + [PrivateSentrySDKOnly discardProfilerForTrace:nativeProfileTraceId]; +# endif nativeProfileTraceId = nil; } nativeProfileStartTime = 0; - return @{ @"error": [NSString stringWithCString: ex.what() encoding:[NSString defaultCStringEncoding]] }; + return @ { + @"error" : [NSString stringWithCString:ex.what() + encoding:[NSString defaultCStringEncoding]] + }; } catch (...) { if (nativeProfileTraceId != nil) { -#if SENTRY_TARGET_PROFILING_SUPPORTED - [PrivateSentrySDKOnly discardProfilerForTrace: nativeProfileTraceId]; -#endif +# if SENTRY_TARGET_PROFILING_SUPPORTED + [PrivateSentrySDKOnly discardProfilerForTrace:nativeProfileTraceId]; +# endif nativeProfileTraceId = nil; } nativeProfileStartTime = 0; - return @{ @"error": @"Failed to start profiling" }; + return @ { @"error" : @"Failed to start profiling" }; } #else - return @{ @"error": enabledProfilingMessage }; + return @ { @"error" : enabledProfilingMessage }; #endif } @@ -725,12 +762,14 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd { #if SENTRY_PROFILING_ENABLED try { - NSDictionary * nativeProfile = nil; + NSDictionary *nativeProfile = nil; if (nativeProfileTraceId != nil && nativeProfileStartTime != 0) { -#if SENTRY_TARGET_PROFILING_SUPPORTED +# if SENTRY_TARGET_PROFILING_SUPPORTED uint64_t nativeProfileStopTime = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - nativeProfile = [PrivateSentrySDKOnly collectProfileBetween:nativeProfileStartTime and:nativeProfileStopTime forTrace:nativeProfileTraceId]; -#endif + nativeProfile = [PrivateSentrySDKOnly collectProfileBetween:nativeProfileStartTime + and:nativeProfileStopTime + forTrace:nativeProfileTraceId]; +# endif } // Cleanup native profiles nativeProfileTraceId = nil; @@ -742,57 +781,66 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd facebook::hermes::HermesRuntime::dumpSampledTraceToStream(ss); std::string s = ss.str(); - NSString *data = [NSString stringWithCString:s.c_str() encoding:[NSString defaultCStringEncoding]]; + NSString *data = [NSString stringWithCString:s.c_str() + encoding:[NSString defaultCStringEncoding]]; -#if SENTRY_PROFILING_DEBUG_ENABLED +# if SENTRY_PROFILING_DEBUG_ENABLED NSString *rawProfileFileName = @"hermes.profile"; NSError *error = nil; - NSString *rawProfileFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:rawProfileFileName]; - if (![data writeToFile:rawProfileFilePath atomically:YES encoding:NSUTF8StringEncoding error:&error]) { + NSString *rawProfileFilePath = + [NSTemporaryDirectory() stringByAppendingPathComponent:rawProfileFileName]; + if (![data writeToFile:rawProfileFilePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&error]) { NSLog(@"Error writing Raw Hermes Profile to %@: %@", rawProfileFilePath, error); } else { NSLog(@"Raw Hermes Profile saved to %@", rawProfileFilePath); } -#endif +# endif if (data == nil) { - return @{ @"error": @"Failed to retrieve Hermes profile." }; + return @ { @"error" : @"Failed to retrieve Hermes profile." }; } if (nativeProfile == nil) { - return @{ @"profile": data }; + return @ { @"profile" : data }; } - return @{ - @"profile": data, - @"nativeProfile": nativeProfile, + return @ { + @"profile" : data, + @"nativeProfile" : nativeProfile, }; - } catch (const std::exception& ex) { + } catch (const std::exception &ex) { if (nativeProfileTraceId != nil) { -#if SENTRY_TARGET_PROFILING_SUPPORTED - [PrivateSentrySDKOnly discardProfilerForTrace: nativeProfileTraceId]; -#endif - nativeProfileTraceId = nil; +# if SENTRY_TARGET_PROFILING_SUPPORTED + [PrivateSentrySDKOnly discardProfilerForTrace:nativeProfileTraceId]; +# endif + nativeProfileTraceId = nil; } nativeProfileStartTime = 0; - return @{ @"error": [NSString stringWithCString: ex.what() encoding:[NSString defaultCStringEncoding]] }; + return @ { + @"error" : [NSString stringWithCString:ex.what() + encoding:[NSString defaultCStringEncoding]] + }; } catch (...) { if (nativeProfileTraceId != nil) { -#if SENTRY_TARGET_PROFILING_SUPPORTED - [PrivateSentrySDKOnly discardProfilerForTrace: nativeProfileTraceId]; -#endif - nativeProfileTraceId = nil; +# if SENTRY_TARGET_PROFILING_SUPPORTED + [PrivateSentrySDKOnly discardProfilerForTrace:nativeProfileTraceId]; +# endif + nativeProfileTraceId = nil; } nativeProfileStartTime = 0; - return @{ @"error": @"Failed to stop profiling" }; + return @ { @"error" : @"Failed to stop profiling" }; } #else - return @{ @"error": enabledProfilingMessage }; + return @ { @"error" : enabledProfilingMessage }; #endif } -RCT_EXPORT_METHOD(crashedLastRun:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(crashedLastRun + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { resolve(@([SentrySDK crashedLastRun])); } @@ -806,8 +854,10 @@ - (NSDictionary*) fetchNativeStackFramesBy: (NSArray*)instructionsAdd } #endif -RCT_EXPORT_METHOD(getNewScreenTimeToDisplay:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) { +RCT_EXPORT_METHOD(getNewScreenTimeToDisplay + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) +{ [_timeToDisplay getTimeToDisplay:resolve]; } diff --git a/packages/core/ios/RNSentryBreadcrumb.h b/packages/core/ios/RNSentryBreadcrumb.h index 083670aefe..c7ee01dec9 100644 --- a/packages/core/ios/RNSentryBreadcrumb.h +++ b/packages/core/ios/RNSentryBreadcrumb.h @@ -6,8 +6,8 @@ @interface RNSentryBreadcrumb : NSObject -+ (SentryBreadcrumb *)from: (NSDictionary *) dict; ++ (SentryBreadcrumb *)from:(NSDictionary *)dict; -+ (NSString *_Nullable) getCurrentScreenFrom: (NSDictionary *) dict; ++ (NSString *_Nullable)getCurrentScreenFrom:(NSDictionary *)dict; @end diff --git a/packages/core/ios/RNSentryBreadcrumb.m b/packages/core/ios/RNSentryBreadcrumb.m index e900ba4833..c849b5a5f9 100644 --- a/packages/core/ios/RNSentryBreadcrumb.m +++ b/packages/core/ios/RNSentryBreadcrumb.m @@ -3,11 +3,11 @@ @implementation RNSentryBreadcrumb -+(SentryBreadcrumb*) from: (NSDictionary *) dict ++ (SentryBreadcrumb *)from:(NSDictionary *)dict { - SentryBreadcrumb* crumb = [[SentryBreadcrumb alloc] init]; + SentryBreadcrumb *crumb = [[SentryBreadcrumb alloc] init]; - NSString * levelString = dict[@"level"]; + NSString *levelString = dict[@"level"]; SentryLevel sentryLevel; if ([levelString isEqualToString:@"fatal"]) { sentryLevel = kSentryLevelFatal; @@ -30,13 +30,14 @@ +(SentryBreadcrumb*) from: (NSDictionary *) dict return crumb; } -+ (NSString *_Nullable) getCurrentScreenFrom: (NSDictionary *_Nonnull) dict { ++ (NSString *_Nullable)getCurrentScreenFrom:(NSDictionary *_Nonnull)dict +{ NSString *_Nullable maybeCategory = [dict valueForKey:@"category"]; if (![maybeCategory isEqualToString:@"navigation"]) { return nil; } - NSDictionary *_Nullable maybeData = [dict valueForKey:@"data"]; + NSDictionary *_Nullable maybeData = [dict valueForKey:@"data"]; if (![maybeData isKindOfClass:[NSDictionary class]]) { return nil; } @@ -45,7 +46,7 @@ + (NSString *_Nullable) getCurrentScreenFrom: (NSDictionary *_Non if (![maybeCurrentScreen isKindOfClass:[NSString class]]) { return nil; } - + return maybeCurrentScreen; } diff --git a/packages/core/ios/RNSentryDependencyContainer.h b/packages/core/ios/RNSentryDependencyContainer.h index ad5b72e4a2..cd3eca59c7 100644 --- a/packages/core/ios/RNSentryDependencyContainer.h +++ b/packages/core/ios/RNSentryDependencyContainer.h @@ -5,13 +5,13 @@ @interface RNSentryDependencyContainer : NSObject SENTRY_NO_INIT -@property (class, readonly, strong) RNSentryDependencyContainer* sharedInstance; +@property (class, readonly, strong) RNSentryDependencyContainer *sharedInstance; #if SENTRY_HAS_UIKIT @property (nonatomic, strong) RNSentryFramesTrackerListener *framesTrackerListener; -- (void)initializeFramesTrackerListenerWith:(RNSentryEmitNewFrameEvent) eventEmitter; +- (void)initializeFramesTrackerListenerWith:(RNSentryEmitNewFrameEvent)eventEmitter; #endif diff --git a/packages/core/ios/RNSentryDependencyContainer.m b/packages/core/ios/RNSentryDependencyContainer.m index a1e703f87b..e91cac7f81 100644 --- a/packages/core/ios/RNSentryDependencyContainer.m +++ b/packages/core/ios/RNSentryDependencyContainer.m @@ -2,8 +2,8 @@ #import @implementation RNSentryDependencyContainer { - NSObject *sentryDependencyContainerLock; - } + NSObject *sentryDependencyContainerLock; +} + (instancetype)sharedInstance { @@ -25,10 +25,11 @@ - (instancetype)init - (void)initializeFramesTrackerListenerWith:(RNSentryEmitNewFrameEvent)eventEmitter { - @synchronized(sentryDependencyContainerLock) { - _framesTrackerListener = [[RNSentryFramesTrackerListener alloc] initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] - andEventEmitter: eventEmitter]; - } + @synchronized(sentryDependencyContainerLock) { + _framesTrackerListener = [[RNSentryFramesTrackerListener alloc] + initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] + andEventEmitter:eventEmitter]; + } } #endif diff --git a/packages/core/ios/RNSentryFramesTrackerListener.h b/packages/core/ios/RNSentryFramesTrackerListener.h index c554fd00df..e0de09dfd9 100644 --- a/packages/core/ios/RNSentryFramesTrackerListener.h +++ b/packages/core/ios/RNSentryFramesTrackerListener.h @@ -2,18 +2,18 @@ #if SENTRY_HAS_UIKIT -#import -#import -#import +# import +# import +# import typedef void (^RNSentryEmitNewFrameEvent)(NSNumber *newFrameTimestampInSeconds); @interface RNSentryFramesTrackerListener : NSObject -- (instancetype)initWithSentryFramesTracker:(SentryFramesTracker *) framesTracker - andEventEmitter:(RNSentryEmitNewFrameEvent) emitNewFrameEvent; +- (instancetype)initWithSentryFramesTracker:(SentryFramesTracker *)framesTracker + andEventEmitter:(RNSentryEmitNewFrameEvent)emitNewFrameEvent; -- (void) startListening; +- (void)startListening; @property (strong, nonatomic) SentryFramesTracker *framesTracker; @property (strong, nonatomic) RNSentryEmitNewFrameEvent emitNewFrameEvent; diff --git a/packages/core/ios/RNSentryFramesTrackerListener.m b/packages/core/ios/RNSentryFramesTrackerListener.m index 24de9ffb92..4a3c7d99cd 100644 --- a/packages/core/ios/RNSentryFramesTrackerListener.m +++ b/packages/core/ios/RNSentryFramesTrackerListener.m @@ -5,7 +5,7 @@ @implementation RNSentryFramesTrackerListener - (instancetype)initWithSentryFramesTracker:(SentryFramesTracker *)framesTracker - andEventEmitter:(RNSentryEmitNewFrameEvent) emitNewFrameEvent; + andEventEmitter:(RNSentryEmitNewFrameEvent)emitNewFrameEvent; { self = [super init]; if (self) { @@ -17,16 +17,18 @@ - (instancetype)initWithSentryFramesTracker:(SentryFramesTracker *)framesTracker - (void)framesTrackerHasNewFrame:(NSDate *)newFrameDate { - [_framesTracker removeListener:self]; - NSNumber *newFrameTimestampInSeconds = [NSNumber numberWithDouble:[newFrameDate timeIntervalSince1970]]; + [_framesTracker removeListener:self]; + NSNumber *newFrameTimestampInSeconds = + [NSNumber numberWithDouble:[newFrameDate timeIntervalSince1970]]; - if (_emitNewFrameEvent) { - _emitNewFrameEvent(newFrameTimestampInSeconds); - } + if (_emitNewFrameEvent) { + _emitNewFrameEvent(newFrameTimestampInSeconds); + } } -- (void)startListening { - [_framesTracker addListener:self]; +- (void)startListening +{ + [_framesTracker addListener:self]; } @end diff --git a/packages/core/ios/RNSentryId.m b/packages/core/ios/RNSentryId.m index bbb832aaff..7618c60893 100644 --- a/packages/core/ios/RNSentryId.m +++ b/packages/core/ios/RNSentryId.m @@ -3,7 +3,8 @@ @implementation RNSentryId -+ (SentryId *)newId { ++ (SentryId *)newId +{ return [[SentryId alloc] init]; } diff --git a/packages/core/ios/RNSentryOnDrawReporter.h b/packages/core/ios/RNSentryOnDrawReporter.h index 5a2585dc96..1cf9fb6245 100644 --- a/packages/core/ios/RNSentryOnDrawReporter.h +++ b/packages/core/ios/RNSentryOnDrawReporter.h @@ -2,9 +2,9 @@ #if SENTRY_HAS_UIKIT -#import -#import -#import "RNSentryFramesTrackerListener.h" +# import "RNSentryFramesTrackerListener.h" +# import +# import @interface RNSentryOnDrawReporter : RCTViewManager @@ -12,11 +12,11 @@ @interface RNSentryOnDrawReporterView : UIView -@property (nonatomic, strong) RNSentryFramesTrackerListener* framesListener; +@property (nonatomic, strong) RNSentryFramesTrackerListener *framesListener; @property (nonatomic, copy) RCTBubblingEventBlock onDrawNextFrame; @property (nonatomic) bool fullDisplay; @property (nonatomic) bool initialDisplay; -@property (nonatomic, weak) RNSentryOnDrawReporter* delegate; +@property (nonatomic, weak) RNSentryOnDrawReporter *delegate; @end diff --git a/packages/core/ios/RNSentryOnDrawReporter.m b/packages/core/ios/RNSentryOnDrawReporter.m index b6f4cabfdc..d8266c73a5 100644 --- a/packages/core/ios/RNSentryOnDrawReporter.m +++ b/packages/core/ios/RNSentryOnDrawReporter.m @@ -2,7 +2,7 @@ #if SENTRY_HAS_UIKIT -#import +# import @implementation RNSentryOnDrawReporter @@ -13,45 +13,47 @@ @implementation RNSentryOnDrawReporter - (UIView *)view { - RNSentryOnDrawReporterView* view = [[RNSentryOnDrawReporterView alloc] init]; - return view; + RNSentryOnDrawReporterView *view = [[RNSentryOnDrawReporterView alloc] init]; + return view; } @end @implementation RNSentryOnDrawReporterView -- (instancetype)init { +- (instancetype)init +{ self = [super init]; if (self) { RNSentryEmitNewFrameEvent emitNewFrameEvent = ^(NSNumber *newFrameTimestampInSeconds) { - if (self->_fullDisplay) { - self.onDrawNextFrame(@{ - @"newFrameTimestampInSeconds": newFrameTimestampInSeconds, - @"type": @"fullDisplay" - }); - return; - } - - if (self->_initialDisplay) { - self.onDrawNextFrame(@{ - @"newFrameTimestampInSeconds": newFrameTimestampInSeconds, - @"type": @"initialDisplay" - }); - return; - } + if (self->_fullDisplay) { + self.onDrawNextFrame(@{ + @"newFrameTimestampInSeconds" : newFrameTimestampInSeconds, + @"type" : @"fullDisplay" + }); + return; + } + + if (self->_initialDisplay) { + self.onDrawNextFrame(@{ + @"newFrameTimestampInSeconds" : newFrameTimestampInSeconds, + @"type" : @"initialDisplay" + }); + return; + } }; - _framesListener = [[RNSentryFramesTrackerListener alloc] initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] - andEventEmitter:emitNewFrameEvent]; + _framesListener = [[RNSentryFramesTrackerListener alloc] + initWithSentryFramesTracker:[[SentryDependencyContainer sharedInstance] framesTracker] + andEventEmitter:emitNewFrameEvent]; } return self; } - (void)didSetProps:(NSArray *)changedProps { - if (_fullDisplay || _initialDisplay) { - [_framesListener startListening]; - } + if (_fullDisplay || _initialDisplay) { + [_framesListener startListening]; + } } @end diff --git a/packages/core/ios/RNSentryRNSScreen.h b/packages/core/ios/RNSentryRNSScreen.h index 53f72fa5b2..dfc2f7281b 100644 --- a/packages/core/ios/RNSentryRNSScreen.h +++ b/packages/core/ios/RNSentryRNSScreen.h @@ -2,7 +2,7 @@ #if SENTRY_HAS_UIKIT -#import +# import @interface RNSentryRNSScreen : NSObject diff --git a/packages/core/ios/RNSentryRNSScreen.m b/packages/core/ios/RNSentryRNSScreen.m index daa4569cf4..20c42ab4c4 100644 --- a/packages/core/ios/RNSentryRNSScreen.m +++ b/packages/core/ios/RNSentryRNSScreen.m @@ -2,28 +2,28 @@ #if SENTRY_HAS_UIKIT -#import -#import -#import +# import +# import +# import -#import "RNSentryDependencyContainer.h" +# import "RNSentryDependencyContainer.h" @implementation RNSentryRNSScreen -+ (void)swizzleViewDidAppear { - Class rnsscreenclass = NSClassFromString(@"RNSScreen"); - if (rnsscreenclass == nil) - { - return; - } - - SEL selector = NSSelectorFromString(@"viewDidAppear:"); - SentrySwizzleInstanceMethod(rnsscreenclass, selector, SentrySWReturnType(void), - SentrySWArguments(BOOL animated), SentrySWReplacement({ - [[[RNSentryDependencyContainer sharedInstance] framesTrackerListener] startListening]; - SentrySWCallOriginal(animated); - }), - SentrySwizzleModeOncePerClass, (void *)selector); ++ (void)swizzleViewDidAppear +{ + Class rnsscreenclass = NSClassFromString(@"RNSScreen"); + if (rnsscreenclass == nil) { + return; + } + + SEL selector = NSSelectorFromString(@"viewDidAppear:"); + SentrySwizzleInstanceMethod(rnsscreenclass, selector, SentrySWReturnType(void), + SentrySWArguments(BOOL animated), SentrySWReplacement({ + [[[RNSentryDependencyContainer sharedInstance] framesTrackerListener] startListening]; + SentrySWCallOriginal(animated); + }), + SentrySwizzleModeOncePerClass, (void *)selector); } @end diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index de6a0c240e..9ef2c4efc0 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -6,70 +6,71 @@ @implementation RNSentryReplay { } -+ (void)updateOptions:(NSMutableDictionary *)options { - NSDictionary *experiments = options[@"_experiments"]; - [options removeObjectForKey:@"_experiments"]; - if (experiments == nil) { - NSLog(@"Session replay disabled via configuration"); - return; - } ++ (void)updateOptions:(NSMutableDictionary *)options +{ + NSDictionary *experiments = options[@"_experiments"]; + [options removeObjectForKey:@"_experiments"]; + if (experiments == nil) { + NSLog(@"Session replay disabled via configuration"); + return; + } - if (experiments[@"replaysSessionSampleRate"] == nil && - experiments[@"replaysOnErrorSampleRate"] == nil) { - NSLog(@"Session replay disabled via configuration"); - return; - } + if (experiments[@"replaysSessionSampleRate"] == nil + && experiments[@"replaysOnErrorSampleRate"] == nil) { + NSLog(@"Session replay disabled via configuration"); + return; + } - NSLog(@"Setting up session replay"); - NSDictionary *replayOptions = options[@"mobileReplayOptions"] ?: @{}; + NSLog(@"Setting up session replay"); + NSDictionary *replayOptions = options[@"mobileReplayOptions"] ?: @{}; - [options setValue:@{ - @"sessionReplay" : @{ - @"sessionSampleRate" : experiments[@"replaysSessionSampleRate"] - ?: [NSNull null], - @"errorSampleRate" : experiments[@"replaysOnErrorSampleRate"] - ?: [NSNull null], - @"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null], - @"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null], + [options setValue:@{ + @"sessionReplay" : @ { + @"sessionSampleRate" : experiments[@"replaysSessionSampleRate"] ?: [NSNull null], + @"errorSampleRate" : experiments[@"replaysOnErrorSampleRate"] ?: [NSNull null], + @"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null], + @"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null], + } } - } - forKey:@"experimental"]; + forKey:@"experimental"]; - [RNSentryReplay addReplayRNRedactClasses:replayOptions]; + [RNSentryReplay addReplayRNRedactClasses:replayOptions]; } -+ (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { - NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; - if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { - Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView"); - if (maybeRNSVGViewClass != nil) { - [classesToRedact addObject:maybeRNSVGViewClass]; - } - } - if ([replayOptions[@"maskAllImages"] boolValue] == YES) { - Class _Nullable maybeRCTImageClass = NSClassFromString(@"RCTImageView"); - if (maybeRCTImageClass != nil) { - [classesToRedact addObject:maybeRCTImageClass]; ++ (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions +{ + NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; + if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { + Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView"); + if (maybeRNSVGViewClass != nil) { + [classesToRedact addObject:maybeRNSVGViewClass]; + } } - } - if ([replayOptions[@"maskAllText"] boolValue] == YES) { - Class _Nullable maybeRCTTextClass = NSClassFromString(@"RCTTextView"); - if (maybeRCTTextClass != nil) { - [classesToRedact addObject:maybeRCTTextClass]; + if ([replayOptions[@"maskAllImages"] boolValue] == YES) { + Class _Nullable maybeRCTImageClass = NSClassFromString(@"RCTImageView"); + if (maybeRCTImageClass != nil) { + [classesToRedact addObject:maybeRCTImageClass]; + } } - Class _Nullable maybeRCTParagraphComponentViewClass = NSClassFromString(@"RCTParagraphComponentView"); - if (maybeRCTParagraphComponentViewClass != nil) { - [classesToRedact addObject:maybeRCTParagraphComponentViewClass]; + if ([replayOptions[@"maskAllText"] boolValue] == YES) { + Class _Nullable maybeRCTTextClass = NSClassFromString(@"RCTTextView"); + if (maybeRCTTextClass != nil) { + [classesToRedact addObject:maybeRCTTextClass]; + } + Class _Nullable maybeRCTParagraphComponentViewClass + = NSClassFromString(@"RCTParagraphComponentView"); + if (maybeRCTParagraphComponentViewClass != nil) { + [classesToRedact addObject:maybeRCTParagraphComponentViewClass]; + } } - } - [PrivateSentrySDKOnly addReplayRedactClasses:classesToRedact]; + [PrivateSentrySDKOnly addReplayRedactClasses:classesToRedact]; } -+ (void)postInit { - RNSentryReplayBreadcrumbConverter *breadcrumbConverter = - [[RNSentryReplayBreadcrumbConverter alloc] init]; - [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter - screenshotProvider:nil]; ++ (void)postInit +{ + RNSentryReplayBreadcrumbConverter *breadcrumbConverter = + [[RNSentryReplayBreadcrumbConverter alloc] init]; + [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; } @end diff --git a/packages/core/ios/RNSentryReplayBreadcrumbConverter.h b/packages/core/ios/RNSentryReplayBreadcrumbConverter.h index ce12fcf39c..2eee190e26 100644 --- a/packages/core/ios/RNSentryReplayBreadcrumbConverter.h +++ b/packages/core/ios/RNSentryReplayBreadcrumbConverter.h @@ -3,14 +3,13 @@ #if SENTRY_TARGET_REPLAY_SUPPORTED @class SentryRRWebEvent; -@interface RNSentryReplayBreadcrumbConverter - : NSObject +@interface RNSentryReplayBreadcrumbConverter : NSObject - (instancetype _Nonnull)init; -+ (NSString* _Nullable) getTouchPathMessageFrom:(NSArray* _Nullable) path; ++ (NSString *_Nullable)getTouchPathMessageFrom:(NSArray *_Nullable)path; -- (id _Nullable)convertFrom:(SentryBreadcrumb *_Nonnull) breadcrumb; +- (id _Nullable)convertFrom:(SentryBreadcrumb *_Nonnull)breadcrumb; @end #endif diff --git a/packages/core/ios/RNSentryReplayBreadcrumbConverter.m b/packages/core/ios/RNSentryReplayBreadcrumbConverter.m index 251ada8903..14dfdc32a0 100644 --- a/packages/core/ios/RNSentryReplayBreadcrumbConverter.m +++ b/packages/core/ios/RNSentryReplayBreadcrumbConverter.m @@ -5,162 +5,169 @@ #if SENTRY_TARGET_REPLAY_SUPPORTED @implementation RNSentryReplayBreadcrumbConverter { - SentrySRDefaultBreadcrumbConverter *defaultConverter; + SentrySRDefaultBreadcrumbConverter *defaultConverter; } -- (instancetype _Nonnull)init { - if (self = [super init]) { - self->defaultConverter = - [SentrySessionReplayIntegration createDefaultBreadcrumbConverter]; - } - return self; +- (instancetype _Nonnull)init +{ + if (self = [super init]) { + self->defaultConverter = [SentrySessionReplayIntegration createDefaultBreadcrumbConverter]; + } + return self; } -- (id _Nullable)convertFrom: - (SentryBreadcrumb *_Nonnull)breadcrumb { - assert(breadcrumb.timestamp != nil); +- (id _Nullable)convertFrom:(SentryBreadcrumb *_Nonnull)breadcrumb +{ + assert(breadcrumb.timestamp != nil); - if ([breadcrumb.category isEqualToString:@"sentry.event"] || - [breadcrumb.category isEqualToString:@"sentry.transaction"]) { - // Do not add Sentry Event breadcrumbs to replay - return nil; - } + if ([breadcrumb.category isEqualToString:@"sentry.event"] || + [breadcrumb.category isEqualToString:@"sentry.transaction"]) { + // Do not add Sentry Event breadcrumbs to replay + return nil; + } - if ([breadcrumb.category isEqualToString:@"http"]) { - // Drop native network breadcrumbs to avoid duplicates - return nil; - } + if ([breadcrumb.category isEqualToString:@"http"]) { + // Drop native network breadcrumbs to avoid duplicates + return nil; + } - if ([breadcrumb.category isEqualToString:@"touch"]) { - return [self convertTouch:breadcrumb]; - } + if ([breadcrumb.category isEqualToString:@"touch"]) { + return [self convertTouch:breadcrumb]; + } - if ([breadcrumb.category isEqualToString:@"navigation"]) { - return [SentrySessionReplayIntegration - createBreadcrumbwithTimestamp:breadcrumb.timestamp - category:breadcrumb.category - message:nil - level:breadcrumb.level - data:breadcrumb.data]; - } - - if ([breadcrumb.category isEqualToString:@"xhr"]) { - return [self convertNavigation:breadcrumb]; - } - - SentryRRWebEvent *nativeBreadcrumb = - [self->defaultConverter convertFrom:breadcrumb]; - - // ignore native navigation breadcrumbs - if (nativeBreadcrumb && nativeBreadcrumb.data && - nativeBreadcrumb.data[@"payload"] && - nativeBreadcrumb.data[@"payload"][@"category"] && - [nativeBreadcrumb.data[@"payload"][@"category"] - isEqualToString:@"navigation"]) { - return nil; - } - - return nativeBreadcrumb; -} + if ([breadcrumb.category isEqualToString:@"navigation"]) { + return [SentrySessionReplayIntegration createBreadcrumbwithTimestamp:breadcrumb.timestamp + category:breadcrumb.category + message:nil + level:breadcrumb.level + data:breadcrumb.data]; + } -- (id _Nullable) convertTouch:(SentryBreadcrumb *_Nonnull)breadcrumb { - if (breadcrumb.data == nil) { - return nil; - } + if ([breadcrumb.category isEqualToString:@"xhr"]) { + return [self convertNavigation:breadcrumb]; + } - NSMutableArray *path = [breadcrumb.data valueForKey:@"path"]; - NSString* message = [RNSentryReplayBreadcrumbConverter getTouchPathMessageFrom:path]; + SentryRRWebEvent *nativeBreadcrumb = [self->defaultConverter convertFrom:breadcrumb]; - return [SentrySessionReplayIntegration - createBreadcrumbwithTimestamp:breadcrumb.timestamp - category:@"ui.tap" - message:message - level:breadcrumb.level - data:breadcrumb.data]; + // ignore native navigation breadcrumbs + if (nativeBreadcrumb && nativeBreadcrumb.data && nativeBreadcrumb.data[@"payload"] + && nativeBreadcrumb.data[@"payload"][@"category"] && + [nativeBreadcrumb.data[@"payload"][@"category"] isEqualToString:@"navigation"]) { + return nil; + } + + return nativeBreadcrumb; } -+ (NSString* _Nullable) getTouchPathMessageFrom:(NSArray* _Nullable) path { - if (path == nil) { - return nil; - } +- (id _Nullable)convertTouch:(SentryBreadcrumb *_Nonnull)breadcrumb +{ + if (breadcrumb.data == nil) { + return nil; + } + + NSMutableArray *path = [breadcrumb.data valueForKey:@"path"]; + NSString *message = [RNSentryReplayBreadcrumbConverter getTouchPathMessageFrom:path]; - NSInteger pathCount = [path count]; - if (pathCount <= 0) { - return nil; - } + return [SentrySessionReplayIntegration createBreadcrumbwithTimestamp:breadcrumb.timestamp + category:@"ui.tap" + message:message + level:breadcrumb.level + data:breadcrumb.data]; +} - NSMutableString *message = [[NSMutableString alloc] init]; - for (NSInteger i = MIN(3, pathCount - 1); i >= 0; i--) { - NSDictionary *item = [path objectAtIndex:i]; - if (item == nil) { - return nil; // There should be no nil (undefined) from JS, but to be safe we check it here ++ (NSString *_Nullable)getTouchPathMessageFrom:(NSArray *_Nullable)path +{ + if (path == nil) { + return nil; } - id name = [item objectForKey:@"name"]; - id label = [item objectForKey:@"label"]; - BOOL hasName = [name isKindOfClass:[NSString class]]; - BOOL hasLabel = [label isKindOfClass:[NSString class]]; - if (!hasName && !hasLabel) { - return nil; // This again should never be allowed in JS, but to be safe we check it here - } - if (hasLabel) { - [message appendString:(NSString *)label]; - } else if (hasName) { - [message appendString:(NSString *)name]; + NSInteger pathCount = [path count]; + if (pathCount <= 0) { + return nil; } - id element = [item objectForKey:@"element"]; - id file = [item objectForKey:@"file"]; - BOOL hasElement = [element isKindOfClass:[NSString class]]; - BOOL hasFile = [file isKindOfClass:[NSString class]]; - if (hasElement && hasFile) { - [message appendFormat:@"(%@, %@)", (NSString *)element, (NSString *)file]; - } else if (hasElement) { - [message appendFormat:@"(%@)", (NSString *)element]; - } else if (hasFile) { - [message appendFormat:@"(%@)", (NSString *)file]; + NSMutableString *message = [[NSMutableString alloc] init]; + for (NSInteger i = MIN(3, pathCount - 1); i >= 0; i--) { + NSDictionary *item = [path objectAtIndex:i]; + if (item == nil) { + return nil; // There should be no nil (undefined) from JS, but to be safe we check it + // here + } + + id name = [item objectForKey:@"name"]; + id label = [item objectForKey:@"label"]; + BOOL hasName = [name isKindOfClass:[NSString class]]; + BOOL hasLabel = [label isKindOfClass:[NSString class]]; + if (!hasName && !hasLabel) { + return nil; // This again should never be allowed in JS, but to be safe we check it here + } + if (hasLabel) { + [message appendString:(NSString *)label]; + } else if (hasName) { + [message appendString:(NSString *)name]; + } + + id element = [item objectForKey:@"element"]; + id file = [item objectForKey:@"file"]; + BOOL hasElement = [element isKindOfClass:[NSString class]]; + BOOL hasFile = [file isKindOfClass:[NSString class]]; + if (hasElement && hasFile) { + [message appendFormat:@"(%@, %@)", (NSString *)element, (NSString *)file]; + } else if (hasElement) { + [message appendFormat:@"(%@)", (NSString *)element]; + } else if (hasFile) { + [message appendFormat:@"(%@)", (NSString *)file]; + } + + if (i > 0) { + [message appendString:@" > "]; + } } - if (i > 0) { - [message appendString:@" > "]; + return message; +} + +- (id _Nullable)convertNavigation:(SentryBreadcrumb *_Nonnull)breadcrumb +{ + NSNumber *startTimestamp = [breadcrumb.data[@"start_timestamp"] isKindOfClass:[NSNumber class]] + ? breadcrumb.data[@"start_timestamp"] + : nil; + NSNumber *endTimestamp = [breadcrumb.data[@"end_timestamp"] isKindOfClass:[NSNumber class]] + ? breadcrumb.data[@"end_timestamp"] + : nil; + NSString *url = + [breadcrumb.data[@"url"] isKindOfClass:[NSString class]] ? breadcrumb.data[@"url"] : nil; + + if (startTimestamp == nil || endTimestamp == nil || url == nil) { + return nil; } - } - return message; -} + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + if ([breadcrumb.data[@"method"] isKindOfClass:[NSString class]]) { + data[@"method"] = breadcrumb.data[@"method"]; + } + if ([breadcrumb.data[@"status_code"] isKindOfClass:[NSNumber class]]) { + data[@"statusCode"] = breadcrumb.data[@"status_code"]; + } + if ([breadcrumb.data[@"request_body_size"] isKindOfClass:[NSNumber class]]) { + data[@"requestBodySize"] = breadcrumb.data[@"request_body_size"]; + } + if ([breadcrumb.data[@"response_body_size"] isKindOfClass:[NSNumber class]]) { + data[@"responseBodySize"] = breadcrumb.data[@"response_body_size"]; + } -- (id _Nullable)convertNavigation: (SentryBreadcrumb *_Nonnull)breadcrumb { - NSNumber* startTimestamp = [breadcrumb.data[@"start_timestamp"] isKindOfClass:[NSNumber class]] - ? breadcrumb.data[@"start_timestamp"] : nil; - NSNumber* endTimestamp = [breadcrumb.data[@"end_timestamp"] isKindOfClass:[NSNumber class]] - ? breadcrumb.data[@"end_timestamp"] : nil; - NSString* url = [breadcrumb.data[@"url"] isKindOfClass:[NSString class]] - ? breadcrumb.data[@"url"] : nil; - - if (startTimestamp == nil || endTimestamp == nil || url == nil) { - return nil; - } - - NSMutableDictionary* data = [[NSMutableDictionary alloc] init]; - if ([breadcrumb.data[@"method"] isKindOfClass:[NSString class]]) { - data[@"method"] = breadcrumb.data[@"method"]; - } - if ([breadcrumb.data[@"status_code"] isKindOfClass:[NSNumber class]]) { - data[@"statusCode"] = breadcrumb.data[@"status_code"]; - } - if ([breadcrumb.data[@"request_body_size"] isKindOfClass:[NSNumber class]]) { - data[@"requestBodySize"] = breadcrumb.data[@"request_body_size"]; - } - if ([breadcrumb.data[@"response_body_size"] isKindOfClass:[NSNumber class]]) { - data[@"responseBodySize"] = breadcrumb.data[@"response_body_size"]; - } - - return [SentrySessionReplayIntegration - createNetworkBreadcrumbWithTimestamp:[NSDate dateWithTimeIntervalSince1970:(startTimestamp.doubleValue / 1000)] - endTimestamp:[NSDate dateWithTimeIntervalSince1970:(endTimestamp.doubleValue / 1000)] - operation:@"resource.http" - description:url - data:data]; + return [SentrySessionReplayIntegration + createNetworkBreadcrumbWithTimestamp:[NSDate + dateWithTimeIntervalSince1970:(startTimestamp + .doubleValue + / 1000)] + endTimestamp:[NSDate + dateWithTimeIntervalSince1970:(endTimestamp + .doubleValue + / 1000)] + operation:@"resource.http" + description:url + data:data]; } @end diff --git a/packages/core/ios/RNSentryTimeToDisplay.m b/packages/core/ios/RNSentryTimeToDisplay.m index 88e24eedc7..9404cf5088 100644 --- a/packages/core/ios/RNSentryTimeToDisplay.m +++ b/packages/core/ios/RNSentryTimeToDisplay.m @@ -2,41 +2,42 @@ #import #import -@implementation RNSentryTimeToDisplay -{ - CADisplayLink *displayLink; - RCTResponseSenderBlock resolveBlock; +@implementation RNSentryTimeToDisplay { + CADisplayLink *displayLink; + RCTResponseSenderBlock resolveBlock; } // Rename requestAnimationFrame to getTimeToDisplay - (void)getTimeToDisplay:(RCTResponseSenderBlock)callback { - // Store the resolve block to use in the callback. - resolveBlock = callback; + // Store the resolve block to use in the callback. + resolveBlock = callback; #if TARGET_OS_IOS - // Create and add a display link to get the callback after the screen is rendered. - displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)]; - [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; + // Create and add a display link to get the callback after the screen is rendered. + displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)]; + [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; #else - resolveBlock(@[]); // Return nothing if not iOS. + resolveBlock(@[]); // Return nothing if not iOS. #endif } #if TARGET_OS_IOS -- (void)handleDisplayLink:(CADisplayLink *)link { - // Get the current time - NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970] * 1000.0; // Convert to milliseconds +- (void)handleDisplayLink:(CADisplayLink *)link +{ + // Get the current time + NSTimeInterval currentTime = + [[NSDate date] timeIntervalSince1970] * 1000.0; // Convert to milliseconds - // Ensure the callback is valid and pass the current time back - if (resolveBlock) { - resolveBlock(@[@(currentTime)]); // Call the callback with the current time - resolveBlock = nil; // Clear the block after it's called - } + // Ensure the callback is valid and pass the current time back + if (resolveBlock) { + resolveBlock(@[ @(currentTime) ]); // Call the callback with the current time + resolveBlock = nil; // Clear the block after it's called + } - // Invalidate the display link to stop future callbacks - [displayLink invalidate]; - displayLink = nil; + // Invalidate the display link to stop future callbacks + [displayLink invalidate]; + displayLink = nil; } #endif diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.cpp index 23bc693960..70e1fce274 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.cpp +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.cpp @@ -6,28 +6,28 @@ namespace facebook { namespace react { -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`: - // - // auto module = samplelibrary_ModuleProvider(moduleName, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(moduleName, params); + std::shared_ptr + MainApplicationModuleProvider( + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) + { + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`: + // + // auto module = samplelibrary_ModuleProvider(moduleName, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(moduleName, params); - // Module providers autolinked by RN CLI - auto rncli_module = rncli_ModuleProvider(moduleName, params); - if (rncli_module != nullptr) - { - return rncli_module; - } + // Module providers autolinked by RN CLI + auto rncli_module = rncli_ModuleProvider(moduleName, params); + if (rncli_module != nullptr) { + return rncli_module; + } - return rncore_ModuleProvider(moduleName, params); -} + return rncore_ModuleProvider(moduleName, params); + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.h b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.h index b38ccf53fd..a77063962a 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.h +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationModuleProvider.h @@ -8,9 +8,8 @@ namespace facebook { namespace react { -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms); + std::shared_ptr MainApplicationModuleProvider( + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp index 5fd688c509..6242cd6825 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp @@ -4,42 +4,43 @@ namespace facebook { namespace react { -jni::local_ref -MainApplicationTurboModuleManagerDelegate::initHybrid( - jni::alias_ref) { - return makeCxxInstance(); -} + jni::local_ref + MainApplicationTurboModuleManagerDelegate::initHybrid(jni::alias_ref) + { + return makeCxxInstance(); + } -void MainApplicationTurboModuleManagerDelegate::registerNatives() { - registerHybrid({ - makeNativeMethod( - "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), - makeNativeMethod( - "canCreateTurboModule", - MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), - }); -} + void + MainApplicationTurboModuleManagerDelegate::registerNatives() + { + registerHybrid({ + makeNativeMethod("initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), + makeNativeMethod("canCreateTurboModule", + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), + }); + } -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) { - // Not implemented yet: provide pure-C++ NativeModules here. - return nullptr; -} + std::shared_ptr + MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string &name, const std::shared_ptr &jsInvoker) + { + // Not implemented yet: provide pure-C++ NativeModules here. + return nullptr; + } -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) { - return MainApplicationModuleProvider(name, params); -} + std::shared_ptr + MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string &name, const JavaTurboModule::InitParams ¶ms) + { + return MainApplicationModuleProvider(name, params); + } -bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( - const std::string &name) { - return getTurboModule(name, nullptr) != nullptr || - getTurboModule(name, {.moduleName = name}) != nullptr; -} + bool + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(const std::string &name) + { + return getTurboModule(name, nullptr) != nullptr + || getTurboModule(name, { .moduleName = name }) != nullptr; + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h index 1393dc6212..36be4bb41f 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h @@ -7,32 +7,29 @@ namespace facebook { namespace react { -class MainApplicationTurboModuleManagerDelegate - : public jni::HybridClass< - MainApplicationTurboModuleManagerDelegate, - TurboModuleManagerDelegate> { - public: - // Adapt it to the package you used for your Java class. - static constexpr auto kJavaDescriptor = - "Lcom/testappsentry/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; - - static jni::local_ref initHybrid(jni::alias_ref); - - static void registerNatives(); - - std::shared_ptr getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) override; - std::shared_ptr getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) override; - - /** - * Test-only method. Allows user to verify whether a TurboModule can be - * created by instances of this class. - */ - bool canCreateTurboModule(const std::string &name); -}; + class MainApplicationTurboModuleManagerDelegate + : public jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + static constexpr auto kJavaDescriptor = "Lcom/testappsentry/newarchitecture/modules/" + "MainApplicationTurboModuleManagerDelegate;"; + + static jni::local_ref initHybrid(jni::alias_ref); + + static void registerNatives(); + + std::shared_ptr getTurboModule( + const std::string &name, const std::shared_ptr &jsInvoker) override; + std::shared_ptr getTurboModule( + const std::string &name, const JavaTurboModule::InitParams ¶ms) override; + + /** + * Test-only method. Allows user to verify whether a TurboModule can be + * created by instances of this class. + */ + bool canCreateTurboModule(const std::string &name); + }; } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.cpp b/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.cpp index 54f598a486..4338b2a3a1 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.cpp +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.cpp @@ -9,57 +9,56 @@ namespace facebook { namespace react { -MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} + MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) { } -std::shared_ptr -MainComponentsRegistry::sharedProviderRegistry() { - auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + std::shared_ptr + MainComponentsRegistry::sharedProviderRegistry() + { + auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); - // Autolinked providers registered by RN CLI - rncli_registerProviders(providerRegistry); + // Autolinked providers registered by RN CLI + rncli_registerProviders(providerRegistry); - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // AocViewerComponentDescriptor>()); - return providerRegistry; -} + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + return providerRegistry; + } -jni::local_ref -MainComponentsRegistry::initHybrid( - jni::alias_ref, - ComponentFactory *delegate) { - auto instance = makeCxxInstance(delegate); + jni::local_ref + MainComponentsRegistry::initHybrid(jni::alias_ref, ComponentFactory *delegate) + { + auto instance = makeCxxInstance(delegate); - auto buildRegistryFunction = - [](EventDispatcher::Weak const &eventDispatcher, - ContextContainer::Shared const &contextContainer) - -> ComponentDescriptorRegistry::Shared { - auto registry = MainComponentsRegistry::sharedProviderRegistry() - ->createComponentDescriptorRegistry( - {eventDispatcher, contextContainer}); + auto buildRegistryFunction = [](EventDispatcher::Weak const &eventDispatcher, + ContextContainer::Shared const &contextContainer) + -> ComponentDescriptorRegistry::Shared { + auto registry + = MainComponentsRegistry::sharedProviderRegistry() + ->createComponentDescriptorRegistry({ eventDispatcher, contextContainer }); - auto mutableRegistry = - std::const_pointer_cast(registry); + auto mutableRegistry = std::const_pointer_cast(registry); - mutableRegistry->setFallbackComponentDescriptor( - std::make_shared( - ComponentDescriptorParameters{ - eventDispatcher, contextContainer, nullptr})); + mutableRegistry->setFallbackComponentDescriptor( + std::make_shared( + ComponentDescriptorParameters { eventDispatcher, contextContainer, nullptr })); - return registry; - }; + return registry; + }; - delegate->buildRegistryFunction = buildRegistryFunction; - return instance; -} + delegate->buildRegistryFunction = buildRegistryFunction; + return instance; + } -void MainComponentsRegistry::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), - }); -} + void + MainComponentsRegistry::registerNatives() + { + registerHybrid({ + makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), + }); + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.h b/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.h index 8e550c678f..e63cfe462a 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.h +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/MainComponentsRegistry.h @@ -8,25 +8,22 @@ namespace facebook { namespace react { -class MainComponentsRegistry - : public facebook::jni::HybridClass { - public: - // Adapt it to the package you used for your Java class. - constexpr static auto kJavaDescriptor = - "Lcom/testappplain/newarchitecture/components/MainComponentsRegistry;"; + class MainComponentsRegistry : public facebook::jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + constexpr static auto kJavaDescriptor + = "Lcom/testappplain/newarchitecture/components/MainComponentsRegistry;"; - static void registerNatives(); + static void registerNatives(); - MainComponentsRegistry(ComponentFactory *delegate); + MainComponentsRegistry(ComponentFactory *delegate); - private: - static std::shared_ptr - sharedProviderRegistry(); + private: + static std::shared_ptr sharedProviderRegistry(); - static jni::local_ref initHybrid( - jni::alias_ref, - ComponentFactory *delegate); -}; + static jni::local_ref initHybrid( + jni::alias_ref, ComponentFactory *delegate); + }; } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppPlain/android/app/src/main/jni/OnLoad.cpp b/performance-tests/TestAppPlain/android/app/src/main/jni/OnLoad.cpp index c569b6e865..e1e387162a 100644 --- a/performance-tests/TestAppPlain/android/app/src/main/jni/OnLoad.cpp +++ b/performance-tests/TestAppPlain/android/app/src/main/jni/OnLoad.cpp @@ -1,11 +1,12 @@ -#include #include "MainApplicationTurboModuleManagerDelegate.h" #include "MainComponentsRegistry.h" +#include -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::MainApplicationTurboModuleManagerDelegate:: - registerNatives(); - facebook::react::MainComponentsRegistry::registerNatives(); - }); +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *) +{ + return facebook::jni::initialize(vm, [] { + facebook::react::MainApplicationTurboModuleManagerDelegate::registerNatives(); + facebook::react::MainComponentsRegistry::registerNatives(); + }); } diff --git a/performance-tests/TestAppPlain/ios/TestAppPlain/AppDelegate.mm b/performance-tests/TestAppPlain/ios/TestAppPlain/AppDelegate.mm index 32f576bc81..426fb5164f 100644 --- a/performance-tests/TestAppPlain/ios/TestAppPlain/AppDelegate.mm +++ b/performance-tests/TestAppPlain/ios/TestAppPlain/AppDelegate.mm @@ -7,57 +7,60 @@ #import #if RCT_NEW_ARCH_ENABLED -#import -#import -#import -#import -#import -#import +# import +# import +# import +# import +# import +# import -#import +# import static NSString *const kRNConcurrentRoot = @"concurrentRoot"; -@interface AppDelegate () { - RCTTurboModuleManager *_turboModuleManager; - RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; - std::shared_ptr _reactNativeConfig; - facebook::react::ContextContainer::Shared _contextContainer; +@interface +AppDelegate () { + RCTTurboModuleManager *_turboModuleManager; + RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; + std::shared_ptr _reactNativeConfig; + facebook::react::ContextContainer::Shared _contextContainer; } @end #endif @implementation AppDelegate -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - RCTAppSetupPrepareApp(application); + RCTAppSetupPrepareApp(application); - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; #if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; - bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge + contextContainer:_contextContainer]; + bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; #endif - NSDictionary *initProps = [self prepareInitialProps]; - UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"TestAppPlain", initProps); - - if (@available(iOS 13.0, *)) { - rootView.backgroundColor = [UIColor systemBackgroundColor]; - } else { - rootView.backgroundColor = [UIColor whiteColor]; - } - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; + NSDictionary *initProps = [self prepareInitialProps]; + UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"TestAppPlain", initProps); + + if (@available(iOS 13.0, *)) { + rootView.backgroundColor = [UIColor systemBackgroundColor]; + } else { + rootView.backgroundColor = [UIColor whiteColor]; + } + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [UIViewController new]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; } /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. @@ -67,65 +70,67 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. - (BOOL)concurrentRootEnabled { - // Switch this bool to turn on and off the concurrent root - return true; + // Switch this bool to turn on and off the concurrent root + return true; } - (NSDictionary *)prepareInitialProps { - NSMutableDictionary *initProps = [NSMutableDictionary new]; + NSMutableDictionary *initProps = [NSMutableDictionary new]; #ifdef RCT_NEW_ARCH_ENABLED - initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); + initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); #endif - return initProps; + return initProps; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } #if RCT_NEW_ARCH_ENABLED -#pragma mark - RCTCxxBridgeDelegate +# pragma mark - RCTCxxBridgeDelegate -- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge +- (std::unique_ptr)jsExecutorFactoryForBridge: + (RCTBridge *)bridge { - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); + _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:bridge.jsCallInvoker]; + return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); } -#pragma mark RCTTurboModuleManagerDelegate +# pragma mark RCTTurboModuleManagerDelegate - (Class)getModuleClassFromName:(const char *)name { - return RCTCoreModulesClassProvider(name); + return RCTCoreModulesClassProvider(name); } -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker +- (std::shared_ptr) + getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker { - return nullptr; + return nullptr; } -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params +- (std::shared_ptr) + getTurboModule:(const std::string &)name + initParams:(const facebook::react::ObjCTurboModule::InitParams &)params { - return nullptr; + return nullptr; } - (id)getModuleInstanceFromClass:(Class)moduleClass { - return RCTAppSetupDefaultModuleFromClass(moduleClass); + return RCTAppSetupDefaultModuleFromClass(moduleClass); } #endif diff --git a/performance-tests/TestAppPlain/ios/TestAppPlain/main.m b/performance-tests/TestAppPlain/ios/TestAppPlain/main.m index d645c7246c..742168d2e4 100644 --- a/performance-tests/TestAppPlain/ios/TestAppPlain/main.m +++ b/performance-tests/TestAppPlain/ios/TestAppPlain/main.m @@ -2,9 +2,10 @@ #import "AppDelegate.h" -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } } diff --git a/performance-tests/TestAppPlain/ios/TestAppPlainTests/TestAppPlainTests.m b/performance-tests/TestAppPlain/ios/TestAppPlainTests/TestAppPlainTests.m index 249dfa0cd5..7abbf13d6b 100644 --- a/performance-tests/TestAppPlain/ios/TestAppPlainTests/TestAppPlainTests.m +++ b/performance-tests/TestAppPlain/ios/TestAppPlainTests/TestAppPlainTests.m @@ -15,52 +15,56 @@ @implementation TestAppPlainTests - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test { - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; + if (test(view)) { + return YES; } - } - return NO; + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; } - (void)testRendersWelcomeScreen { - UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; - __block NSString *redboxError = nil; + __block NSString *redboxError = nil; #ifdef DEBUG - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, + NSNumber *lineNumber, NSString *message) { if (level >= RCTLogLevelError) { - redboxError = message; + redboxError = message; } - }); + }); #endif - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - foundElement = [self findSubviewInView:vc.view - matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } + foundElement = + [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } #ifdef DEBUG - RCTSetLogFunction(RCTDefaultLogFunction); + RCTSetLogFunction(RCTDefaultLogFunction); #endif - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", + TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); } @end diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.cpp index 23bc693960..70e1fce274 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.cpp +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.cpp @@ -6,28 +6,28 @@ namespace facebook { namespace react { -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`: - // - // auto module = samplelibrary_ModuleProvider(moduleName, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(moduleName, params); + std::shared_ptr + MainApplicationModuleProvider( + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) + { + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`: + // + // auto module = samplelibrary_ModuleProvider(moduleName, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(moduleName, params); - // Module providers autolinked by RN CLI - auto rncli_module = rncli_ModuleProvider(moduleName, params); - if (rncli_module != nullptr) - { - return rncli_module; - } + // Module providers autolinked by RN CLI + auto rncli_module = rncli_ModuleProvider(moduleName, params); + if (rncli_module != nullptr) { + return rncli_module; + } - return rncore_ModuleProvider(moduleName, params); -} + return rncore_ModuleProvider(moduleName, params); + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.h b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.h index b38ccf53fd..a77063962a 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.h +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationModuleProvider.h @@ -8,9 +8,8 @@ namespace facebook { namespace react { -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms); + std::shared_ptr MainApplicationModuleProvider( + const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp index 5fd688c509..6242cd6825 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp @@ -4,42 +4,43 @@ namespace facebook { namespace react { -jni::local_ref -MainApplicationTurboModuleManagerDelegate::initHybrid( - jni::alias_ref) { - return makeCxxInstance(); -} + jni::local_ref + MainApplicationTurboModuleManagerDelegate::initHybrid(jni::alias_ref) + { + return makeCxxInstance(); + } -void MainApplicationTurboModuleManagerDelegate::registerNatives() { - registerHybrid({ - makeNativeMethod( - "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), - makeNativeMethod( - "canCreateTurboModule", - MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), - }); -} + void + MainApplicationTurboModuleManagerDelegate::registerNatives() + { + registerHybrid({ + makeNativeMethod("initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), + makeNativeMethod("canCreateTurboModule", + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), + }); + } -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) { - // Not implemented yet: provide pure-C++ NativeModules here. - return nullptr; -} + std::shared_ptr + MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string &name, const std::shared_ptr &jsInvoker) + { + // Not implemented yet: provide pure-C++ NativeModules here. + return nullptr; + } -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) { - return MainApplicationModuleProvider(name, params); -} + std::shared_ptr + MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string &name, const JavaTurboModule::InitParams ¶ms) + { + return MainApplicationModuleProvider(name, params); + } -bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( - const std::string &name) { - return getTurboModule(name, nullptr) != nullptr || - getTurboModule(name, {.moduleName = name}) != nullptr; -} + bool + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(const std::string &name) + { + return getTurboModule(name, nullptr) != nullptr + || getTurboModule(name, { .moduleName = name }) != nullptr; + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h index 1393dc6212..36be4bb41f 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h @@ -7,32 +7,29 @@ namespace facebook { namespace react { -class MainApplicationTurboModuleManagerDelegate - : public jni::HybridClass< - MainApplicationTurboModuleManagerDelegate, - TurboModuleManagerDelegate> { - public: - // Adapt it to the package you used for your Java class. - static constexpr auto kJavaDescriptor = - "Lcom/testappsentry/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; - - static jni::local_ref initHybrid(jni::alias_ref); - - static void registerNatives(); - - std::shared_ptr getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) override; - std::shared_ptr getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) override; - - /** - * Test-only method. Allows user to verify whether a TurboModule can be - * created by instances of this class. - */ - bool canCreateTurboModule(const std::string &name); -}; + class MainApplicationTurboModuleManagerDelegate + : public jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + static constexpr auto kJavaDescriptor = "Lcom/testappsentry/newarchitecture/modules/" + "MainApplicationTurboModuleManagerDelegate;"; + + static jni::local_ref initHybrid(jni::alias_ref); + + static void registerNatives(); + + std::shared_ptr getTurboModule( + const std::string &name, const std::shared_ptr &jsInvoker) override; + std::shared_ptr getTurboModule( + const std::string &name, const JavaTurboModule::InitParams ¶ms) override; + + /** + * Test-only method. Allows user to verify whether a TurboModule can be + * created by instances of this class. + */ + bool canCreateTurboModule(const std::string &name); + }; } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.cpp b/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.cpp index 54f598a486..4338b2a3a1 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.cpp +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.cpp @@ -9,57 +9,56 @@ namespace facebook { namespace react { -MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} + MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) { } -std::shared_ptr -MainComponentsRegistry::sharedProviderRegistry() { - auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + std::shared_ptr + MainComponentsRegistry::sharedProviderRegistry() + { + auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); - // Autolinked providers registered by RN CLI - rncli_registerProviders(providerRegistry); + // Autolinked providers registered by RN CLI + rncli_registerProviders(providerRegistry); - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // AocViewerComponentDescriptor>()); - return providerRegistry; -} + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + return providerRegistry; + } -jni::local_ref -MainComponentsRegistry::initHybrid( - jni::alias_ref, - ComponentFactory *delegate) { - auto instance = makeCxxInstance(delegate); + jni::local_ref + MainComponentsRegistry::initHybrid(jni::alias_ref, ComponentFactory *delegate) + { + auto instance = makeCxxInstance(delegate); - auto buildRegistryFunction = - [](EventDispatcher::Weak const &eventDispatcher, - ContextContainer::Shared const &contextContainer) - -> ComponentDescriptorRegistry::Shared { - auto registry = MainComponentsRegistry::sharedProviderRegistry() - ->createComponentDescriptorRegistry( - {eventDispatcher, contextContainer}); + auto buildRegistryFunction = [](EventDispatcher::Weak const &eventDispatcher, + ContextContainer::Shared const &contextContainer) + -> ComponentDescriptorRegistry::Shared { + auto registry + = MainComponentsRegistry::sharedProviderRegistry() + ->createComponentDescriptorRegistry({ eventDispatcher, contextContainer }); - auto mutableRegistry = - std::const_pointer_cast(registry); + auto mutableRegistry = std::const_pointer_cast(registry); - mutableRegistry->setFallbackComponentDescriptor( - std::make_shared( - ComponentDescriptorParameters{ - eventDispatcher, contextContainer, nullptr})); + mutableRegistry->setFallbackComponentDescriptor( + std::make_shared( + ComponentDescriptorParameters { eventDispatcher, contextContainer, nullptr })); - return registry; - }; + return registry; + }; - delegate->buildRegistryFunction = buildRegistryFunction; - return instance; -} + delegate->buildRegistryFunction = buildRegistryFunction; + return instance; + } -void MainComponentsRegistry::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), - }); -} + void + MainComponentsRegistry::registerNatives() + { + registerHybrid({ + makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), + }); + } } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.h b/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.h index e5fb647396..c9466dcc43 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.h +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/MainComponentsRegistry.h @@ -8,25 +8,22 @@ namespace facebook { namespace react { -class MainComponentsRegistry - : public facebook::jni::HybridClass { - public: - // Adapt it to the package you used for your Java class. - constexpr static auto kJavaDescriptor = - "Lcom/testappsentry/newarchitecture/components/MainComponentsRegistry;"; + class MainComponentsRegistry : public facebook::jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + constexpr static auto kJavaDescriptor + = "Lcom/testappsentry/newarchitecture/components/MainComponentsRegistry;"; - static void registerNatives(); + static void registerNatives(); - MainComponentsRegistry(ComponentFactory *delegate); + MainComponentsRegistry(ComponentFactory *delegate); - private: - static std::shared_ptr - sharedProviderRegistry(); + private: + static std::shared_ptr sharedProviderRegistry(); - static jni::local_ref initHybrid( - jni::alias_ref, - ComponentFactory *delegate); -}; + static jni::local_ref initHybrid( + jni::alias_ref, ComponentFactory *delegate); + }; } // namespace react } // namespace facebook diff --git a/performance-tests/TestAppSentry/android/app/src/main/jni/OnLoad.cpp b/performance-tests/TestAppSentry/android/app/src/main/jni/OnLoad.cpp index c569b6e865..e1e387162a 100644 --- a/performance-tests/TestAppSentry/android/app/src/main/jni/OnLoad.cpp +++ b/performance-tests/TestAppSentry/android/app/src/main/jni/OnLoad.cpp @@ -1,11 +1,12 @@ -#include #include "MainApplicationTurboModuleManagerDelegate.h" #include "MainComponentsRegistry.h" +#include -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::MainApplicationTurboModuleManagerDelegate:: - registerNatives(); - facebook::react::MainComponentsRegistry::registerNatives(); - }); +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *) +{ + return facebook::jni::initialize(vm, [] { + facebook::react::MainApplicationTurboModuleManagerDelegate::registerNatives(); + facebook::react::MainComponentsRegistry::registerNatives(); + }); } diff --git a/performance-tests/TestAppSentry/ios/TestAppSentry/AppDelegate.mm b/performance-tests/TestAppSentry/ios/TestAppSentry/AppDelegate.mm index a1ff54fe5c..729d9941e9 100644 --- a/performance-tests/TestAppSentry/ios/TestAppSentry/AppDelegate.mm +++ b/performance-tests/TestAppSentry/ios/TestAppSentry/AppDelegate.mm @@ -7,57 +7,60 @@ #import #if RCT_NEW_ARCH_ENABLED -#import -#import -#import -#import -#import -#import +# import +# import +# import +# import +# import +# import -#import +# import static NSString *const kRNConcurrentRoot = @"concurrentRoot"; -@interface AppDelegate () { - RCTTurboModuleManager *_turboModuleManager; - RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; - std::shared_ptr _reactNativeConfig; - facebook::react::ContextContainer::Shared _contextContainer; +@interface +AppDelegate () { + RCTTurboModuleManager *_turboModuleManager; + RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; + std::shared_ptr _reactNativeConfig; + facebook::react::ContextContainer::Shared _contextContainer; } @end #endif @implementation AppDelegate -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - RCTAppSetupPrepareApp(application); + RCTAppSetupPrepareApp(application); - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; #if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; - bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge + contextContainer:_contextContainer]; + bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; #endif - NSDictionary *initProps = [self prepareInitialProps]; - UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"TestAppSentry", initProps); - - if (@available(iOS 13.0, *)) { - rootView.backgroundColor = [UIColor systemBackgroundColor]; - } else { - rootView.backgroundColor = [UIColor whiteColor]; - } - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; + NSDictionary *initProps = [self prepareInitialProps]; + UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"TestAppSentry", initProps); + + if (@available(iOS 13.0, *)) { + rootView.backgroundColor = [UIColor systemBackgroundColor]; + } else { + rootView.backgroundColor = [UIColor whiteColor]; + } + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [UIViewController new]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; } /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. @@ -67,65 +70,67 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. - (BOOL)concurrentRootEnabled { - // Switch this bool to turn on and off the concurrent root - return true; + // Switch this bool to turn on and off the concurrent root + return true; } - (NSDictionary *)prepareInitialProps { - NSMutableDictionary *initProps = [NSMutableDictionary new]; + NSMutableDictionary *initProps = [NSMutableDictionary new]; #ifdef RCT_NEW_ARCH_ENABLED - initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); + initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); #endif - return initProps; + return initProps; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } #if RCT_NEW_ARCH_ENABLED -#pragma mark - RCTCxxBridgeDelegate +# pragma mark - RCTCxxBridgeDelegate -- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge +- (std::unique_ptr)jsExecutorFactoryForBridge: + (RCTBridge *)bridge { - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); + _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:bridge.jsCallInvoker]; + return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); } -#pragma mark RCTTurboModuleManagerDelegate +# pragma mark RCTTurboModuleManagerDelegate - (Class)getModuleClassFromName:(const char *)name { - return RCTCoreModulesClassProvider(name); + return RCTCoreModulesClassProvider(name); } -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker +- (std::shared_ptr) + getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker { - return nullptr; + return nullptr; } -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params +- (std::shared_ptr) + getTurboModule:(const std::string &)name + initParams:(const facebook::react::ObjCTurboModule::InitParams &)params { - return nullptr; + return nullptr; } - (id)getModuleInstanceFromClass:(Class)moduleClass { - return RCTAppSetupDefaultModuleFromClass(moduleClass); + return RCTAppSetupDefaultModuleFromClass(moduleClass); } #endif diff --git a/performance-tests/TestAppSentry/ios/TestAppSentry/main.m b/performance-tests/TestAppSentry/ios/TestAppSentry/main.m index d645c7246c..742168d2e4 100644 --- a/performance-tests/TestAppSentry/ios/TestAppSentry/main.m +++ b/performance-tests/TestAppSentry/ios/TestAppSentry/main.m @@ -2,9 +2,10 @@ #import "AppDelegate.h" -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } } diff --git a/performance-tests/TestAppSentry/ios/TestAppSentryTests/TestAppSentryTests.m b/performance-tests/TestAppSentry/ios/TestAppSentryTests/TestAppSentryTests.m index 33ae29a52c..bce8f7d71e 100644 --- a/performance-tests/TestAppSentry/ios/TestAppSentryTests/TestAppSentryTests.m +++ b/performance-tests/TestAppSentry/ios/TestAppSentryTests/TestAppSentryTests.m @@ -15,52 +15,56 @@ @implementation TestAppSentryTests - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test { - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; + if (test(view)) { + return YES; } - } - return NO; + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; } - (void)testRendersWelcomeScreen { - UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; - __block NSString *redboxError = nil; + __block NSString *redboxError = nil; #ifdef DEBUG - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, + NSNumber *lineNumber, NSString *message) { if (level >= RCTLogLevelError) { - redboxError = message; + redboxError = message; } - }); + }); #endif - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - foundElement = [self findSubviewInView:vc.view - matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } + foundElement = + [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } #ifdef DEBUG - RCTSetLogFunction(RCTDefaultLogFunction); + RCTSetLogFunction(RCTDefaultLogFunction); #endif - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", + TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); } @end diff --git a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.h b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.h index 63db973168..1c6ff45148 100644 --- a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.h +++ b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.h @@ -1,5 +1,5 @@ -#import #import +#import @interface AppDelegate : RCTAppDelegate diff --git a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.mm b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.mm index d33f0d7f39..3cb5dff1a5 100644 --- a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.mm +++ b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/AppDelegate.mm @@ -6,20 +6,20 @@ @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)notification { - self.moduleName = @"sentry-react-native-sample"; - // You can add your custom initial props in the dictionary below. - // They will be passed down to the ViewController used by React Native. - self.initialProps = @{}; + self.moduleName = @"sentry-react-native-sample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; - return [super applicationDidFinishLaunching:notification]; + return [super applicationDidFinishLaunching:notification]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } @@ -31,9 +31,9 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge - (BOOL)concurrentRootEnabled { #ifdef RN_FABRIC_ENABLED - return true; + return true; #else - return false; + return false; #endif } diff --git a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/main.m b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/main.m index 1f154fcf69..71875488f7 100644 --- a/samples/react-native-macos/macos/sentry-react-native-sample-macOS/main.m +++ b/samples/react-native-macos/macos/sentry-react-native-sample-macOS/main.m @@ -1,5 +1,7 @@ #import -int main(int argc, const char *argv[]) { - return NSApplicationMain(argc, argv); +int +main(int argc, const char *argv[]) +{ + return NSApplicationMain(argc, argv); } diff --git a/samples/react-native/android/app/src/main/jni/OnLoad.cpp b/samples/react-native/android/app/src/main/jni/OnLoad.cpp index f7425ab605..6cbb3d648d 100644 --- a/samples/react-native/android/app/src/main/jni/OnLoad.cpp +++ b/samples/react-native/android/app/src/main/jni/OnLoad.cpp @@ -35,97 +35,99 @@ #include #ifdef REACT_NATIVE_APP_CODEGEN_HEADER -#include REACT_NATIVE_APP_CODEGEN_HEADER +# include REACT_NATIVE_APP_CODEGEN_HEADER #endif #ifdef REACT_NATIVE_APP_COMPONENT_DESCRIPTORS_HEADER -#include REACT_NATIVE_APP_COMPONENT_DESCRIPTORS_HEADER +# include REACT_NATIVE_APP_COMPONENT_DESCRIPTORS_HEADER #endif namespace facebook::react { -void registerComponents( - std::shared_ptr registry) { - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // MyComponentDescriptor>()); +void +registerComponents(std::shared_ptr registry) +{ + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // MyComponentDescriptor>()); - // We link app local components if available + // We link app local components if available #ifdef REACT_NATIVE_APP_COMPONENT_REGISTRATION - REACT_NATIVE_APP_COMPONENT_REGISTRATION(registry); + REACT_NATIVE_APP_COMPONENT_REGISTRATION(registry); #endif - // And we fallback to the components autolinked - autolinking_registerProviders(registry); + // And we fallback to the components autolinked + autolinking_registerProviders(registry); } -std::shared_ptr cxxModuleProvider( - const std::string& name, - const std::shared_ptr& jsInvoker) { - // Here you can provide your CXX Turbo Modules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a module called `NativeCxxModuleExample`): - // - // if (name == NativeCxxModuleExample::kModuleName) { - // return std::make_shared(jsInvoker); - // } - - // And we fallback to the CXX module providers autolinked - return autolinking_cxxModuleProvider(name, jsInvoker); +std::shared_ptr +cxxModuleProvider(const std::string &name, const std::shared_ptr &jsInvoker) +{ + // Here you can provide your CXX Turbo Modules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a module called `NativeCxxModuleExample`): + // + // if (name == NativeCxxModuleExample::kModuleName) { + // return std::make_shared(jsInvoker); + // } + + // And we fallback to the CXX module providers autolinked + return autolinking_cxxModuleProvider(name, jsInvoker); } -std::shared_ptr javaModuleProvider( - const std::string& name, - const JavaTurboModule::InitParams& params) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`): - // - // auto module = samplelibrary_ModuleProvider(name, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(name, params); - - // We link app local modules if available +std::shared_ptr +javaModuleProvider(const std::string &name, const JavaTurboModule::InitParams ¶ms) +{ + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`): + // + // auto module = samplelibrary_ModuleProvider(name, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(name, params); + + // We link app local modules if available #ifdef REACT_NATIVE_APP_MODULE_PROVIDER - auto module = REACT_NATIVE_APP_MODULE_PROVIDER(name, params); - if (module != nullptr) { - return module; - } + auto module = REACT_NATIVE_APP_MODULE_PROVIDER(name, params); + if (module != nullptr) { + return module; + } #endif - // We first try to look up core modules - if (auto module = rncore_ModuleProvider(name, params)) { - return module; - } + // We first try to look up core modules + if (auto module = rncore_ModuleProvider(name, params)) { + return module; + } - // And we fallback to the module providers autolinked - if (auto module = autolinking_ModuleProvider(name, params)) { - return module; - } + // And we fallback to the module providers autolinked + if (auto module = autolinking_ModuleProvider(name, params)) { + return module; + } - return nullptr; + return nullptr; } } // namespace facebook::react -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { - return facebook::jni::initialize(vm, [] { - facebook::react::DefaultTurboModuleManagerDelegate::cxxModuleProvider = - &facebook::react::cxxModuleProvider; - facebook::react::DefaultTurboModuleManagerDelegate::javaModuleProvider = - &facebook::react::javaModuleProvider; - facebook::react::DefaultComponentsRegistry:: - registerComponentDescriptorsFromEntryPoint = - &facebook::react::registerComponents; - }); +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *) +{ + return facebook::jni::initialize(vm, [] { + facebook::react::DefaultTurboModuleManagerDelegate::cxxModuleProvider + = &facebook::react::cxxModuleProvider; + facebook::react::DefaultTurboModuleManagerDelegate::javaModuleProvider + = &facebook::react::javaModuleProvider; + facebook::react::DefaultComponentsRegistry::registerComponentDescriptorsFromEntryPoint + = &facebook::react::registerComponents; + }); } -extern "C" -JNIEXPORT void JNICALL -Java_io_sentry_reactnative_sample_SamplePackage_crash(JNIEnv *env, jobject thiz) { - char *ptr = 0; - *ptr += 1; +extern "C" JNIEXPORT void JNICALL +Java_io_sentry_reactnative_sample_SamplePackage_crash(JNIEnv *env, jobject thiz) +{ + char *ptr = 0; + *ptr += 1; } diff --git a/samples/react-native/ios/sentryreactnativesample/AppDelegate.mm b/samples/react-native/ios/sentryreactnativesample/AppDelegate.mm index 1fe2052e1e..0321e65bc4 100644 --- a/samples/react-native/ios/sentryreactnativesample/AppDelegate.mm +++ b/samples/react-native/ios/sentryreactnativesample/AppDelegate.mm @@ -1,76 +1,81 @@ #import "AppDelegate.h" -#import #import +#import #import #ifdef RCT_NEW_ARCH_ENABLED -#import +# import #endif -#import #import +#import -@interface AppDelegate () {} +@interface +AppDelegate () { +} @end @implementation AppDelegate -- (void) initializeSentry +- (void)initializeSentry { - [SentrySDK startWithConfigureOptions:^(SentryOptions *options) { - // Only options set here will apply to the iOS SDK - // Options from JS are not passed to the iOS SDK when initialized manually - options.dsn = @"https://1df17bd4e543fdb31351dee1768bb679@o447951.ingest.sentry.io/5428561"; - options.debug = YES; // Enabled debug when first installing is always helpful - - options.beforeSend = ^SentryEvent*(SentryEvent *event) { - // We don't want to send an event after startup that came from a Unhandled JS Exception of react native - // Because we sent it already before the app crashed. - if (nil != event.exceptions.firstObject.type && - [event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) { - NSLog(@"Unhandled JS Exception"); - return nil; - } - - return event; - }; - - // Enable the App start and Frames tracking measurements - // If this is disabled the app start and frames tracking - // won't be passed from native to JS transactions - PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = true; + [SentrySDK startWithConfigureOptions:^(SentryOptions *options) { + // Only options set here will apply to the iOS SDK + // Options from JS are not passed to the iOS SDK when initialized manually + options.dsn = @"https://1df17bd4e543fdb31351dee1768bb679@o447951.ingest.sentry.io/5428561"; + options.debug = YES; // Enabled debug when first installing is always helpful + + options.beforeSend = ^SentryEvent *(SentryEvent *event) + { + // We don't want to send an event after startup that came from a Unhandled JS Exception + // of react native Because we sent it already before the app crashed. + if (nil != event.exceptions.firstObject.type && + [event.exceptions.firstObject.type rangeOfString:@"Unhandled JS Exception"].location + != NSNotFound) { + NSLog(@"Unhandled JS Exception"); + return nil; + } + + return event; + }; + + // Enable the App start and Frames tracking measurements + // If this is disabled the app start and frames tracking + // won't be passed from native to JS transactions + PrivateSentrySDKOnly.appStartMeasurementHybridSDKMode = true; #if TARGET_OS_IPHONE || TARGET_OS_MACCATALYST - PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode = true; + PrivateSentrySDKOnly.framesTrackingMeasurementHybridSDKMode = true; #endif - }]; + }]; } -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // When the native init is enabled the `autoInitializeNativeSdk` - // in JS has to be set to `false` - // [self initializeSentry]; + // When the native init is enabled the `autoInitializeNativeSdk` + // in JS has to be set to `false` + // [self initializeSentry]; - self.moduleName = @"sentry-react-native-sample"; - // You can add your custom initial props in the dictionary below. - // They will be passed down to the ViewController used by React - self.initialProps = @{}; + self.moduleName = @"sentry-react-native-sample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React + self.initialProps = @{}; - return [super application:application didFinishLaunchingWithOptions:launchOptions]; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { - return [self bundleURL]; + return [self bundleURL]; } - (NSURL *)bundleURL { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } @@ -81,20 +86,21 @@ - (NSURL *)bundleURL /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. - (BOOL)concurrentRootEnabled { - return true; + return true; } #pragma mark RCTTurboModuleManagerDelegate -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker +- (std::shared_ptr) + getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker { #ifdef RCT_NEW_ARCH_ENABLED - if (name == "NativeSampleModule") { - return std::make_shared(jsInvoker); - } + if (name == "NativeSampleModule") { + return std::make_shared(jsInvoker); + } #endif - return nullptr; + return nullptr; } @end diff --git a/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.h b/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.h index ceac888bef..fb83052a55 100644 --- a/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.h +++ b/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.h @@ -1,7 +1,7 @@ #import #ifdef RCT_NEW_ARCH_ENABLED -#import +# import @interface NativePlatformSampleModule : NSObject diff --git a/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.mm b/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.mm index 09c572d125..80c31d1b3a 100644 --- a/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.mm +++ b/samples/react-native/ios/sentryreactnativesample/NativePlatformSampleModule.mm @@ -7,14 +7,17 @@ @implementation NativePlatformSampleModule RCT_EXPORT_MODULE(); // Thanks to this guard, we won't compile this code when we build for the old architecture. -- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { - return std::make_shared(params); +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); } -- (NSString *)crashOrString { - NSObject * nilObject = NULL; - NSArray * _ = @[nilObject]; - return @"NEVER RETURNED"; +- (NSString *)crashOrString +{ + NSObject *nilObject = NULL; + NSArray *_ = @[ nilObject ]; + return @"NEVER RETURNED"; } @end diff --git a/samples/react-native/ios/sentryreactnativesample/RCTAssetsModule.m b/samples/react-native/ios/sentryreactnativesample/RCTAssetsModule.m index dc9fd70635..87c570adea 100644 --- a/samples/react-native/ios/sentryreactnativesample/RCTAssetsModule.m +++ b/samples/react-native/ios/sentryreactnativesample/RCTAssetsModule.m @@ -2,27 +2,26 @@ @implementation RCTAssetsModule -RCT_EXPORT_METHOD(getExampleAssetData: (RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(getExampleAssetData + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { - NSDataAsset *data = [[NSDataAsset alloc] initWithName:@"ExampleBinaryData"]; - if (data == nil) { - reject(@"SampleSentryReactNative",@"Failed to load exmaple binary data asset.", nil); - } + NSDataAsset *data = [[NSDataAsset alloc] initWithName:@"ExampleBinaryData"]; + if (data == nil) { + reject(@"SampleSentryReactNative", @"Failed to load exmaple binary data asset.", nil); + } - NSMutableArray *array = [NSMutableArray arrayWithCapacity:data.data.length]; + NSMutableArray *array = [NSMutableArray arrayWithCapacity:data.data.length]; - const char *bytes = [data.data bytes]; + const char *bytes = [data.data bytes]; - for (int i = 0; i < [data.data length]; i++) - { - [array addObject:[[NSNumber alloc] initWithChar:bytes[i]]]; - } + for (int i = 0; i < [data.data length]; i++) { + [array addObject:[[NSNumber alloc] initWithChar:bytes[i]]]; + } - resolve(array); + resolve(array); } RCT_EXPORT_MODULE(AssetsModule); @end - diff --git a/samples/react-native/ios/sentryreactnativesample/main.m b/samples/react-native/ios/sentryreactnativesample/main.m index d645c7246c..742168d2e4 100644 --- a/samples/react-native/ios/sentryreactnativesample/main.m +++ b/samples/react-native/ios/sentryreactnativesample/main.m @@ -2,9 +2,10 @@ #import "AppDelegate.h" -int main(int argc, char *argv[]) +int +main(int argc, char *argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } } diff --git a/samples/react-native/ios/sentryreactnativesampleTests/sentryreactnativesampleTests.m b/samples/react-native/ios/sentryreactnativesampleTests/sentryreactnativesampleTests.m index 0eb5dfb8ab..68e29d1ec5 100644 --- a/samples/react-native/ios/sentryreactnativesampleTests/sentryreactnativesampleTests.m +++ b/samples/react-native/ios/sentryreactnativesampleTests/sentryreactnativesampleTests.m @@ -15,52 +15,56 @@ @implementation sentryreactnativesampleTests - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test { - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; + if (test(view)) { + return YES; } - } - return NO; + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; } - (void)testRendersWelcomeScreen { - UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; - __block NSString *redboxError = nil; + __block NSString *redboxError = nil; #ifdef DEBUG - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, + NSNumber *lineNumber, NSString *message) { if (level >= RCTLogLevelError) { - redboxError = message; + redboxError = message; } - }); + }); #endif - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes + beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - foundElement = [self findSubviewInView:vc.view - matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } + foundElement = + [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } #ifdef DEBUG - RCTSetLogFunction(RCTDefaultLogFunction); + RCTSetLogFunction(RCTDefaultLogFunction); #endif - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", + TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); } @end diff --git a/samples/react-native/tm/NativeSampleModule.cpp b/samples/react-native/tm/NativeSampleModule.cpp index 529463cf16..718f42bba4 100644 --- a/samples/react-native/tm/NativeSampleModule.cpp +++ b/samples/react-native/tm/NativeSampleModule.cpp @@ -1,14 +1,16 @@ #include "NativeSampleModule.h" -namespace facebook::react -{ +namespace facebook::react { - NativeSampleModule::NativeSampleModule(std::shared_ptr jsInvoker) - : NativeSampleModuleCxxSpec(std::move(jsInvoker)) {} +NativeSampleModule::NativeSampleModule(std::shared_ptr jsInvoker) + : NativeSampleModuleCxxSpec(std::move(jsInvoker)) +{ +} - void NativeSampleModule::crash(jsi::Runtime &rt) - { +void +NativeSampleModule::crash(jsi::Runtime &rt) +{ throw std::runtime_error("Error from native cxx module"); - } +} } // namespace facebook::react diff --git a/samples/react-native/tm/NativeSampleModule.h b/samples/react-native/tm/NativeSampleModule.h index 38ef640842..c37cd715c9 100644 --- a/samples/react-native/tm/NativeSampleModule.h +++ b/samples/react-native/tm/NativeSampleModule.h @@ -1,22 +1,20 @@ #pragma once #if __has_include() // CocoaPod headers on Apple -#include +# include #elif __has_include("AppSpecsJSI.h") // CMake headers on Android -#include "AppSpecsJSI.h" +# include "AppSpecsJSI.h" #endif #include #include -namespace facebook::react -{ +namespace facebook::react { - class NativeSampleModule : public NativeSampleModuleCxxSpec - { - public: +class NativeSampleModule : public NativeSampleModuleCxxSpec { +public: NativeSampleModule(std::shared_ptr jsInvoker); void crash(jsi::Runtime &rt); - }; +}; } // namespace facebook::react From eb9d2deb908af66aaff573c4e152faddbdfc9c1b Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 4 Nov 2024 18:08:37 +0100 Subject: [PATCH 04/39] fix clang format --- packages/core/ios/Replay/RNSentryReplayMask.h | 2 +- packages/core/ios/Replay/RNSentryReplayUnmask.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/ios/Replay/RNSentryReplayMask.h b/packages/core/ios/Replay/RNSentryReplayMask.h index a5d46bc477..759d3ab031 100644 --- a/packages/core/ios/Replay/RNSentryReplayMask.h +++ b/packages/core/ios/Replay/RNSentryReplayMask.h @@ -1,5 +1,5 @@ -#import #import +#import @interface RNSentryReplayMaskManager : RCTViewManager @end diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.h b/packages/core/ios/Replay/RNSentryReplayUnmask.h index 9c4268b526..683c67b181 100644 --- a/packages/core/ios/Replay/RNSentryReplayUnmask.h +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.h @@ -1,5 +1,5 @@ -#import #import +#import @interface RNSentryReplayUnmaskManager : RCTViewManager @end From cbf400a61baf7497cdb0eacd1beb961ca373e54e Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 5 Nov 2024 16:33:32 +0100 Subject: [PATCH 05/39] add native architecture masks for ios --- packages/core/.npmignore | 2 +- packages/core/ios/RNSentryReplay.m | 5 ++ packages/core/ios/Replay/RNSentryReplayMask.h | 15 +++++- packages/core/ios/Replay/RNSentryReplayMask.m | 16 ------ .../core/ios/Replay/RNSentryReplayMask.mm | 45 ++++++++++++++++ .../core/ios/Replay/RNSentryReplayUnmask.h | 15 +++++- .../core/ios/Replay/RNSentryReplayUnmask.m | 16 ------ .../core/ios/Replay/RNSentryReplayUnmask.mm | 45 ++++++++++++++++ packages/core/package.json | 3 +- .../js/RNSentryReplayMaskNativeComponent.ts | 8 +++ .../js/RNSentryReplayUnmaskNativeComponent.ts | 8 +++ packages/core/src/js/index.ts | 2 +- packages/core/src/js/replay/CustomMask.tsx | 52 +++++++++++++++++++ .../core/src/js/replay/CustomMask.web.tsx | 18 +++++++ packages/core/src/js/replay/customRedact.tsx | 34 ------------ packages/core/tsconfig.json | 1 + samples/react-native/metro.config.js | 2 +- samples/react-native/src/App.tsx | 2 +- .../src/Screens/PlaygroundScreen.tsx | 10 ++-- 19 files changed, 219 insertions(+), 80 deletions(-) delete mode 100644 packages/core/ios/Replay/RNSentryReplayMask.m create mode 100644 packages/core/ios/Replay/RNSentryReplayMask.mm delete mode 100644 packages/core/ios/Replay/RNSentryReplayUnmask.m create mode 100644 packages/core/ios/Replay/RNSentryReplayUnmask.mm create mode 100644 packages/core/src/js/RNSentryReplayMaskNativeComponent.ts create mode 100644 packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts create mode 100644 packages/core/src/js/replay/CustomMask.tsx create mode 100644 packages/core/src/js/replay/CustomMask.web.tsx delete mode 100644 packages/core/src/js/replay/customRedact.tsx diff --git a/packages/core/.npmignore b/packages/core/.npmignore index 6a301a4784..19f604c323 100644 --- a/packages/core/.npmignore +++ b/packages/core/.npmignore @@ -11,7 +11,7 @@ !react-native.config.js !/ios/**/* !/android/**/* -!src/js/NativeRNSentry.ts +!src/**/* !scripts/collect-modules.sh !scripts/copy-debugid.js !scripts/has-sourcemap-debugid.js diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index 59d8dfbbf2..d403c5a1fa 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -1,6 +1,8 @@ #import "RNSentryReplay.h" #import "RNSentryReplayBreadcrumbConverter.h" #import "React/RCTTextView.h" +#import "Replay/RNSentryReplayMask.h" +#import "Replay/RNSentryReplayUnmask.h" #if SENTRY_TARGET_REPLAY_SUPPORTED @@ -41,6 +43,9 @@ + (void)updateOptions:(NSMutableDictionary *)options + (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; + [classesToRedact addObject:RNSentryReplayMask.class]; + [classesToRedact addObject:RNSentryReplayUnmask.class]; + if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView"); if (maybeRNSVGViewClass != nil) { diff --git a/packages/core/ios/Replay/RNSentryReplayMask.h b/packages/core/ios/Replay/RNSentryReplayMask.h index 759d3ab031..e761e18b98 100644 --- a/packages/core/ios/Replay/RNSentryReplayMask.h +++ b/packages/core/ios/Replay/RNSentryReplayMask.h @@ -1,8 +1,19 @@ -#import #import +#import + +#ifdef RCT_NEW_ARCH_ENABLED +# import +#else +# import +#endif @interface RNSentryReplayMaskManager : RCTViewManager @end -@interface RNSentryReplayMask : RCTView +@interface RNSentryReplayMask : +#ifdef RCT_NEW_ARCH_ENABLED + RCTViewComponentView +#else + RCTView +#endif @end diff --git a/packages/core/ios/Replay/RNSentryReplayMask.m b/packages/core/ios/Replay/RNSentryReplayMask.m deleted file mode 100644 index 4f0cb7f1cc..0000000000 --- a/packages/core/ios/Replay/RNSentryReplayMask.m +++ /dev/null @@ -1,16 +0,0 @@ -#import "RNSentryReplayMask.h" - -@implementation RNSentryReplayMaskManager - -RCT_EXPORT_MODULE(RNSentryReplayMask) - -- (UIView *)view -{ - return [RNSentryReplayMask new]; -} - -@end - -@implementation RNSentryReplayMask - -@end diff --git a/packages/core/ios/Replay/RNSentryReplayMask.mm b/packages/core/ios/Replay/RNSentryReplayMask.mm new file mode 100644 index 0000000000..d1b92f21a6 --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayMask.mm @@ -0,0 +1,45 @@ +#import "RNSentryReplayMask.h" + +#ifdef RCT_NEW_ARCH_ENABLED +# import +# import +// RCTFabricComponentsPlugins needed for RNSentryReplayMaskCls +# import +#endif + +@implementation RNSentryReplayMaskManager + +RCT_EXPORT_MODULE(RNSentryReplayMask) + +- (UIView *)view +{ + return [RNSentryReplayMask new]; +} + +@end + +#ifdef RCT_NEW_ARCH_ENABLED +@interface +RNSentryReplayMask () +@end +#endif + +@implementation RNSentryReplayMask + +#ifdef RCT_NEW_ARCH_ENABLED ++ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider +{ + return facebook::react::concreteComponentDescriptorProvider< + facebook::react::RNSentryReplayMaskComponentDescriptor>(); +} +#endif + +@end + +#ifdef RCT_NEW_ARCH_ENABLED +Class +RNSentryReplayMaskCls(void) +{ + return RNSentryReplayMask.class; +} +#endif diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.h b/packages/core/ios/Replay/RNSentryReplayUnmask.h index 683c67b181..3a18fa9c54 100644 --- a/packages/core/ios/Replay/RNSentryReplayUnmask.h +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.h @@ -1,8 +1,19 @@ -#import #import +#import + +#ifdef RCT_NEW_ARCH_ENABLED +# import +#else +# import +#endif @interface RNSentryReplayUnmaskManager : RCTViewManager @end -@interface RNSentryReplayUnmask : RCTView +@interface RNSentryReplayUnmask : +#ifdef RCT_NEW_ARCH_ENABLED + RCTViewComponentView +#else + RCTView +#endif @end diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.m b/packages/core/ios/Replay/RNSentryReplayUnmask.m deleted file mode 100644 index f0a018a82b..0000000000 --- a/packages/core/ios/Replay/RNSentryReplayUnmask.m +++ /dev/null @@ -1,16 +0,0 @@ -#import "RNSentryReplayUnmask.h" - -@implementation RNSentryReplayUnmaskManager - -RCT_EXPORT_MODULE(RNSentryReplayUnmask) - -- (UIView *)view -{ - return [RNSentryReplayUnmask new]; -} - -@end - -@implementation RNSentryReplayUnmask - -@end diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.mm b/packages/core/ios/Replay/RNSentryReplayUnmask.mm new file mode 100644 index 0000000000..2522538d20 --- /dev/null +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.mm @@ -0,0 +1,45 @@ +#import "RNSentryReplayUnmask.h" + +#ifdef RCT_NEW_ARCH_ENABLED +# import +# import +// RCTFabricComponentsPlugins needed for RNSentryReplayUnmaskCls +# import +#endif + +@implementation RNSentryReplayUnmaskManager + +RCT_EXPORT_MODULE(RNSentryReplayUnmask) + +- (UIView *)view +{ + return [RNSentryReplayUnmask new]; +} + +@end + +#ifdef RCT_NEW_ARCH_ENABLED +@interface +RNSentryReplayUnmask () +@end +#endif + +@implementation RNSentryReplayUnmask + +#ifdef RCT_NEW_ARCH_ENABLED ++ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider +{ + return facebook::react::concreteComponentDescriptorProvider< + facebook::react::RNSentryReplayUnmaskComponentDescriptor>(); +} +#endif + +@end + +#ifdef RCT_NEW_ARCH_ENABLED +Class +RNSentryReplayUnmaskCls(void) +{ + return RNSentryReplayUnmask.class; +} +#endif diff --git a/packages/core/package.json b/packages/core/package.json index 0f7c5be237..2756d5ee44 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,6 +16,7 @@ "typescript": { "definition": "dist/js/index.d.ts" }, + "react-native": "src/js/index.ts", "main": "dist/js/index.js", "scripts": { "build": "npx run-s build:sdk downlevel build:tools build:plugin", @@ -118,7 +119,7 @@ }, "codegenConfig": { "name": "RNSentrySpec", - "type": "modules", + "type": "all", "jsSrcsDir": "src", "android": { "javaPackageName": "io.sentry.react" diff --git a/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts b/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts new file mode 100644 index 0000000000..223680179d --- /dev/null +++ b/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts @@ -0,0 +1,8 @@ +import type { HostComponent, ViewProps } from 'react-native'; +// The default export exists in the file but eslint doesn't see it +// eslint-disable-next-line import/default +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; + +export type NativeProps = ViewProps; + +export default codegenNativeComponent('RNSentryReplayMask') as HostComponent; diff --git a/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts b/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts new file mode 100644 index 0000000000..c726bdbe56 --- /dev/null +++ b/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts @@ -0,0 +1,8 @@ +import type { HostComponent, ViewProps } from 'react-native'; +// The default export exists in the file but eslint doesn't see it +// eslint-disable-next-line import/default +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; + +export type NativeProps = ViewProps; + +export default codegenNativeComponent('RNSentryReplayUnmask') as HostComponent; diff --git a/packages/core/src/js/index.ts b/packages/core/src/js/index.ts index f3112a86aa..7be0ed21bd 100644 --- a/packages/core/src/js/index.ts +++ b/packages/core/src/js/index.ts @@ -75,4 +75,4 @@ export { export type { TimeToDisplayProps } from './tracing'; -export { SentryMask, SentryUnmask } from './replay/customRedact'; +export { Mask, Unmask } from './replay/CustomMask'; diff --git a/packages/core/src/js/replay/CustomMask.tsx b/packages/core/src/js/replay/CustomMask.tsx new file mode 100644 index 0000000000..ffbb6a359e --- /dev/null +++ b/packages/core/src/js/replay/CustomMask.tsx @@ -0,0 +1,52 @@ +import { logger } from '@sentry/utils'; +import * as React from 'react'; +import type { HostComponent, ViewProps } from 'react-native'; +import { UIManager, View } from 'react-native'; + +const MaskNativeComponentName = 'RNSentryReplayMask'; +const UnmaskNativeComponentName = 'RNSentryReplayUnmask'; + +const warnMessage = (component: string): string => `[SentrySessionReplay] ${component} component is not supported on the current platform. If ${component} should be supported, please ensure that the application build is up to date.`; + +const warn = (component: string): void => { + setTimeout(() => { + // Missing mask component could cause leaking PII, we have to ensure that the warning is visible + // even if the app is running without debug. + // eslint-disable-next-line no-console + console.warn(warnMessage(component)); + }, 0); +}; + +const MaskFallback = (viewProps: ViewProps): React.ReactElement => { + warn('Mask'); + return ; +}; + +const UnmaskFallback = (viewProps: ViewProps): React.ReactElement => { + warn('Unmask'); + return ; +}; + +const hasViewManagerConfig = (nativeComponentName: string): boolean => UIManager.hasViewManagerConfig && UIManager.hasViewManagerConfig(nativeComponentName); + +const Mask = ((): HostComponent | React.ComponentType => { + if (!hasViewManagerConfig(MaskNativeComponentName)) { + logger.warn(`[SentrySessionReplay] Can't load ${MaskNativeComponentName}.`); + return MaskFallback; + } + + // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access + return require('../RNSentryReplayMaskNativeComponent').default; +})() + +const Unmask = ((): HostComponent | React.ComponentType => { + if (!hasViewManagerConfig(UnmaskNativeComponentName)) { + logger.warn(`[SentrySessionReplay] Can't load ${UnmaskNativeComponentName}.`); + return UnmaskFallback; + } + + // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access + return require('../RNSentryReplayUnmaskNativeComponent').default; +})(); + +export { Mask, Unmask }; diff --git a/packages/core/src/js/replay/CustomMask.web.tsx b/packages/core/src/js/replay/CustomMask.web.tsx new file mode 100644 index 0000000000..87275b9986 --- /dev/null +++ b/packages/core/src/js/replay/CustomMask.web.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import type { ViewProps } from 'react-native'; +import { View } from 'react-native'; + +const Mask = (props: ViewProps): React.ReactElement => { + // We have to ensure that the warning is visible even if the app is running without debug + // eslint-disable-next-line no-console + console.warn('[SentrySessionReplay] Mask component is not supported on web.'); + return ; +}; +const Unmask = (props: ViewProps): React.ReactElement => { + // We have to ensure that the warning is visible even if the app is running without debug + // eslint-disable-next-line no-console + console.warn('[SentrySessionReplay] Unmask component is not supported on web.'); + return ; +}; + +export { Mask, Unmask }; diff --git a/packages/core/src/js/replay/customRedact.tsx b/packages/core/src/js/replay/customRedact.tsx deleted file mode 100644 index b5ff2b058b..0000000000 --- a/packages/core/src/js/replay/customRedact.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import * as React from 'react'; -import { UIManager, View, ViewProps } from 'react-native'; -import { logger } from '@sentry/utils'; - -import { ReactNativeLibraries } from '../utils/rnlibraries'; -import { HostComponent } from '../vendor/react-native'; - -function requireNativeComponent(viewName: string): HostComponent | null { - if (!UIManager.hasViewManagerConfig) { - logger.warn(`[SentrySessionReplay] Can't load ${viewName}. UIManager.hasViewManagerConfig is not available`); - return null; - } - - if (!UIManager.hasViewManagerConfig(viewName)) { - logger.warn(`[SentrySessionReplay] Can't load ${viewName}. UIManager.hasViewManagerConfig(${viewName}) is not available`); - return null; - } - - if (!ReactNativeLibraries.ReactNative?.requireNativeComponent) { - logger.warn(`[SentrySessionReplay] Can't load ${viewName}. requireNativeComponent from 'react-native' is not available`); - return null; - } - - return ReactNativeLibraries.ReactNative.requireNativeComponent(viewName); -} - -const NativeSentryMask = requireNativeComponent('RNSentryReplayMask'); -const NativeSentryUnmask = requireNativeComponent('RNSentryReplayUnmask'); - -const FallbackSentryMask = (props: ViewProps) => ; -const FallbackSentryUnmask = (props: ViewProps) => ; - -export const SentryMask = NativeSentryMask || FallbackSentryMask; -export const SentryUnmask = NativeSentryUnmask || FallbackSentryUnmask; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index b0a099d1e9..7f757b53ce 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,6 +4,7 @@ "src/js/tools/**/*.ts", "src/js/*.ts", "src/js/**/*.web.ts", + "src/js/**/*.web.tsx", "src/js/*.tsx", "test/**/*.ts", "test/**/*.tsx", diff --git a/samples/react-native/metro.config.js b/samples/react-native/metro.config.js index 2444d12dcc..7ecc754c00 100644 --- a/samples/react-native/metro.config.js +++ b/samples/react-native/metro.config.js @@ -25,7 +25,7 @@ const config = { // Note how we change this from `monorepoRoot` to `projectRoot`. This is part of the optimization! watchFolders: [projectRoot, ...Object.values(monorepoPackages)], resolver: { - resolverMainFields: ['main', 'react-native'], + resolverMainFields: ['react-native', 'main'], resolveRequest: (context, moduleName, platform) => { if (moduleName.includes('promise/')) { return context.resolveRequest( diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 7e2d922b10..87f6ee53cd 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -112,7 +112,7 @@ Sentry.init({ // otherwise they will not work. // release: 'myapp@1.2.3+1', // dist: `1`, - profilesSampleRate: 1.0, + // profilesSampleRate: 1.0, _experiments: { replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 1.0, diff --git a/samples/react-native/src/Screens/PlaygroundScreen.tsx b/samples/react-native/src/Screens/PlaygroundScreen.tsx index 3c336dae27..40d073a007 100644 --- a/samples/react-native/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native/src/Screens/PlaygroundScreen.tsx @@ -16,7 +16,7 @@ import { } from 'react-native'; import SvgGraphic from '../components/SvgGraphic'; import { StackNavigationProp } from '@react-navigation/stack'; -import { SentryMask, SentryUnmask } from '@sentry/react-native'; +import * as Sentry from '@sentry/react-native'; const multilineText = `This is @@ -45,12 +45,12 @@ const PlaygroundScreen = (props: Props) => { /> Custom Mask: - + This is masked - + This is unmasked - - + + Text: {'This is '} From 77691bd13f768c8539bd4a379177f6ed9057d8ca Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 5 Nov 2024 18:52:44 +0100 Subject: [PATCH 06/39] add js tests --- packages/core/test/replay/CustomMask.test.ts | 58 +++++++++++++++++++ .../core/test/replay/CustomMask.web.test.ts | 10 ++++ 2 files changed, 68 insertions(+) create mode 100644 packages/core/test/replay/CustomMask.test.ts create mode 100644 packages/core/test/replay/CustomMask.web.test.ts diff --git a/packages/core/test/replay/CustomMask.test.ts b/packages/core/test/replay/CustomMask.test.ts new file mode 100644 index 0000000000..75d6d589db --- /dev/null +++ b/packages/core/test/replay/CustomMask.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it, beforeEach } from '@jest/globals'; + +describe('CustomMask', () => { + beforeEach(() => { + jest.resetModules(); + }); + + it('returns a fallback when native view manager is missing', () => { + jest.mock('react-native', () => ({ + UIManager: {}, + View: jest.fn(), + })); + + const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + + expect(Mask).toBeDefined(); + expect(Unmask).toBeDefined(); + }); + + it('returns a fallback component when native view manager config is missing', () => { + jest.mock('react-native', () => ({ + UIManager: { + hasViewManagerConfig: () => false, + }, + View: jest.fn(), + })); + + const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + + expect(Mask).toBeDefined(); + expect(Unmask).toBeDefined(); + }); + + it('returns native components when native components exist', () => { + const mockMaskComponent = jest.fn(); + const mockUnmaskComponent = jest.fn(); + + jest.mock('../../src/js/RNSentryReplayMaskNativeComponent', () => ({ + default: mockMaskComponent, + })); + + jest.mock('../../src/js/RNSentryReplayUnmaskNativeComponent', () => ({ + default: mockUnmaskComponent, + })); + + jest.mock('react-native', () => ({ + UIManager: { + hasViewManagerConfig: () => true, + }, + View: jest.fn(), + })); + + const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + + expect(Mask).toBe(mockMaskComponent); + expect(Unmask).toBe(mockUnmaskComponent); + }); +}); diff --git a/packages/core/test/replay/CustomMask.web.test.ts b/packages/core/test/replay/CustomMask.web.test.ts new file mode 100644 index 0000000000..1ee8d61e99 --- /dev/null +++ b/packages/core/test/replay/CustomMask.web.test.ts @@ -0,0 +1,10 @@ +import { describe } from '@jest/globals'; + +describe('CustomMask', () => { + it('returns a react native view', () => { + const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + + expect(Mask).toBeDefined(); + expect(Unmask).toBeDefined(); + }); +}); From 45374befc71ae489fb959a4e6637e356a5d72797 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 11:08:29 +0100 Subject: [PATCH 07/39] fix eslint changing the native props interface to type --- packages/core/src/js/RNSentryReplayMaskNativeComponent.ts | 4 +++- packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts | 4 +++- packages/core/test/replay/CustomMask.test.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts b/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts index 223680179d..794dcb2e8c 100644 --- a/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts +++ b/packages/core/src/js/RNSentryReplayMaskNativeComponent.ts @@ -3,6 +3,8 @@ import type { HostComponent, ViewProps } from 'react-native'; // eslint-disable-next-line import/default import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; -export type NativeProps = ViewProps; +// If changed to type NativeProps = ViewProps, react native codegen will fail finding the NativeProps type +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface NativeProps extends ViewProps {} export default codegenNativeComponent('RNSentryReplayMask') as HostComponent; diff --git a/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts b/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts index c726bdbe56..928499c747 100644 --- a/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts +++ b/packages/core/src/js/RNSentryReplayUnmaskNativeComponent.ts @@ -3,6 +3,8 @@ import type { HostComponent, ViewProps } from 'react-native'; // eslint-disable-next-line import/default import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; -export type NativeProps = ViewProps; +// If changed to type NativeProps = ViewProps, react native codegen will fail finding the NativeProps type +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface NativeProps extends ViewProps {} export default codegenNativeComponent('RNSentryReplayUnmask') as HostComponent; diff --git a/packages/core/test/replay/CustomMask.test.ts b/packages/core/test/replay/CustomMask.test.ts index 75d6d589db..7f82ccd060 100644 --- a/packages/core/test/replay/CustomMask.test.ts +++ b/packages/core/test/replay/CustomMask.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, beforeEach } from '@jest/globals'; +import { beforeEach, describe, expect, it } from '@jest/globals'; describe('CustomMask', () => { beforeEach(() => { From 0a127d21662c85673d1a3e27c3460e582925fa6a Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 14:56:16 +0100 Subject: [PATCH 08/39] Fix mask components for non uikit builds --- packages/core/ios/Replay/RNSentryReplayMask.h | 25 ++++++++++------- .../core/ios/Replay/RNSentryReplayMask.mm | 28 +++++++++++-------- .../core/ios/Replay/RNSentryReplayUnmask.h | 25 ++++++++++------- .../core/ios/Replay/RNSentryReplayUnmask.mm | 28 +++++++++++-------- samples/react-native-macos/metro.config.js | 2 +- .../src/Screens/PlaygroundScreen.tsx | 10 +++++++ 6 files changed, 75 insertions(+), 43 deletions(-) diff --git a/packages/core/ios/Replay/RNSentryReplayMask.h b/packages/core/ios/Replay/RNSentryReplayMask.h index e761e18b98..3903d413e7 100644 --- a/packages/core/ios/Replay/RNSentryReplayMask.h +++ b/packages/core/ios/Replay/RNSentryReplayMask.h @@ -1,19 +1,24 @@ -#import -#import +#import -#ifdef RCT_NEW_ARCH_ENABLED -# import -#else -# import -#endif +#if SENTRY_HAS_UIKIT + +# import + +# ifdef RCT_NEW_ARCH_ENABLED +# import +# else +# import +# endif @interface RNSentryReplayMaskManager : RCTViewManager @end @interface RNSentryReplayMask : -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED RCTViewComponentView -#else +# else RCTView -#endif +# endif @end + +#endif diff --git a/packages/core/ios/Replay/RNSentryReplayMask.mm b/packages/core/ios/Replay/RNSentryReplayMask.mm index d1b92f21a6..bc39f229e2 100644 --- a/packages/core/ios/Replay/RNSentryReplayMask.mm +++ b/packages/core/ios/Replay/RNSentryReplayMask.mm @@ -1,11 +1,15 @@ -#import "RNSentryReplayMask.h" +#import -#ifdef RCT_NEW_ARCH_ENABLED -# import -# import +#if SENTRY_HAS_UIKIT + +# import "RNSentryReplayMask.h" + +# ifdef RCT_NEW_ARCH_ENABLED +# import +# import // RCTFabricComponentsPlugins needed for RNSentryReplayMaskCls -# import -#endif +# import +# endif @implementation RNSentryReplayMaskManager @@ -18,28 +22,30 @@ - (UIView *)view @end -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED @interface RNSentryReplayMask () @end -#endif +# endif @implementation RNSentryReplayMask -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED + (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider { return facebook::react::concreteComponentDescriptorProvider< facebook::react::RNSentryReplayMaskComponentDescriptor>(); } -#endif +# endif @end -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED Class RNSentryReplayMaskCls(void) { return RNSentryReplayMask.class; } +# endif + #endif diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.h b/packages/core/ios/Replay/RNSentryReplayUnmask.h index 3a18fa9c54..c1dc8a3479 100644 --- a/packages/core/ios/Replay/RNSentryReplayUnmask.h +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.h @@ -1,19 +1,24 @@ -#import -#import +#import -#ifdef RCT_NEW_ARCH_ENABLED -# import -#else -# import -#endif +#if SENTRY_HAS_UIKIT + +# import + +# ifdef RCT_NEW_ARCH_ENABLED +# import +# else +# import +# endif @interface RNSentryReplayUnmaskManager : RCTViewManager @end @interface RNSentryReplayUnmask : -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED RCTViewComponentView -#else +# else RCTView -#endif +# endif @end + +#endif diff --git a/packages/core/ios/Replay/RNSentryReplayUnmask.mm b/packages/core/ios/Replay/RNSentryReplayUnmask.mm index 2522538d20..8dd0f06611 100644 --- a/packages/core/ios/Replay/RNSentryReplayUnmask.mm +++ b/packages/core/ios/Replay/RNSentryReplayUnmask.mm @@ -1,11 +1,15 @@ -#import "RNSentryReplayUnmask.h" +#import -#ifdef RCT_NEW_ARCH_ENABLED -# import -# import +#if SENTRY_HAS_UIKIT + +# import "RNSentryReplayUnmask.h" + +# ifdef RCT_NEW_ARCH_ENABLED +# import +# import // RCTFabricComponentsPlugins needed for RNSentryReplayUnmaskCls -# import -#endif +# import +# endif @implementation RNSentryReplayUnmaskManager @@ -18,28 +22,30 @@ - (UIView *)view @end -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED @interface RNSentryReplayUnmask () @end -#endif +# endif @implementation RNSentryReplayUnmask -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED + (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider { return facebook::react::concreteComponentDescriptorProvider< facebook::react::RNSentryReplayUnmaskComponentDescriptor>(); } -#endif +# endif @end -#ifdef RCT_NEW_ARCH_ENABLED +# ifdef RCT_NEW_ARCH_ENABLED Class RNSentryReplayUnmaskCls(void) { return RNSentryReplayUnmask.class; } +# endif + #endif diff --git a/samples/react-native-macos/metro.config.js b/samples/react-native-macos/metro.config.js index f34d60cc69..363086b13c 100644 --- a/samples/react-native-macos/metro.config.js +++ b/samples/react-native-macos/metro.config.js @@ -25,7 +25,7 @@ const config = { // Note how we change this from `monorepoRoot` to `projectRoot`. This is part of the optimization! watchFolders: [projectRoot, ...Object.values(monorepoPackages)], resolver: { - resolverMainFields: ['main', 'react-native'], + resolverMainFields: ['react-native', 'main'], resolveRequest: (context, moduleName, platform) => { if (moduleName.includes('promise/')) { return context.resolveRequest( diff --git a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx index 7a5d212892..7802195605 100644 --- a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx @@ -14,6 +14,7 @@ import { Pressable, } from 'react-native'; import SvgGraphic from '../components/SvgGraphic'; +import * as Sentry from '@sentry/react-native'; const multilineText = `This is @@ -32,6 +33,15 @@ const PlaygroundScreen = () => { Text: {'This is '} + Custom Mask: + + + This is masked + + This is unmasked + + + TextInput: Date: Wed, 6 Nov 2024 15:03:31 +0100 Subject: [PATCH 09/39] add changelog --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df0ba2bbeb..2b448340e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,27 @@ export SENTRY_DISABLE_NATIVE_DEBUG_UPLOAD=true ``` +- Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) + + ```jsx + import * as Sentry from '@sentry/react-native' + + const Example = () => { + return ( + + + + ${"This text will be masked"} + + ${"This text won't be masked"} + + + + + ); + }; + ``` + ### Fixes - Skips ignoring require cycle logs for RN 0.70 or newer ([#4214](https://github.com/getsentry/sentry-react-native/pull/4214)) From eb64e8dad5ebb38e48897af0c3257923e2c1a047 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 15:03:44 +0100 Subject: [PATCH 10/39] fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b448340e4..1fa09a9ff8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ - Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) ```jsx - import * as Sentry from '@sentry/react-native' + import * as Sentry from '@sentry/react-native'; const Example = () => { return ( From 32c45e472366160d0bf8cae076c729f4a8112044 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 16:14:42 +0100 Subject: [PATCH 11/39] fix ts3.8 type check test --- dev-packages/type-check/ts3.8-test/index.ts | 23 +++++++++++++++++++ .../type-check/ts3.8-test/package.json | 2 +- .../type-check/ts3.8-test/tsconfig.build.json | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/dev-packages/type-check/ts3.8-test/index.ts b/dev-packages/type-check/ts3.8-test/index.ts index cbad1c30a0..37d79a049d 100644 --- a/dev-packages/type-check/ts3.8-test/index.ts +++ b/dev-packages/type-check/ts3.8-test/index.ts @@ -1,2 +1,25 @@ +declare global { + interface History {} + interface IDBObjectStore {} + interface Window { + fetch: any; + } + interface ShadowRoot {} + interface BufferSource {} + interface PerformanceResourceTiming { + decodedBodySize: any; + encodedBodySize: any; + duration: any; + domInteractive: any; + domContentLoadedEventEnd: any; + domContentLoadedEventStart: any; + loadEventStart: any; + loadEventEnd: number; + domComplete: number; + redirectCount: number; + } + interface PerformanceEntry {} +} + // we need to import the SDK to ensure tsc check the types import * as _Sentry from '@sentry/react-native'; diff --git a/dev-packages/type-check/ts3.8-test/package.json b/dev-packages/type-check/ts3.8-test/package.json index 5d6bcbdbe3..daf8ea0be0 100644 --- a/dev-packages/type-check/ts3.8-test/package.json +++ b/dev-packages/type-check/ts3.8-test/package.json @@ -9,7 +9,7 @@ }, "license": "MIT", "devDependencies": { - "@types/react": "17.0.58", + "@types/react": "17.0.83", "@types/react-native": "0.65.30", "typescript": "3.8.3" }, diff --git a/dev-packages/type-check/ts3.8-test/tsconfig.build.json b/dev-packages/type-check/ts3.8-test/tsconfig.build.json index f3d299fc98..28d4363cb9 100644 --- a/dev-packages/type-check/ts3.8-test/tsconfig.build.json +++ b/dev-packages/type-check/ts3.8-test/tsconfig.build.json @@ -5,7 +5,9 @@ "compilerOptions": { "skipLibCheck": false, "noEmit": true, + "importHelpers": true, "types": [], + "lib": ["es2015"], "jsx": "react-native", "target": "es6", "moduleResolution": "node", From 02bb9132cb673bee171b266aaf7f533eaff0775a Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 16:57:21 +0100 Subject: [PATCH 12/39] fix new arch build decoupled replay and replay mask --- packages/core/ios/RNSentryReplay.m | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index d403c5a1fa..1686c3bef3 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -1,8 +1,6 @@ #import "RNSentryReplay.h" #import "RNSentryReplayBreadcrumbConverter.h" #import "React/RCTTextView.h" -#import "Replay/RNSentryReplayMask.h" -#import "Replay/RNSentryReplayUnmask.h" #if SENTRY_TARGET_REPLAY_SUPPORTED @@ -43,8 +41,8 @@ + (void)updateOptions:(NSMutableDictionary *)options + (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; - [classesToRedact addObject:RNSentryReplayMask.class]; - [classesToRedact addObject:RNSentryReplayUnmask.class]; + [classesToRedact addObject:NSClassFromString(@"RNSentryReplayMask")]; + [classesToRedact addObject:NSClassFromString(@"RNSentryReplayUnmask")]; if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView"); From 5315bb23bc67d280a2c2bb8670029a2682dd741f Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Wed, 6 Nov 2024 17:02:25 +0100 Subject: [PATCH 13/39] fix missing react native types --- dev-packages/type-check/ts3.8-test/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-packages/type-check/ts3.8-test/index.ts b/dev-packages/type-check/ts3.8-test/index.ts index 37d79a049d..6f1ec6d6cc 100644 --- a/dev-packages/type-check/ts3.8-test/index.ts +++ b/dev-packages/type-check/ts3.8-test/index.ts @@ -20,6 +20,7 @@ declare global { } interface PerformanceEntry {} } +import 'react-native'; // we need to import the SDK to ensure tsc check the types import * as _Sentry from '@sentry/react-native'; From cdd3da8db5fe375d97f57cc1e019bc13071ed335 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Fri, 8 Nov 2024 22:24:33 +0100 Subject: [PATCH 14/39] Update mask sample --- .../react-native/src/Screens/PlaygroundScreen.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/samples/react-native/src/Screens/PlaygroundScreen.tsx b/samples/react-native/src/Screens/PlaygroundScreen.tsx index 40d073a007..cb6dda156c 100644 --- a/samples/react-native/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native/src/Screens/PlaygroundScreen.tsx @@ -45,12 +45,15 @@ const PlaygroundScreen = (props: Props) => { /> Custom Mask: - - This is masked - - This is unmasked - - + + This is masked if all text is masked + + This is masked always because it's a child of a masked view + + This is masked because all children of masked view are masked + + + Text: {'This is '} From 1170838df86b7a4af400267cc1cfe9cbda0391ae Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Fri, 8 Nov 2024 22:25:15 +0100 Subject: [PATCH 15/39] fix rn unmask class is added to unmask array --- packages/core/ios/RNSentryReplay.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index 304557354f..d33f910e6e 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -32,11 +32,17 @@ + (void)updateOptions:(NSMutableDictionary *)options @"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null], @"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null], @"maskedViewClasses" : [RNSentryReplay getReplayRNRedactClasses:replayOptions], + @"unmaskedViewClasses" : [RNSentryReplay getReplayRNUnmaskClasses], } } forKey:@"experimental"]; } ++ (NSArray *_Nonnull)getReplayRNUnmaskClasses +{ + return @[ @"RNSentryReplayUnmask" ]; +} + + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; From 3a9e1559a92a30740fc29919a4208ba460d14bb1 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Fri, 8 Nov 2024 23:28:53 +0100 Subject: [PATCH 16/39] fix tests for custom classes --- .../project.pbxproj | 12 +++++ ...RNSentryCocoaTesterTests-Bridging-Header.h | 2 + .../RNSentryReplayOptionsTests.swift | 45 +++++++++++++------ packages/core/ios/RNSentryReplay.m | 5 ++- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj index 82d6c51fd5..20e07d71fb 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayBreadcrumbConverter.h; path = ../ios/RNSentryReplayBreadcrumbConverter.h; sourceTree = ""; }; 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryBreadcrumbTests.swift; sourceTree = ""; }; 3360898D29524164007C7730 /* RNSentryCocoaTesterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNSentryCocoaTesterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3380C6C12CDEC5850018B9B6 /* RNSentryReplayUnmask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayUnmask.h; path = ../ios/Replay/RNSentryReplayUnmask.h; sourceTree = SOURCE_ROOT; }; + 3380C6C22CDEC6630018B9B6 /* RNSentryReplayMask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayMask.h; path = ../ios/Replay/RNSentryReplayMask.h; sourceTree = SOURCE_ROOT; }; 338739072A7D7D2800950DDD /* RNSentryReplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplay.h; path = ../ios/RNSentryReplay.h; sourceTree = ""; }; 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = ""; }; 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryOnDrawReporterTests.m; sourceTree = ""; }; @@ -98,9 +100,19 @@ path = RNSentryCocoaTesterTests; sourceTree = ""; }; + 3380C6C02CDEC56B0018B9B6 /* Replay */ = { + isa = PBXGroup; + children = ( + 3380C6C22CDEC6630018B9B6 /* RNSentryReplayMask.h */, + 3380C6C12CDEC5850018B9B6 /* RNSentryReplayUnmask.h */, + ); + path = Replay; + sourceTree = ""; + }; 33AFE0122B8F319000AAB120 /* RNSentry */ = { isa = PBXGroup; children = ( + 3380C6C02CDEC56B0018B9B6 /* Replay */, 332D33482CDBDC7300547D76 /* RNSentry.h */, 3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */, 330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */, diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h index 43f9933853..bc2bdd0304 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryCocoaTesterTests-Bridging-Header.h @@ -5,3 +5,5 @@ #import "RNSentryBreadcrumb.h" #import "RNSentryReplay.h" #import "RNSentryReplayBreadcrumbConverter.h" +#import "RNSentryReplayMask.h" +#import "RNSentryReplayUnmask.h" diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift index 18a329ebec..3462479f5e 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift @@ -64,12 +64,13 @@ final class RNSentryReplayOptions: XCTestCase { } func assertAllDefaultReplayOptionsAreNotNil(replayOptions: [String: Any]) { - XCTAssertEqual(replayOptions.count, 5) + XCTAssertEqual(replayOptions.count, 6) XCTAssertNotNil(replayOptions["sessionSampleRate"]) XCTAssertNotNil(replayOptions["errorSampleRate"]) XCTAssertNotNil(replayOptions["redactAllImages"]) XCTAssertNotNil(replayOptions["redactAllText"]) XCTAssertNotNil(replayOptions["maskedViewClasses"]) + XCTAssertNotNil(replayOptions["unmaskedViewClasses"]) } func testSessionSampleRate() { @@ -109,11 +110,7 @@ final class RNSentryReplayOptions: XCTestCase { let sessionReplay = experimental["sessionReplay"] as! [String:Any] let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String] - XCTAssertEqual(maskedViewClasses.count, 1) - XCTAssertEqual(maskedViewClasses[0], "RNSVGSvgView") - - let actualOptions = try! Options(dict: optionsDict as! [String: Any]) - XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 0) + XCTAssertTrue(maskedViewClasses.contains("RNSVGSvgView")) } func testMaskAllImages() { @@ -128,9 +125,7 @@ final class RNSentryReplayOptions: XCTestCase { let actualOptions = try! Options(dict: optionsDict as! [String: Any]) XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllImages, true) - XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 1) - XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0]) - XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTImageView")!)) + assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, stringClass: "RCTImageView") } func testMaskAllText() { @@ -145,11 +140,33 @@ final class RNSentryReplayOptions: XCTestCase { let actualOptions = try! Options(dict: optionsDict as! [String: Any]) XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllText, true) - XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 2) - XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0]) - XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[1]) - XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTTextView")!)) - XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[1]), ObjectIdentifier(NSClassFromString("RCTParagraphComponentView")!)) + assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, stringClass: "RCTTextView") + assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, stringClass: "RCTParagraphComponentView") + } + + func testMaskRNSentryReplayCustomComponents() { + let optionsDict = ([ + "dsn": "https://abc@def.ingest.sentry.io/1234567", + "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], + ] as NSDictionary).mutableCopy() as! NSMutableDictionary + + RNSentryReplay.updateOptions(optionsDict) + + let actualOptions = try! Options(dict: optionsDict as! [String: Any]) + + assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, anyClass: RNSentryReplayMask.self) + assertContainsClass(classArray: actualOptions.experimental.sessionReplay.unmaskedViewClasses, anyClass: RNSentryReplayUnmask.self) } + func assertContainsClass(classArray: [AnyClass], anyClass: AnyClass) { + XCTAssertTrue(mapToObjectIdentifiers(classArray: classArray).contains(ObjectIdentifier(anyClass))) + } + + func assertContainsClass(classArray: [AnyClass], stringClass: String) { + XCTAssertTrue(mapToObjectIdentifiers(classArray: classArray).contains(ObjectIdentifier(NSClassFromString(stringClass)!))) + } + + func mapToObjectIdentifiers(classArray: [AnyClass]) -> [ObjectIdentifier] { + return classArray.map { ObjectIdentifier($0) } + } } diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index d33f910e6e..5ba133cc25 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -40,14 +40,17 @@ + (void)updateOptions:(NSMutableDictionary *)options + (NSArray *_Nonnull)getReplayRNUnmaskClasses { + // We can't import RNSentryReplayUnmask.h here because it's Objective-C++ + // To avoid typos, we test the class existens in the tests return @[ @"RNSentryReplayUnmask" ]; } + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; + // We can't import RNSentryReplayMask.h here because it's Objective-C++ + // To avoid typos, we test the class existens in the tests [classesToRedact addObject:@"RNSentryReplayMask"]; - [classesToRedact addObject:@"RNSentryReplayUnmask"]; if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { [classesToRedact addObject:@"RNSVGSvgView"]; From c02d06c5e171634887c52d715a09ac7ccd581fb0 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:49:28 +0100 Subject: [PATCH 17/39] Update samples/react-native/src/App.tsx --- samples/react-native/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 87f6ee53cd..7e2d922b10 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -112,7 +112,7 @@ Sentry.init({ // otherwise they will not work. // release: 'myapp@1.2.3+1', // dist: `1`, - // profilesSampleRate: 1.0, + profilesSampleRate: 1.0, _experiments: { replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 1.0, From 9fe9c24afa403654d56b0aaff5e2aa9a6febd679 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 11 Nov 2024 16:17:48 +0100 Subject: [PATCH 18/39] update redact example --- samples/react-native/src/Screens/PlaygroundScreen.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/react-native/src/Screens/PlaygroundScreen.tsx b/samples/react-native/src/Screens/PlaygroundScreen.tsx index cb6dda156c..49d3a99b43 100644 --- a/samples/react-native/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native/src/Screens/PlaygroundScreen.tsx @@ -46,11 +46,12 @@ const PlaygroundScreen = (props: Props) => { Custom Mask: - This is masked if all text is masked + This is unmasked because it's direct child of Sentry.Unmask (can be masked if Sentry.Masked is used higher in the hierarchy) - This is masked always because it's a child of a masked view + This is masked always because it's a child of a Sentry.Mask - This is masked because all children of masked view are masked + {/* Sentry.Unmask does not override the Sentry.Mask from above in the hierarchy */} + This is masked always because it's a child of Sentry.Mask From 845c2605dcc9c1f1bf875b58c407846219c34d24 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 11 Nov 2024 16:33:12 +0100 Subject: [PATCH 19/39] fix changelog and macos sample --- CHANGELOG.md | 10 ++++------ .../src/Screens/PlaygroundScreen.tsx | 7 ++++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c15e441eb..bcea8eab9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,13 +40,11 @@ return ( - - ${"This text will be masked"} - - ${"This text won't be masked"} - - + ${"All children of Sentry.Mask will be masked."} + + ${"Only direct children will be unmasked."} + ); }; diff --git a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx index 7802195605..a81f09b7bd 100644 --- a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx @@ -35,12 +35,13 @@ const PlaygroundScreen = () => { {'This is '} Custom Mask: + {/* Replay is not supported on macOS, this test that the unavailable components do not crash the app */} This is masked - - This is unmasked - + + This is unmasked + TextInput: From 2edaeb0e4f260fd9a2a59255e58694b47107d065 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 11 Nov 2024 16:33:24 +0100 Subject: [PATCH 20/39] fix rnsentry impl --- packages/core/ios/RNSentryReplay.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index 5ba133cc25..fd4da71265 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -32,7 +32,6 @@ + (void)updateOptions:(NSMutableDictionary *)options @"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null], @"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null], @"maskedViewClasses" : [RNSentryReplay getReplayRNRedactClasses:replayOptions], - @"unmaskedViewClasses" : [RNSentryReplay getReplayRNUnmaskClasses], } } forKey:@"experimental"]; @@ -48,9 +47,6 @@ + (NSArray *_Nonnull)getReplayRNUnmaskClasses + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; - // We can't import RNSentryReplayMask.h here because it's Objective-C++ - // To avoid typos, we test the class existens in the tests - [classesToRedact addObject:@"RNSentryReplayMask"]; if ([replayOptions[@"maskAllVectors"] boolValue] == YES) { [classesToRedact addObject:@"RNSVGSvgView"]; @@ -68,6 +64,10 @@ + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOpt + (void)postInit { + // We can't import RNSentryReplayMask.h here because it's Objective-C++ + // To avoid typos, we test the class existens in the tests + [PrivateSentrySDKOnly setRedactContainerClass:NSClassFromString(@"RNSentryReplayMask")]; + [PrivateSentrySDKOnly setIgnoreContainerClass:NSClassFromString(@"RNSentryReplayUnmask")]; RNSentryReplayBreadcrumbConverter *breadcrumbConverter = [[RNSentryReplayBreadcrumbConverter alloc] init]; [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; From 4f88064fb130ba593caa46686f73a36828ddc213 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 11 Nov 2024 17:51:09 +0100 Subject: [PATCH 21/39] fix class names tests --- .../project.pbxproj | 4 ++++ .../RNSentryReplayOptionsTests.swift | 21 +------------------ .../RNSentryReplayPostInitTests.swift | 13 ++++++++++++ packages/core/ios/RNSentryReplay.h | 4 ++++ packages/core/ios/RNSentryReplay.m | 14 +++++++++++-- 5 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj index 20e07d71fb..a2224753fe 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTester.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */; }; 336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */; }; + 3380C6C42CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3380C6C32CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift */; }; 33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; }; 33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; }; 33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */; }; @@ -29,6 +30,7 @@ 3360898D29524164007C7730 /* RNSentryCocoaTesterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNSentryCocoaTesterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3380C6C12CDEC5850018B9B6 /* RNSentryReplayUnmask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayUnmask.h; path = ../ios/Replay/RNSentryReplayUnmask.h; sourceTree = SOURCE_ROOT; }; 3380C6C22CDEC6630018B9B6 /* RNSentryReplayMask.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayMask.h; path = ../ios/Replay/RNSentryReplayMask.h; sourceTree = SOURCE_ROOT; }; + 3380C6C32CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryReplayPostInitTests.swift; sourceTree = ""; }; 338739072A7D7D2800950DDD /* RNSentryReplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplay.h; path = ../ios/RNSentryReplay.h; sourceTree = ""; }; 33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = ""; }; 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryOnDrawReporterTests.m; sourceTree = ""; }; @@ -96,6 +98,7 @@ 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */, 3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */, 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */, + 3380C6C32CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift */, ); path = RNSentryCocoaTesterTests; sourceTree = ""; @@ -238,6 +241,7 @@ 336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */, 33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */, 33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */, + 3380C6C42CE25ECA0018B9B6 /* RNSentryReplayPostInitTests.swift in Sources */, 33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift index 3462479f5e..a805c884df 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayOptionsTests.swift @@ -64,13 +64,12 @@ final class RNSentryReplayOptions: XCTestCase { } func assertAllDefaultReplayOptionsAreNotNil(replayOptions: [String: Any]) { - XCTAssertEqual(replayOptions.count, 6) + XCTAssertEqual(replayOptions.count, 5) XCTAssertNotNil(replayOptions["sessionSampleRate"]) XCTAssertNotNil(replayOptions["errorSampleRate"]) XCTAssertNotNil(replayOptions["redactAllImages"]) XCTAssertNotNil(replayOptions["redactAllText"]) XCTAssertNotNil(replayOptions["maskedViewClasses"]) - XCTAssertNotNil(replayOptions["unmaskedViewClasses"]) } func testSessionSampleRate() { @@ -144,24 +143,6 @@ final class RNSentryReplayOptions: XCTestCase { assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, stringClass: "RCTParagraphComponentView") } - func testMaskRNSentryReplayCustomComponents() { - let optionsDict = ([ - "dsn": "https://abc@def.ingest.sentry.io/1234567", - "_experiments": [ "replaysOnErrorSampleRate": 0.75 ], - ] as NSDictionary).mutableCopy() as! NSMutableDictionary - - RNSentryReplay.updateOptions(optionsDict) - - let actualOptions = try! Options(dict: optionsDict as! [String: Any]) - - assertContainsClass(classArray: actualOptions.experimental.sessionReplay.maskedViewClasses, anyClass: RNSentryReplayMask.self) - assertContainsClass(classArray: actualOptions.experimental.sessionReplay.unmaskedViewClasses, anyClass: RNSentryReplayUnmask.self) - } - - func assertContainsClass(classArray: [AnyClass], anyClass: AnyClass) { - XCTAssertTrue(mapToObjectIdentifiers(classArray: classArray).contains(ObjectIdentifier(anyClass))) - } - func assertContainsClass(classArray: [AnyClass], stringClass: String) { XCTAssertTrue(mapToObjectIdentifiers(classArray: classArray).contains(ObjectIdentifier(NSClassFromString(stringClass)!))) } diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift new file mode 100644 index 0000000000..e7eed0d01c --- /dev/null +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift @@ -0,0 +1,13 @@ +import XCTest +import Sentry + +final class RNSentryReplayPostInitTests: XCTestCase { + + func testMask() { + XCTAssertEqual(ObjectIdentifier(RNSentryReplay.getMaskClass()), ObjectIdentifier(RNSentryReplayMask.self)) + } + + func testUnmask() { + XCTAssertEqual(ObjectIdentifier(RNSentryReplay.getUnmaskClass()), ObjectIdentifier(RNSentryReplayUnmask.self)) + } +} diff --git a/packages/core/ios/RNSentryReplay.h b/packages/core/ios/RNSentryReplay.h index f3cb5a6ef8..452914af15 100644 --- a/packages/core/ios/RNSentryReplay.h +++ b/packages/core/ios/RNSentryReplay.h @@ -5,4 +5,8 @@ + (void)postInit; ++ (Class)getMaskClass; + ++ (Class)getUnmaskClass; + @end diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index fd4da71265..1e5b5df6b0 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -66,12 +66,22 @@ + (void)postInit { // We can't import RNSentryReplayMask.h here because it's Objective-C++ // To avoid typos, we test the class existens in the tests - [PrivateSentrySDKOnly setRedactContainerClass:NSClassFromString(@"RNSentryReplayMask")]; - [PrivateSentrySDKOnly setIgnoreContainerClass:NSClassFromString(@"RNSentryReplayUnmask")]; + [PrivateSentrySDKOnly setRedactContainerClass:[self getMaskClass]]; + [PrivateSentrySDKOnly setIgnoreContainerClass:[self getUnmaskClass]]; RNSentryReplayBreadcrumbConverter *breadcrumbConverter = [[RNSentryReplayBreadcrumbConverter alloc] init]; [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; } ++ (Class) getMaskClass +{ + return NSClassFromString(@"RNSentryReplayMask"); +} + ++ (Class) getUnmaskClass +{ + return NSClassFromString(@"RNSentryReplayUnmask"); +} + @end #endif From e0ccb78fc41f348a9123950294348fdb6616086e Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:52:54 +0100 Subject: [PATCH 22/39] Update samples/react-native-macos/src/Screens/PlaygroundScreen.tsx Co-authored-by: LucasZF --- samples/react-native-macos/src/Screens/PlaygroundScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx index a81f09b7bd..96575f2aa9 100644 --- a/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx +++ b/samples/react-native-macos/src/Screens/PlaygroundScreen.tsx @@ -35,7 +35,7 @@ const PlaygroundScreen = () => { {'This is '} Custom Mask: - {/* Replay is not supported on macOS, this test that the unavailable components do not crash the app */} + {/* Replay is not supported on macOS. This sample demonstrates that unavailable components do not cause the app to crash. */} This is masked From 711e547af537e38e947e80e3d4c09627b01fd87c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 11 Nov 2024 23:07:25 +0100 Subject: [PATCH 23/39] feat(replay): Add Mask and Unmask Android New Arch implementation --- .../java/io/sentry/react/RNSentryPackage.java | 34 ++++++++++++++++-- .../react/replay/RNSentryReplayMask.java | 10 ++++++ .../replay/RNSentryReplayMaskManager.java | 35 ++++++++++++++++++ .../react/replay/RNSentryReplayUnmask.java | 10 ++++++ .../replay/RNSentryReplayUnmaskManager.java | 36 +++++++++++++++++++ samples/react-native/src/App.tsx | 2 +- 6 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMask.java create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmask.java create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java index c039a1c002..a6c143a64a 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java @@ -8,7 +8,8 @@ import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.ViewManager; -import java.util.Arrays; +import io.sentry.react.replay.RNSentryReplayMaskManager; +import io.sentry.react.replay.RNSentryReplayUnmaskManager; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,8 +19,12 @@ public class RNSentryPackage extends TurboReactPackage { @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(RNSentryModuleImpl.NAME)) { + if (RNSentryModuleImpl.NAME.equals(name)) { return new RNSentryModule(reactContext); + } else if (RNSentryReplayMaskManager.REACT_CLASS.equals(name)) { + return new RNSentryReplayMaskManager(); + } else if (RNSentryReplayUnmaskManager.REACT_CLASS.equals(name)) { + return new RNSentryReplayUnmaskManager(); } else { return null; } @@ -41,6 +46,26 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { false, // isCxxModule isTurboModule // isTurboModule )); + moduleInfos.put( + RNSentryReplayMaskManager.REACT_CLASS, + new ReactModuleInfo( + RNSentryReplayMaskManager.REACT_CLASS, // name + RNSentryReplayMaskManager.REACT_CLASS, // className + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + )); + moduleInfos.put( + RNSentryReplayUnmaskManager.REACT_CLASS, + new ReactModuleInfo( + RNSentryReplayUnmaskManager.REACT_CLASS, // name + RNSentryReplayUnmaskManager.REACT_CLASS, // className + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + )); return moduleInfos; }; } @@ -48,6 +73,9 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { @NonNull @Override public List createViewManagers(ReactApplicationContext reactContext) { - return Arrays.asList(new RNSentryOnDrawReporterManager(reactContext)); + return List.of( + new RNSentryOnDrawReporterManager(reactContext), + new RNSentryReplayMaskManager(), + new RNSentryReplayUnmaskManager()); } } diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMask.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMask.java new file mode 100644 index 0000000000..eee70884ef --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMask.java @@ -0,0 +1,10 @@ +package io.sentry.react.replay; + +import android.content.Context; +import com.facebook.react.views.view.ReactViewGroup; + +public class RNSentryReplayMask extends ReactViewGroup { + public RNSentryReplayMask(Context context) { + super(context); + } +} diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java new file mode 100644 index 0000000000..3b2e912399 --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java @@ -0,0 +1,35 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.ViewManagerDelegate; +import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerDelegate; +import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerInterface; + +@ReactModule(name = RNSentryReplayMaskManager.REACT_CLASS) +public class RNSentryReplayMaskManager extends ViewGroupManager + implements RNSentryReplayMaskManagerInterface { + private final RNSentryReplayMaskManagerDelegate + delegate = new RNSentryReplayMaskManagerDelegate<>(this); + + @Override + public ViewManagerDelegate getDelegate() { + return delegate; + } + + @NonNull + @Override + public String getName() { + return REACT_CLASS; + } + + @NonNull + @Override + public RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayMask(context); + } + + public static final String REACT_CLASS = "RNSentryReplayMask"; +} diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmask.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmask.java new file mode 100644 index 0000000000..adc6f2dd25 --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmask.java @@ -0,0 +1,10 @@ +package io.sentry.react.replay; + +import android.content.Context; +import com.facebook.react.views.view.ReactViewGroup; + +public class RNSentryReplayUnmask extends ReactViewGroup { + public RNSentryReplayUnmask(Context context) { + super(context); + } +} diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java new file mode 100644 index 0000000000..b836d6860a --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java @@ -0,0 +1,36 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; +import com.facebook.react.uimanager.ViewManagerDelegate; +import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerDelegate; +import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerInterface; + +@ReactModule(name = RNSentryReplayUnmaskManager.REACT_CLASS) +public class RNSentryReplayUnmaskManager extends ViewGroupManager + implements RNSentryReplayUnmaskManagerInterface { + private final RNSentryReplayUnmaskManagerDelegate< + RNSentryReplayUnmask, RNSentryReplayUnmaskManager> + delegate = new RNSentryReplayUnmaskManagerDelegate<>(this); + + @Override + public ViewManagerDelegate getDelegate() { + return delegate; + } + + @NonNull + @Override + public String getName() { + return REACT_CLASS; + } + + @NonNull + @Override + public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayUnmask(context); + } + + public static final String REACT_CLASS = "RNSentryReplayUnmask"; +} diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 7b613cbf45..239a2b200d 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -120,7 +120,7 @@ Sentry.init({ // otherwise they will not work. // release: 'myapp@1.2.3+1', // dist: `1`, - profilesSampleRate: 1.0, + // profilesSampleRate: 1.0, _experiments: { replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 1.0, From ed81fd7dec1c893d94fce3ee81784004eaf8ff85 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 12 Nov 2024 15:34:24 +0100 Subject: [PATCH 24/39] use mask containers --- .../src/main/java/io/sentry/react/RNSentryModuleImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index 8191108ad2..35a2b73236 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -63,6 +63,8 @@ import io.sentry.protocol.SentryPackage; import io.sentry.protocol.User; import io.sentry.protocol.ViewHierarchy; +import io.sentry.react.replay.RNSentryReplayMask; +import io.sentry.react.replay.RNSentryReplayUnmask; import io.sentry.util.DebugMetaPropertiesApplier; import io.sentry.util.FileUtils; import io.sentry.util.JsonSerializationUtils; @@ -352,6 +354,9 @@ private SentryReplayOptions getReplayOptions(@NotNull ReadableMap rnOptions) { androidReplayOptions.addMaskViewClass("com.horcrux.svg.SvgView"); // react-native-svg } + androidReplayOptions.setMaskViewContainerClass(RNSentryReplayMask.class.getName()); + androidReplayOptions.setUnmaskViewContainerClass(RNSentryReplayUnmask.class.getName()); + return androidReplayOptions; } From dd2c350365ad9950b6afb3b6e4c7c256bf733097 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 12 Nov 2024 16:21:31 +0100 Subject: [PATCH 25/39] Add backwards compatibility with legacy architecture --- .../java/io/sentry/react/RNSentryPackage.java | 59 +++++++++++-------- .../replay/RNSentryReplayMaskManagerImpl.java | 16 +++++ .../RNSentryReplayUnmaskManagerImpl.java | 16 +++++ .../replay/RNSentryReplayMaskManager.java | 6 +- .../replay/RNSentryReplayUnmaskManager.java | 0 .../replay/RNSentryReplayMaskManager.java | 21 +++++++ .../replay/RNSentryReplayUnmaskManager.java | 21 +++++++ 7 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManagerImpl.java create mode 100644 packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManagerImpl.java rename packages/core/android/src/{main => newarch}/java/io/sentry/react/replay/RNSentryReplayMaskManager.java (87%) rename packages/core/android/src/{main => newarch}/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java (100%) create mode 100644 packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java create mode 100644 packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java index a6c143a64a..6c936ae348 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java @@ -9,21 +9,33 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.ViewManager; import io.sentry.react.replay.RNSentryReplayMaskManager; +import io.sentry.react.replay.RNSentryReplayMaskManagerImpl; import io.sentry.react.replay.RNSentryReplayUnmaskManager; +import io.sentry.react.replay.RNSentryReplayUnmaskManagerImpl; import java.util.HashMap; import java.util.List; import java.util.Map; public class RNSentryPackage extends TurboReactPackage { + private static final boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { if (RNSentryModuleImpl.NAME.equals(name)) { return new RNSentryModule(reactContext); - } else if (RNSentryReplayMaskManager.REACT_CLASS.equals(name)) { + } else if (isTurboModule) { + return getFabricComponentNativeModule(name); + } else { + return null; + } + } + + private NativeModule getFabricComponentNativeModule(String name) { + if (RNSentryReplayMaskManagerImpl.REACT_CLASS.equals(name)) { return new RNSentryReplayMaskManager(); - } else if (RNSentryReplayUnmaskManager.REACT_CLASS.equals(name)) { + } else if (RNSentryReplayUnmaskManagerImpl.REACT_CLASS.equals(name)) { return new RNSentryReplayUnmaskManager(); } else { return null; @@ -34,7 +46,6 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext) public ReactModuleInfoProvider getReactModuleInfoProvider() { return () -> { final Map moduleInfos = new HashMap<>(); - boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( RNSentryModuleImpl.NAME, new ReactModuleInfo( @@ -46,26 +57,28 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { false, // isCxxModule isTurboModule // isTurboModule )); - moduleInfos.put( - RNSentryReplayMaskManager.REACT_CLASS, - new ReactModuleInfo( - RNSentryReplayMaskManager.REACT_CLASS, // name - RNSentryReplayMaskManager.REACT_CLASS, // className - false, // canOverrideExistingModule - false, // needsEagerInit - false, // isCxxModule - true // isTurboModule - )); - moduleInfos.put( - RNSentryReplayUnmaskManager.REACT_CLASS, - new ReactModuleInfo( - RNSentryReplayUnmaskManager.REACT_CLASS, // name - RNSentryReplayUnmaskManager.REACT_CLASS, // className - false, // canOverrideExistingModule - false, // needsEagerInit - false, // isCxxModule - true // isTurboModule - )); + if (isTurboModule) { + moduleInfos.put( + RNSentryReplayMaskManagerImpl.REACT_CLASS, + new ReactModuleInfo( + RNSentryReplayMaskManagerImpl.REACT_CLASS, // name + RNSentryReplayMaskManagerImpl.REACT_CLASS, // className + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + )); + moduleInfos.put( + RNSentryReplayUnmaskManagerImpl.REACT_CLASS, + new ReactModuleInfo( + RNSentryReplayUnmaskManagerImpl.REACT_CLASS, // name + RNSentryReplayUnmaskManagerImpl.REACT_CLASS, // className + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + )); + } return moduleInfos; }; } diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManagerImpl.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManagerImpl.java new file mode 100644 index 0000000000..a5165eb7a7 --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManagerImpl.java @@ -0,0 +1,16 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.uimanager.ThemedReactContext; + +public final class RNSentryReplayMaskManagerImpl { + + private RNSentryReplayMaskManagerImpl() {} + + public static final String REACT_CLASS = "RNSentryReplayMask"; + + @NonNull + public static RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayMask(context); + } +} diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManagerImpl.java b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManagerImpl.java new file mode 100644 index 0000000000..7bee880222 --- /dev/null +++ b/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManagerImpl.java @@ -0,0 +1,16 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.uimanager.ThemedReactContext; + +public final class RNSentryReplayUnmaskManagerImpl { + + private RNSentryReplayUnmaskManagerImpl() {} + + public static final String REACT_CLASS = "RNSentryReplayUnmask"; + + @NonNull + public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayUnmask(context); + } +} diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java b/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java similarity index 87% rename from packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java rename to packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java index 3b2e912399..aa1ee90825 100644 --- a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayMaskManager.java +++ b/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java @@ -8,7 +8,7 @@ import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerDelegate; import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerInterface; -@ReactModule(name = RNSentryReplayMaskManager.REACT_CLASS) +@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS) public class RNSentryReplayMaskManager extends ViewGroupManager implements RNSentryReplayMaskManagerInterface { private final RNSentryReplayMaskManagerDelegate @@ -22,7 +22,7 @@ public ViewManagerDelegate getDelegate() { @NonNull @Override public String getName() { - return REACT_CLASS; + return RNSentryReplayMaskManagerImpl.REACT_CLASS; } @NonNull @@ -30,6 +30,4 @@ public String getName() { public RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) { return new RNSentryReplayMask(context); } - - public static final String REACT_CLASS = "RNSentryReplayMask"; } diff --git a/packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java b/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java similarity index 100% rename from packages/core/android/src/main/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java rename to packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java diff --git a/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java b/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java new file mode 100644 index 0000000000..236a7760e4 --- /dev/null +++ b/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayMaskManager.java @@ -0,0 +1,21 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; + +@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS) +public class RNSentryReplayMaskManager extends ViewGroupManager { + @NonNull + @Override + public String getName() { + return RNSentryReplayMaskManagerImpl.REACT_CLASS; + } + + @NonNull + @Override + public RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayMask(context); + } +} diff --git a/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java b/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java new file mode 100644 index 0000000000..86732eca38 --- /dev/null +++ b/packages/core/android/src/oldarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java @@ -0,0 +1,21 @@ +package io.sentry.react.replay; + +import androidx.annotation.NonNull; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewGroupManager; + +@ReactModule(name = RNSentryReplayUnmaskManagerImpl.REACT_CLASS) +public class RNSentryReplayUnmaskManager extends ViewGroupManager { + @NonNull + @Override + public String getName() { + return RNSentryReplayUnmaskManagerImpl.REACT_CLASS; + } + + @NonNull + @Override + public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) { + return new RNSentryReplayUnmask(context); + } +} From 30586a376d24e181822b920aac5f4ada0624e23d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Tue, 12 Nov 2024 18:30:15 +0100 Subject: [PATCH 26/39] revert disable profiling --- samples/react-native/src/App.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 239a2b200d..1acffadd03 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -28,7 +28,7 @@ import { Provider } from 'react-redux'; import { store } from './reduxApp'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import GesturesTracingScreen from './Screens/GesturesTracingScreen'; -import { LogBox, Platform, StyleSheet, View } from 'react-native'; +import { LogBox, Platform, StyleSheet, Text, View } from 'react-native'; import Ionicons from 'react-native-vector-icons/Ionicons'; import PlaygroundScreen from './Screens/PlaygroundScreen'; import { logWithoutTracing } from './utils'; @@ -120,7 +120,7 @@ Sentry.init({ // otherwise they will not work. // release: 'myapp@1.2.3+1', // dist: `1`, - // profilesSampleRate: 1.0, + profilesSampleRate: 1.0, _experiments: { replaysSessionSampleRate: 1.0, replaysOnErrorSampleRate: 1.0, @@ -273,6 +273,11 @@ function App() { <> + + + Hello + + ); } From d9cc0d90a2b3c5da519e35305fee04e2f1831573 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 21 Nov 2024 18:03:12 +0100 Subject: [PATCH 27/39] fix custom fallback tests --- packages/core/src/js/replay/CustomMask.tsx | 2 +- packages/core/test/replay/CustomMask.test.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/core/src/js/replay/CustomMask.tsx b/packages/core/src/js/replay/CustomMask.tsx index ffbb6a359e..6ebc67db42 100644 --- a/packages/core/src/js/replay/CustomMask.tsx +++ b/packages/core/src/js/replay/CustomMask.tsx @@ -49,4 +49,4 @@ const Unmask = ((): HostComponent | React.ComponentType => return require('../RNSentryReplayUnmaskNativeComponent').default; })(); -export { Mask, Unmask }; +export { Mask, Unmask, MaskFallback, UnmaskFallback }; diff --git a/packages/core/test/replay/CustomMask.test.ts b/packages/core/test/replay/CustomMask.test.ts index 7f82ccd060..44c5740418 100644 --- a/packages/core/test/replay/CustomMask.test.ts +++ b/packages/core/test/replay/CustomMask.test.ts @@ -11,10 +11,10 @@ describe('CustomMask', () => { View: jest.fn(), })); - const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + const { Mask, Unmask, MaskFallback, UnmaskFallback } = require('../../src/js/replay/CustomMask'); - expect(Mask).toBeDefined(); - expect(Unmask).toBeDefined(); + expect(Mask).toBe(MaskFallback); + expect(Unmask).toBe(UnmaskFallback); }); it('returns a fallback component when native view manager config is missing', () => { @@ -25,10 +25,10 @@ describe('CustomMask', () => { View: jest.fn(), })); - const { Mask, Unmask } = require('../../src/js/replay/CustomMask'); + const { Mask, Unmask, MaskFallback, UnmaskFallback } = require('../../src/js/replay/CustomMask'); - expect(Mask).toBeDefined(); - expect(Unmask).toBeDefined(); + expect(Mask).toBe(MaskFallback); + expect(Unmask).toBe(UnmaskFallback); }); it('returns native components when native components exist', () => { From e66514134e8a06afa87d388f83f06eb22215bd55 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 21 Nov 2024 18:05:48 +0100 Subject: [PATCH 28/39] Fix lint and typos --- .../RNSentryReplayPostInitTests.swift | 2 +- packages/core/ios/RNSentryReplay.m | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift index e7eed0d01c..6008746256 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryReplayPostInitTests.swift @@ -1,5 +1,5 @@ -import XCTest import Sentry +import XCTest final class RNSentryReplayPostInitTests: XCTestCase { diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.m index 425d8ce6c5..caa10cf1e3 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.m @@ -40,7 +40,7 @@ + (void)updateOptions:(NSMutableDictionary *)options + (NSArray *_Nonnull)getReplayRNUnmaskClasses { // We can't import RNSentryReplayUnmask.h here because it's Objective-C++ - // To avoid typos, we test the class existens in the tests + // To avoid typos, we test the class existence in the tests return @[ @"RNSentryReplayUnmask" ]; } @@ -65,7 +65,7 @@ + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOpt + (void)postInit { // We can't import RNSentryReplayMask.h here because it's Objective-C++ - // To avoid typos, we test the class existens in the tests + // To avoid typos, we test the class existence in the tests [PrivateSentrySDKOnly setRedactContainerClass:[self getMaskClass]]; [PrivateSentrySDKOnly setIgnoreContainerClass:[self getUnmaskClass]]; RNSentryReplayBreadcrumbConverter *breadcrumbConverter = @@ -73,12 +73,12 @@ + (void)postInit [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; } -+ (Class) getMaskClass ++ (Class)getMaskClass { return NSClassFromString(@"RNSentryReplayMask"); } -+ (Class) getUnmaskClass ++ (Class)getUnmaskClass { return NSClassFromString(@"RNSentryReplayUnmask"); } From 050acade6e7d3e2d0843dbfbcb1e82e67a713c7b Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 21 Nov 2024 19:05:28 +0100 Subject: [PATCH 29/39] use mask/unmask classes directly --- .../{RNSentryReplay.m => RNSentryReplay.mm} | 24 +++++++------------ .../RNSentryReplayBreadcrumbConverterHelper.h | 7 ++++++ .../RNSentryReplayBreadcrumbConverterHelper.m | 16 +++++++++++++ 3 files changed, 32 insertions(+), 15 deletions(-) rename packages/core/ios/{RNSentryReplay.m => RNSentryReplay.mm} (73%) create mode 100644 packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.h create mode 100644 packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m diff --git a/packages/core/ios/RNSentryReplay.m b/packages/core/ios/RNSentryReplay.mm similarity index 73% rename from packages/core/ios/RNSentryReplay.m rename to packages/core/ios/RNSentryReplay.mm index caa10cf1e3..8c941741c4 100644 --- a/packages/core/ios/RNSentryReplay.m +++ b/packages/core/ios/RNSentryReplay.mm @@ -1,6 +1,9 @@ #import "RNSentryReplay.h" -#import "RNSentryReplayBreadcrumbConverter.h" +#import "RNSentryReplayBreadcrumbConverterHelper.h" #import "React/RCTTextView.h" +#import "Replay/RNSentryReplayMask.h" +#import "Replay/RNSentryReplayUnmask.h" +#import #if SENTRY_TARGET_REPLAY_SUPPORTED @@ -37,13 +40,6 @@ + (void)updateOptions:(NSMutableDictionary *)options forKey:@"experimental"]; } -+ (NSArray *_Nonnull)getReplayRNUnmaskClasses -{ - // We can't import RNSentryReplayUnmask.h here because it's Objective-C++ - // To avoid typos, we test the class existence in the tests - return @[ @"RNSentryReplayUnmask" ]; -} - + (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions { NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init]; @@ -66,21 +62,19 @@ + (void)postInit { // We can't import RNSentryReplayMask.h here because it's Objective-C++ // To avoid typos, we test the class existence in the tests - [PrivateSentrySDKOnly setRedactContainerClass:[self getMaskClass]]; - [PrivateSentrySDKOnly setIgnoreContainerClass:[self getUnmaskClass]]; - RNSentryReplayBreadcrumbConverter *breadcrumbConverter = - [[RNSentryReplayBreadcrumbConverter alloc] init]; - [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; + [PrivateSentrySDKOnly setRedactContainerClass:[RNSentryReplay getMaskClass]]; + [PrivateSentrySDKOnly setIgnoreContainerClass:[RNSentryReplay getUnmaskClass]]; + [RNSentryReplayBreadcrumbConverterHelper configureSessionReplayWithConverter]; } + (Class)getMaskClass { - return NSClassFromString(@"RNSentryReplayMask"); + return RNSentryReplayMask.class; } + (Class)getUnmaskClass { - return NSClassFromString(@"RNSentryReplayUnmask"); + return RNSentryReplayUnmask.class; } @end diff --git a/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.h b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.h new file mode 100644 index 0000000000..727cf17dc7 --- /dev/null +++ b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.h @@ -0,0 +1,7 @@ +#import + +@interface RNSentryReplayBreadcrumbConverterHelper : NSObject + ++ (void)configureSessionReplayWithConverter; + +@end diff --git a/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m new file mode 100644 index 0000000000..1bef4efebf --- /dev/null +++ b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m @@ -0,0 +1,16 @@ +#import "RNSentryReplayBreadcrumbConverterHelper.h" + +#if SENTRY_TARGET_REPLAY_SUPPORTED +# import "RNSentryReplayBreadcrumbConverter.h" + +@implementation RNSentryReplayBreadcrumbConverterHelper + ++ (void)configureSessionReplayWithConverter +{ + RNSentryReplayBreadcrumbConverter *breadcrumbConverter = + [[RNSentryReplayBreadcrumbConverter alloc] init]; + [PrivateSentrySDKOnly configureSessionReplayWith:breadcrumbConverter screenshotProvider:nil]; +} + +@end +#endif From d50ffe20e0d3e47378671820f442cd358e7b039e Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Thu, 21 Nov 2024 19:08:47 +0100 Subject: [PATCH 30/39] fix changelog --- CHANGELOG.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae44d5175..1110d50f07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,27 @@ ## Unreleased +### Features + +- Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) + + ```jsx + import * as Sentry from '@sentry/react-native'; + + const Example = () => { + return ( + + + ${"All children of Sentry.Mask will be masked."} + + + ${"Only direct children of Sentry.Unmask will be unmasked."} + + + ); + }; + ``` + ### Fixes - Remove `.sentry` tmp directory and use environmental variables instead to save default Babel transformer path ([#4298](https://github.com/getsentry/sentry-react-native/pull/4298)) @@ -95,25 +116,6 @@ export SENTRY_DISABLE_NATIVE_DEBUG_UPLOAD=true ``` -- Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) - - ```jsx - import * as Sentry from '@sentry/react-native'; - - const Example = () => { - return ( - - - ${"All children of Sentry.Mask will be masked."} - - - ${"Only direct children will be unmasked."} - - - ); - }; - ``` - ### Fixes - Ignore JavascriptException to filter out obfuscated duplicate JS Errors on Android ([#4232](https://github.com/getsentry/sentry-react-native/pull/4232)) From eacc48799bf7995ff0eba0e2b26b5695e1f4936c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Fri, 22 Nov 2024 18:52:50 +0100 Subject: [PATCH 31/39] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1281682de4..fea28f9625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ ### Features -- Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) +- Add Replay Custom Masking for iOS and Android ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224), ([#4265](https://github.com/getsentry/sentry-react-native/pull/4265))) ```jsx import * as Sentry from '@sentry/react-native'; From eb457fc6eee542b8e09f571d2667b2711235dbe8 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Sat, 23 Nov 2024 01:07:17 +0100 Subject: [PATCH 32/39] fix old RN builds, remove ts from shipped package --- packages/core/.npmignore | 8 +++++++- packages/core/package.json | 1 - packages/core/src/js/replay/CustomMask.tsx | 15 +++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/core/.npmignore b/packages/core/.npmignore index 19f604c323..bf5fdefe0f 100644 --- a/packages/core/.npmignore +++ b/packages/core/.npmignore @@ -11,7 +11,13 @@ !react-native.config.js !/ios/**/* !/android/**/* -!src/**/* + +# New Architecture Codegen +!src/js/NativeRNSentry.ts +!src/js/RNSentryReplayMaskNativeComponent.ts +!src/js/RNSentryReplayUnmaskNativeComponent.ts + +# Scripts !scripts/collect-modules.sh !scripts/copy-debugid.js !scripts/has-sourcemap-debugid.js diff --git a/packages/core/package.json b/packages/core/package.json index 649ee6c517..e648f81a68 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,7 +16,6 @@ "typescript": { "definition": "dist/js/index.d.ts" }, - "react-native": "src/js/index.ts", "main": "dist/js/index.js", "scripts": { "build": "npx run-s build:sdk downlevel build:tools build:plugin", diff --git a/packages/core/src/js/replay/CustomMask.tsx b/packages/core/src/js/replay/CustomMask.tsx index 6ebc67db42..962288e40a 100644 --- a/packages/core/src/js/replay/CustomMask.tsx +++ b/packages/core/src/js/replay/CustomMask.tsx @@ -3,6 +3,11 @@ import * as React from 'react'; import type { HostComponent, ViewProps } from 'react-native'; import { UIManager, View } from 'react-native'; +const NativeComponentRegistry: { + get>(componentName: string, createViewConfig: () => C): HostComponent; +// eslint-disable-next-line @typescript-eslint/no-var-requires +} = require('react-native/Libraries/NativeComponent/NativeComponentRegistry'); + const MaskNativeComponentName = 'RNSentryReplayMask'; const UnmaskNativeComponentName = 'RNSentryReplayUnmask'; @@ -35,8 +40,9 @@ const Mask = ((): HostComponent | React.ComponentType => { return MaskFallback; } - // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access - return require('../RNSentryReplayMaskNativeComponent').default; + return NativeComponentRegistry.get(MaskNativeComponentName, () => ({ + uiViewClassName: MaskNativeComponentName, + })); })() const Unmask = ((): HostComponent | React.ComponentType => { @@ -45,8 +51,9 @@ const Unmask = ((): HostComponent | React.ComponentType => return UnmaskFallback; } - // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access - return require('../RNSentryReplayUnmaskNativeComponent').default; + return NativeComponentRegistry.get(UnmaskNativeComponentName, () => ({ + uiViewClassName: UnmaskNativeComponentName, + })); })(); export { Mask, Unmask, MaskFallback, UnmaskFallback }; From b41d759d4bbc501b2afa7dff225f170e0227b29d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 12:21:55 +0100 Subject: [PATCH 33/39] fix custom mask tests --- packages/core/test/replay/CustomMask.test.ts | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/core/test/replay/CustomMask.test.ts b/packages/core/test/replay/CustomMask.test.ts index 44c5740418..7ae7978665 100644 --- a/packages/core/test/replay/CustomMask.test.ts +++ b/packages/core/test/replay/CustomMask.test.ts @@ -34,13 +34,18 @@ describe('CustomMask', () => { it('returns native components when native components exist', () => { const mockMaskComponent = jest.fn(); const mockUnmaskComponent = jest.fn(); + const mockNativeComponentRegistryGet = jest.fn().mockImplementation((componentName: string) => { + if (componentName === 'RNSentryReplayMask') { + return mockMaskComponent; + } else if (componentName === 'RNSentryReplayUnmask') { + return mockUnmaskComponent; + } else { + throw new Error(`Unknown component name: ${componentName}`); + } + }); - jest.mock('../../src/js/RNSentryReplayMaskNativeComponent', () => ({ - default: mockMaskComponent, - })); - - jest.mock('../../src/js/RNSentryReplayUnmaskNativeComponent', () => ({ - default: mockUnmaskComponent, + jest.mock('react-native/Libraries/NativeComponent/NativeComponentRegistry', () => ({ + get: mockNativeComponentRegistryGet, })); jest.mock('react-native', () => ({ @@ -54,5 +59,9 @@ describe('CustomMask', () => { expect(Mask).toBe(mockMaskComponent); expect(Unmask).toBe(mockUnmaskComponent); + + expect(mockNativeComponentRegistryGet).toBeCalledTimes(2); + expect(mockNativeComponentRegistryGet).toBeCalledWith('RNSentryReplayMask', expect.any(Function)); + expect(mockNativeComponentRegistryGet).toBeCalledWith('RNSentryReplayUnmask', expect.any(Function)); }); }); From 8eaa867e0425f3bd54f242ae3538720ddb572e96 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 12:37:11 +0100 Subject: [PATCH 34/39] add native component registry access explanation --- packages/core/src/js/replay/CustomMask.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/core/src/js/replay/CustomMask.tsx b/packages/core/src/js/replay/CustomMask.tsx index 962288e40a..8abc635da0 100644 --- a/packages/core/src/js/replay/CustomMask.tsx +++ b/packages/core/src/js/replay/CustomMask.tsx @@ -1,7 +1,7 @@ import { logger } from '@sentry/utils'; import * as React from 'react'; import type { HostComponent, ViewProps } from 'react-native'; -import { UIManager, View } from 'react-native'; +import { UIManager, View, requireNativeComponent } from 'react-native'; const NativeComponentRegistry: { get>(componentName: string, createViewConfig: () => C): HostComponent; @@ -40,6 +40,8 @@ const Mask = ((): HostComponent | React.ComponentType => { return MaskFallback; } + // Based on @react-native/babel-plugin-codegen output + // https://github.com/facebook/react-native/blob/b32c6c2cc1bc566a85a883901dbf5e23b5a75b61/packages/react-native-codegen/src/generators/components/GenerateViewConfigJs.js#L139 return NativeComponentRegistry.get(MaskNativeComponentName, () => ({ uiViewClassName: MaskNativeComponentName, })); @@ -51,6 +53,8 @@ const Unmask = ((): HostComponent | React.ComponentType => return UnmaskFallback; } + // Based on @react-native/babel-plugin-codegen output + // https://github.com/facebook/react-native/blob/b32c6c2cc1bc566a85a883901dbf5e23b5a75b61/packages/react-native-codegen/src/generators/components/GenerateViewConfigJs.js#L139 return NativeComponentRegistry.get(UnmaskNativeComponentName, () => ({ uiViewClassName: UnmaskNativeComponentName, })); From 4e18dc46d8b54b6b6e52df5962e873938d28033c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:55:03 +0100 Subject: [PATCH 35/39] Apply suggestions from code review Co-authored-by: LucasZF --- CHANGELOG.md | 2 +- packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a4bca36e1..d6fda94a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ ### Features -- Add Replay Custom Masking for iOS ([#4238](https://github.com/getsentry/sentry-react-native/pull/4224)) +- Add Replay Custom Masking for iOS ([#4224](https://github.com/getsentry/sentry-react-native/pull/4224)) ```jsx import * as Sentry from '@sentry/react-native'; diff --git a/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m index 1bef4efebf..ef3da7ec38 100644 --- a/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m +++ b/packages/core/ios/RNSentryReplayBreadcrumbConverterHelper.m @@ -13,4 +13,5 @@ + (void)configureSessionReplayWithConverter } @end + #endif From 71664aef066d575371d4805e54a06f8a9d29d304 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 14:15:16 +0100 Subject: [PATCH 36/39] use deprecated ReactModuleInfo constructor --- .../android/src/main/java/io/sentry/react/RNSentryPackage.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java index 6c936ae348..1af2fe8c89 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java @@ -65,6 +65,7 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { RNSentryReplayMaskManagerImpl.REACT_CLASS, // className false, // canOverrideExistingModule false, // needsEagerInit + false, // hasConstants, required in RN 0.65 false, // isCxxModule true // isTurboModule )); @@ -75,6 +76,7 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { RNSentryReplayUnmaskManagerImpl.REACT_CLASS, // className false, // canOverrideExistingModule false, // needsEagerInit + false, // hasConstants, required in RN 0.65 false, // isCxxModule true // isTurboModule )); From af13626ba12fa89aa5d311b006ef5f72ee0f1e49 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 14:21:07 +0100 Subject: [PATCH 37/39] fix lint --- packages/core/src/js/replay/CustomMask.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/js/replay/CustomMask.tsx b/packages/core/src/js/replay/CustomMask.tsx index 8abc635da0..df4e3c1cfc 100644 --- a/packages/core/src/js/replay/CustomMask.tsx +++ b/packages/core/src/js/replay/CustomMask.tsx @@ -1,7 +1,7 @@ import { logger } from '@sentry/utils'; import * as React from 'react'; import type { HostComponent, ViewProps } from 'react-native'; -import { UIManager, View, requireNativeComponent } from 'react-native'; +import { UIManager, View } from 'react-native'; const NativeComponentRegistry: { get>(componentName: string, createViewConfig: () => C): HostComponent; From 2189770712a4b3bf145e8a3b9ab849ffe977cd6c Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 15:08:13 +0100 Subject: [PATCH 38/39] remove unintentional sample text element --- samples/react-native/src/App.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 5ac8a5dfcd..04348fa5c6 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -28,7 +28,7 @@ import { Provider } from 'react-redux'; import { store } from './reduxApp'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import GesturesTracingScreen from './Screens/GesturesTracingScreen'; -import { LogBox, Platform, StyleSheet, Text, View } from 'react-native'; +import { LogBox, Platform, StyleSheet, View } from 'react-native'; import Ionicons from 'react-native-vector-icons/Ionicons'; import PlaygroundScreen from './Screens/PlaygroundScreen'; import { logWithoutTracing } from './utils'; @@ -277,11 +277,6 @@ function App() { <> - - - Hello - - ); } From 3bcd455fbb5011901e3576cd210dfcded699ad99 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 16:33:38 +0100 Subject: [PATCH 39/39] reuse class name from impl --- .../io/sentry/react/replay/RNSentryReplayUnmaskManager.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java b/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java index b836d6860a..da0648123d 100644 --- a/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java +++ b/packages/core/android/src/newarch/java/io/sentry/react/replay/RNSentryReplayUnmaskManager.java @@ -8,7 +8,7 @@ import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerDelegate; import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerInterface; -@ReactModule(name = RNSentryReplayUnmaskManager.REACT_CLASS) +@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS) public class RNSentryReplayUnmaskManager extends ViewGroupManager implements RNSentryReplayUnmaskManagerInterface { private final RNSentryReplayUnmaskManagerDelegate< @@ -23,7 +23,7 @@ public ViewManagerDelegate getDelegate() { @NonNull @Override public String getName() { - return REACT_CLASS; + return RNSentryReplayMaskManagerImpl.REACT_CLASS; } @NonNull @@ -31,6 +31,4 @@ public String getName() { public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) { return new RNSentryReplayUnmask(context); } - - public static final String REACT_CLASS = "RNSentryReplayUnmask"; }