Skip to content

Commit d0a3d40

Browse files
feat(example): Add more sdk crashes buttons
1 parent 5c9b032 commit d0a3d40

File tree

6 files changed

+303
-46
lines changed

6 files changed

+303
-46
lines changed

android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77
import com.facebook.react.bridge.ReactContextBaseJavaModule;
88
import com.facebook.react.bridge.ReactMethod;
99
import com.instabug.crash.CrashReporting;
10+
import com.instabug.crash.models.IBGNonFatalException;
1011
import com.instabug.library.Feature;
1112
import com.instabug.reactlibrary.utils.MainThreadHandler;
1213

1314
import org.json.JSONObject;
1415

1516
import java.lang.reflect.InvocationTargetException;
1617
import java.lang.reflect.Method;
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.Random;
1721

1822
import javax.annotation.Nonnull;
1923
import javax.annotation.Nullable;
@@ -57,8 +61,8 @@ public void run() {
5761
* Send unhandled JS error object
5862
*
5963
* @param exceptionObject Exception object to be sent to Instabug's servers
60-
* @param promise This makes sure that the RN side crashes the app only after the Android SDK
61-
* finishes processing/handling the crash.
64+
* @param promise This makes sure that the RN side crashes the app only after the Android SDK
65+
* finishes processing/handling the crash.
6266
*/
6367
@ReactMethod
6468
public void sendJSCrash(final String exceptionObject, final Promise promise) {
@@ -90,29 +94,96 @@ public void sendHandledJSCrash(final String exceptionObject) {
9094
}
9195
}
9296

93-
private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) {
94-
MainThreadHandler.runOnMainThread(new Runnable() {
95-
@Override
96-
public void run() {
97-
try {
98-
Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class);
99-
if (method != null) {
100-
method.invoke(null, exceptionObject, isHandled);
101-
RNInstabugReactnativeModule.clearCurrentReport();
102-
}
103-
} catch (ClassNotFoundException e) {
104-
e.printStackTrace();
105-
} catch (IllegalAccessException e) {
106-
e.printStackTrace();
107-
} catch (InvocationTargetException e) {
108-
e.printStackTrace();
109-
} finally {
110-
if (onComplete != null) {
111-
onComplete.run();
112-
}
113-
}
114-
}
115-
});
97+
@ReactMethod
98+
public void sendNativeNonFatal(final String exceptionObject) {
99+
final IBGNonFatalException exception = new IBGNonFatalException.Builder(new IllegalStateException("Test exception"))
100+
.build();
101+
CrashReporting.report(exception);
102+
103+
}
104+
105+
@ReactMethod
106+
public void sendNativeFatalCrash() {
107+
throw new IllegalStateException("Unhandled IllegalStateException from Instabug Test App");
108+
}
109+
110+
@ReactMethod
111+
public void sendANR() {
112+
try {
113+
Thread.sleep(20000);
114+
} catch (InterruptedException e) {
115+
throw new RuntimeException(e);
116+
}
117+
}
118+
119+
@ReactMethod
120+
public void sendFatalHang() {
121+
try {
122+
Thread.sleep(3000);
123+
} catch (InterruptedException e) {
124+
throw new RuntimeException(e);
125+
}
126+
}
127+
128+
@ReactMethod
129+
public void sendOOM() {
130+
oomCrash();
131+
}
132+
133+
private void oomCrash() {
134+
new Thread(() -> {
135+
List<String> stringList = new ArrayList<>();
136+
for (int i = 0; i < 1_000_000; i++) {
137+
stringList.add(getRandomString(10_000));
138+
}
139+
}).start();
140+
}
141+
142+
private String getRandomString(int length) {
143+
List<Character> charset = new ArrayList<>();
144+
for (char ch = 'a'; ch <= 'z'; ch++) {
145+
charset.add(ch);
146+
}
147+
for (char ch = 'A'; ch <= 'Z'; ch++) {
148+
charset.add(ch);
149+
}
150+
for (char ch = '0'; ch <= '9'; ch++) {
151+
charset.add(ch);
152+
}
153+
154+
StringBuilder randomString = new StringBuilder();
155+
Random random = new Random();
156+
for (int i = 0; i < length; i++) {
157+
char randomChar = charset.get(random.nextInt(charset.size()));
158+
randomString.append(randomChar);
159+
}
160+
161+
return randomString.toString();
162+
}
163+
164+
private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) {
165+
MainThreadHandler.runOnMainThread(new Runnable() {
166+
@Override
167+
public void run() {
168+
try {
169+
Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class);
170+
if (method != null) {
171+
method.invoke(null, exceptionObject, isHandled);
172+
RNInstabugReactnativeModule.clearCurrentReport();
173+
}
174+
} catch (ClassNotFoundException e) {
175+
e.printStackTrace();
176+
} catch (IllegalAccessException e) {
177+
e.printStackTrace();
178+
} catch (InvocationTargetException e) {
179+
e.printStackTrace();
180+
} finally {
181+
if (onComplete != null) {
182+
onComplete.run();
183+
}
184+
}
185+
}
186+
});
116187

