Skip to content

Commit bc4b9f6

Browse files
misc: Add linked errors examples to the sample apps (#3549)
* Fix native linked errors execution order * fix lint * Add integrations execution order tests * Add jest extended types and linkedErrors order tests * Add changelog * remove empty test * fix native linked errors async calls * fix native async calls ios * fix old arch build * feat: Add linked errors examples to the sample apps * fix sample lint * remove unused header file
1 parent deebf78 commit bc4b9f6

File tree

10 files changed

+150
-15
lines changed

10 files changed

+150
-15
lines changed

samples/expo/app/(tabs)/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ export default function TabOneScreen() {
104104
Sentry.captureException(new Error('Captured exception'));
105105
}}
106106
/>
107+
<Button
108+
title="Capture exception with cause"
109+
onPress={() => {
110+
const error = new Error('Captured exception')
111+
error.cause = new Error('Cause of captured exception')
112+
Sentry.captureException(error);
113+
}}
114+
/>
107115
<Button
108116
title="Uncaught Thrown Error"
109117
onPress={() => {

samples/react-native/android/app/src/main/java/com/samplenewarchitecture/MainApplication.kt

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,16 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
1111
import com.facebook.react.defaults.DefaultReactNativeHost
1212
import com.facebook.react.flipper.ReactNativeFlipper
1313
import com.facebook.soloader.SoLoader
14-
import io.sentry.react.RNSentryPackage
1514

16-
class MainApplication : Application(), ReactApplication {
15+
class MainApplication() : Application(), ReactApplication {
1716
override val reactNativeHost: ReactNativeHost =
1817
object : DefaultReactNativeHost(this) {
19-
override fun getPackages(): List<ReactPackage> {
20-
val packages: MutableList<ReactPackage> = PackageList(this).packages
21-
packages.add(SamplePackage())
22-
// Packages that cannot be auto linked yet can be added manually here, for example:
23-
// packages.add(new MyReactNativePackage());
24-
for (pkg in packages) {
25-
if (pkg is RNSentryPackage) {
26-
return packages
27-
}
18+
override fun getPackages(): List<ReactPackage> =
19+
PackageList(this).packages.apply {
20+
add(SamplePackage())
21+
add(TurboSamplePackage())
2822
}
29-
packages.add(RNSentryPackage())
30-
return packages
31-
}
23+
3224
override fun getJSMainModuleName(): String = "index"
3325
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
3426
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
@@ -47,4 +39,4 @@ class MainApplication : Application(), ReactApplication {
4739
}
4840
ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager)
4941
}
50-
}
42+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.samplenewarchitecture
2+
3+
import com.facebook.fbreact.specs.NativePlatformSampleModuleSpec
4+
import com.facebook.react.bridge.ReactApplicationContext
5+
6+
class NativePlatformSampleModule(reactContext: ReactApplicationContext) : NativePlatformSampleModuleSpec(reactContext) {
7+
8+
override fun getName() = NAME
9+
10+
override fun crashOrString(): String {
11+
throw RuntimeException("JVM Crash in NativePlatformSampleModule.crashOrString()")
12+
}
13+
14+
companion object {
15+
const val NAME = "NativePlatformSampleModule"
16+
}
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.samplenewarchitecture
2+
3+
import com.facebook.react.TurboReactPackage
4+
import com.facebook.react.bridge.NativeModule
5+
import com.facebook.react.bridge.ReactApplicationContext
6+
import com.facebook.react.module.model.ReactModuleInfo
7+
import com.facebook.react.module.model.ReactModuleInfoProvider
8+
import org.jetbrains.annotations.Nullable
9+
10+
class TurboSamplePackage : TurboReactPackage() {
11+
@Nullable
12+
override fun getModule(
13+
name: String,
14+
reactApplicationContext: ReactApplicationContext
15+
): NativeModule? {
16+
return if (name == NativePlatformSampleModule.NAME) {
17+
NativePlatformSampleModule(reactApplicationContext)
18+
} else {
19+
null
20+
}
21+
}
22+
23+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
24+
return ReactModuleInfoProvider {
25+
val moduleInfos: MutableMap<String, ReactModuleInfo> =
26+
HashMap()
27+
moduleInfos[NativePlatformSampleModule.NAME] = ReactModuleInfo(
28+
NativePlatformSampleModule.NAME,
29+
NativePlatformSampleModule.NAME,
30+
false, // canOverrideExistingModule
31+
false, // needsEagerInit
32+
true, // hasConstants
33+
false, // isCxxModule
34+
true // isTurboModule
35+
)
36+
moduleInfos
37+
}
38+
}
39+
}

samples/react-native/android/app/src/main/jni/OnLoad.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
// }
2828
// }
2929

30+
#include <AppSpecs.h>
3031
#include <DefaultComponentsRegistry.h>
3132
#include <DefaultTurboModuleManagerDelegate.h>
3233
#include <fbjni/fbjni.h>
@@ -73,6 +74,11 @@ std::shared_ptr<TurboModule> javaModuleProvider(
7374
// }
7475
// return rncore_ModuleProvider(moduleName, params);
7576

77+
auto module = AppSpecs_ModuleProvider(name, params);
78+
if (module != nullptr) {
79+
return module;
80+
}
81+
7682
// By default we just use the module providers autolinked by RN CLI
7783
return rncli_ModuleProvider(name, params);
7884
}

samples/react-native/ios/sampleNewArchitecture.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
1313
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
1414
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
15+
338BBBC82B614FA10035844C /* NativePlatformSampleModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 338BBBC62B614FA10035844C /* NativePlatformSampleModule.mm */; };
1516
33E2D62A29A7719600B5042B /* RCTAssetsModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 33E2D62829A7719600B5042B /* RCTAssetsModule.m */; };
1617
7699B88040F8A987B510C191 /* libPods-sampleNewArchitecture-sampleNewArchitectureTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-sampleNewArchitecture-sampleNewArchitectureTests.a */; };
1718
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
@@ -38,6 +39,8 @@
3839
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = sampleNewArchitecture/Info.plist; sourceTree = "<group>"; };
3940
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = sampleNewArchitecture/main.m; sourceTree = "<group>"; };
4041
19F6CBCC0A4E27FBF8BF4A61 /* libPods-sampleNewArchitecture-sampleNewArchitectureTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-sampleNewArchitecture-sampleNewArchitectureTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
42+
338BBBC62B614FA10035844C /* NativePlatformSampleModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NativePlatformSampleModule.mm; path = sampleNewArchitecture/NativePlatformSampleModule.mm; sourceTree = "<group>"; };
43+
338BBBC72B614FA10035844C /* NativePlatformSampleModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativePlatformSampleModule.h; path = sampleNewArchitecture/NativePlatformSampleModule.h; sourceTree = "<group>"; };
4144
33E2D62829A7719600B5042B /* RCTAssetsModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTAssetsModule.m; path = sampleNewArchitecture/RCTAssetsModule.m; sourceTree = "<group>"; };
4245
33E2D62929A7719600B5042B /* RCTAssetsModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTAssetsModule.h; path = sampleNewArchitecture/RCTAssetsModule.h; sourceTree = "<group>"; };
4346
3B4392A12AC88292D35C810B /* Pods-sampleNewArchitecture.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sampleNewArchitecture.debug.xcconfig"; path = "Target Support Files/Pods-sampleNewArchitecture/Pods-sampleNewArchitecture.debug.xcconfig"; sourceTree = "<group>"; };
@@ -89,6 +92,8 @@
8992
13B07FAE1A68108700A75B9A /* sampleNewArchitecture */ = {
9093
isa = PBXGroup;
9194
children = (
95+
338BBBC72B614FA10035844C /* NativePlatformSampleModule.h */,
96+
338BBBC62B614FA10035844C /* NativePlatformSampleModule.mm */,
9297
33E2D62929A7719600B5042B /* RCTAssetsModule.h */,
9398
33E2D62829A7719600B5042B /* RCTAssetsModule.m */,
9499
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
@@ -416,6 +421,7 @@
416421
files = (
417422
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
418423
13B07FC11A68108700A75B9A /* main.m in Sources */,
424+
338BBBC82B614FA10035844C /* NativePlatformSampleModule.mm in Sources */,
419425
33E2D62A29A7719600B5042B /* RCTAssetsModule.m in Sources */,
420426
);
421427
runOnlyForDeploymentPostprocessing = 0;
@@ -601,6 +607,7 @@
601607
"-DFOLLY_NO_CONFIG",
602608
"-DFOLLY_MOBILE=1",
603609
"-DFOLLY_USE_LIBCPP=1",
610+
" ",
604611
);
605612
OTHER_LDFLAGS = (
606613
"$(inherited)",
@@ -673,6 +680,7 @@
673680
"-DFOLLY_NO_CONFIG",
674681
"-DFOLLY_MOBILE=1",
675682
"-DFOLLY_USE_LIBCPP=1",
683+
" ",
676684
);
677685
OTHER_LDFLAGS = (
678686
"$(inherited)",
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#import <Foundation/Foundation.h>
2+
3+
#ifdef RCT_NEW_ARCH_ENABLED
4+
#import <AppSpecs/AppSpecs.h>
5+
6+
@interface NativePlatformSampleModule : NSObject <NativePlatformSampleModuleSpec>
7+
8+
@end
9+
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#import "NativePlatformSampleModule.h"
2+
3+
#ifdef RCT_NEW_ARCH_ENABLED
4+
5+
@implementation NativePlatformSampleModule
6+
7+
RCT_EXPORT_MODULE();
8+
9+
// Thanks to this guard, we won't compile this code when we build for the old architecture.
10+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
11+
return std::make_shared<facebook::react::NativePlatformSampleModuleSpecJSI>(params);
12+
}
13+
14+
- (NSString *)crashOrString {
15+
NSObject * nilObject = NULL;
16+
NSArray * _ = @[nilObject];
17+
return @"NEVER RETURNED";
18+
}
19+
20+
@end
21+
22+
#endif

samples/react-native/src/Screens/ErrorsScreen.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { StackNavigationProp } from '@react-navigation/stack';
1818
import { UserFeedbackModal } from '../components/UserFeedbackModal';
1919
import { FallbackRender } from '@sentry/react';
2020
import NativeSampleModule from '../../tm/NativeSampleModule';
21+
import NativePlatformSampleModule from '../../tm/NativePlatformSampleModule';
2122
import { timestampInSeconds } from '@sentry/utils';
2223

2324
const { AssetsModule, CppModule, CrashModule } = NativeModules;
@@ -77,6 +78,16 @@ const ErrorsScreen = (_props: Props) => {
7778
Sentry.captureException(new Error('Captured exception'));
7879
}}
7980
/>
81+
<Button
82+
title="Capture exception with cause"
83+
onPress={() => {
84+
const error = new Error('Captured exception');
85+
(error as { cause?: unknown }).cause = new Error(
86+
'Cause of captured exception',
87+
);
88+
Sentry.captureException(error);
89+
}}
90+
/>
8091
<Button
8192
title="Uncaught Thrown Error"
8293
onPress={() => {
@@ -127,6 +138,21 @@ const ErrorsScreen = (_props: Props) => {
127138
NativeSampleModule?.crash();
128139
}}
129140
/>
141+
<Button
142+
title="Catch Turbo Crash or String"
143+
onPress={() => {
144+
if (!NativePlatformSampleModule) {
145+
throw new Error(
146+
'NativePlatformSampleModule is not available. Build the application with the New Architecture enabled.',
147+
);
148+
}
149+
try {
150+
NativePlatformSampleModule?.crashOrString();
151+
} catch (e) {
152+
Sentry.captureException(e);
153+
}
154+
}}
155+
/>
130156
{Platform.OS === 'android' && (
131157
<>
132158
<Button
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { TurboModule } from 'react-native';
2+
import { TurboModuleRegistry } from 'react-native';
3+
4+
export interface Spec extends TurboModule {
5+
crashOrString(): string;
6+
}
7+
8+
export default TurboModuleRegistry.get<Spec>('NativePlatformSampleModule');

0 commit comments

Comments
 (0)