117188
}
118189
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React, { PropsWithChildren } from 'react';
2+
3+
import { Box, HStack, Pressable, Text } from 'native-base';
4+
import { Platform } from 'react-native';
5+
6+
interface PlatformListTileProps extends PropsWithChildren {
7+
title: string;
8+
onPress?: () => void;
9+
platform?: 'ios' | 'android';
10+
}
11+
12+
export const PlatformListTile: React.FC<PlatformListTileProps> = ({
13+
title,
14+
onPress,
15+
platform,
16+
children,
17+
}) => {
18+
if (Platform.OS === platform || !platform) {
19+
return (
20+
<Pressable
21+
onPress={onPress}
22+
p="4"
23+
rounded="2"
24+
shadow="1"
25+
borderBottomWidth="1"
26+
borderColor="coolGray.300"
27+
bg="coolGray.100"
28+
_pressed={{ bg: 'coolGray.200' }}>
29+
<HStack justifyContent="space-between" alignItems="center">
30+
<Text>{title}</Text>
31+
<Box width={160}>{children}</Box>
32+
</HStack>
33+
</Pressable>
34+
);
35+
}
36+
return null;
37+
};
Lines changed: 113 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,126 @@
11
import React from 'react';
2-
import { Alert } from 'react-native';
2+
import { Alert, ScrollView, Text } from 'react-native';
33

44
import { CrashReporting } from 'instabug-reactnative';
55

66
import { ListTile } from '../components/ListTile';
77
import { Screen } from '../components/Screen';
8+
import { Section } from '../components/Section';
9+
import { NativeCrashReporting } from '../../../../src/native/NativeCrashReporting';
10+
import { PlatformListTile } from '../components/PlatformListTie';
811

912
export const CrashReportingScreen: React.FC = () => {
13+
function throwHandledException(error: Error) {
14+
try {
15+
if (!error.message) {
16+
const appName = 'Instabug Test App';
17+
error.message = `Handled ${error.name} From ${appName}`;
18+
}
19+
throw error;
20+
} catch (err) {
21+
if (err instanceof Error) {
22+
CrashReporting.reportError(err).then(() =>
23+
Alert.alert(`Crash report for ${error.name} is Sent!`),
24+
);
25+
}
26+
}
27+
}
28+
29+
function throwUnhandledException(error: Error, isPromise: boolean = false) {
30+
const appName = 'Instabug Test App';
31+
const rejectionType = isPromise ? 'Promise Rejection ' : '';
32+
const errorMessage = `Unhandled ${rejectionType}${error.name} from ${appName}`;
33+
34+
if (!error.message) {
35+
console.log(`IBG-CRSH | Error message: ${error.message}`);
36+
error.message = errorMessage;
37+
}
38+
39+
if (isPromise) {
40+
console.log('IBG-CRSH | Promise');
41+
Promise.reject(error).then(() =>
42+
Alert.alert(`Promise Rejection Crash report for ${error.name} is Sent!`),
43+
);
44+
} else {
45+
throw error;
46+
}
47+
}
48+
1049
return (
1150
<Screen>
12-
<ListTile
13-
title="Throw Handled Exception"
14-
onPress={() => {
15-
try {
16-
throw new Error('Handled Exception From Instabug Test App');
17-
} catch (err) {
18-
if (err instanceof Error) {
19-
CrashReporting.reportError(err);
20-
Alert.alert('Crash report Sent!');
21-
}
22-
}
23-
}}
24-
/>
25-
<ListTile
26-
title="Reject an Unhandled Promise"
27-
onPress={() => {
28-
Promise.reject(new Error('Unhandled Promise Rejection from Instabug Test App'));
29-
Alert.alert('Crash report sent!');
30-
}}
31-
/>
51+
<ScrollView>
52+
<Section title="Non-Fatals">
53+
<ListTile
54+
title="Throw Handled Exception"
55+
onPress={() => throwHandledException(new Error())}
56+
/>
57+
<ListTile
58+
title="Throw Handled Syntax Exception"
59+
onPress={() => throwHandledException(new SyntaxError())}
60+
/>
61+
<ListTile
62+
title="Throw Handled Range Exception"
63+
onPress={() => throwHandledException(new RangeError())}
64+
/>
65+
<ListTile
66+
title="Throw Handled Reference Exception"
67+
onPress={() => throwHandledException(new ReferenceError())}
68+
/>
69+
<ListTile
70+
title="Throw Handled URIError Exception"
71+
onPress={() => throwHandledException(new URIError())}
72+
/>
73+
<ListTile
74+
title="Throw Handled Native Exception"
75+
onPress={() => NativeCrashReporting.sendNativeNonFatal()}
76+
/>
77+
</Section>
78+
<Section title={'Fatal Crashes'}>
79+
<Text>Fatal Crashes can only be tested in release mode </Text>
80+
<Text>These buttons will crash the application.</Text>
81+
<ListTile
82+
title="Reject Unhandled Promise"
83+
onPress={() => throwUnhandledException(Error(), true)}
84+
/>
85+
<ListTile
86+
title="Throw Unhandled Fatal Exception"
87+
onPress={() => throwUnhandledException(Error())}
88+
/>
89+
<ListTile
90+
title="Throw Unhandled Syntax Exception"
91+
onPress={() => throwUnhandledException(new SyntaxError())}
92+
/>
93+
<ListTile
94+
title="Throw Unhandled Range Exception"
95+
onPress={() => throwUnhandledException(new RangeError())}
96+
/>
97+
<ListTile
98+
title="Throw Unhandled Reference Exception"
99+
onPress={() => throwUnhandledException(new ReferenceError())}
100+
/>
101+
<ListTile
102+
title="Throw Unhandled URIError Exception"
103+
onPress={() => throwUnhandledException(new URIError())}
104+
/>
105+
<ListTile
106+
title="Throw Unhandled Native Exception"
107+
onPress={() => NativeCrashReporting.sendNativeFatalCrash()}
108+
/>
109+
<ListTile
110+
title="Send Native Fatal Hang"
111+
onPress={() => NativeCrashReporting.sendFatalHang()}
112+
/>
113+
<PlatformListTile
114+
title="Send Native ANR"
115+
onPress={() => NativeCrashReporting.sendANR()}
116+
platform={'android'}
117+
/>
118+
<ListTile
119+
title="Throw Unhandled Native OOM Exception"
120+
onPress={() => NativeCrashReporting.sendOOM()}
121+
/>
122+
</Section>
123+
</ScrollView>
32124
</Screen>
33125
);
34126
};

ios/RNInstabug/InstabugCrashReportingBridge.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
- (void)setEnabled:(BOOL) isEnabled;
88
- (void)sendJSCrash:(NSDictionary *)stackTrace;
99
- (void)sendHandledJSCrash:(NSDictionary *)stackTrace;
10+
- (void)sendNativeNonFatal;
11+
- (void)sendNativeFatalCrash;
12+
- (void)sendFatalHang;
13+
- (void)sendOOM;
1014

1115
@end

0 commit comments

Comments
 (0)