Skip to content

Commit a434614

Browse files
authored
Merge pull request #75 from master-atul/develop
Merging test branch
2 parents f7bac35 + e03a7c4 commit a434614

File tree

6 files changed

+129
-51
lines changed

6 files changed

+129
-51
lines changed

README.md

+53-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ To tackle this we register a global error handler that could be used to for exam
2020
**V2 of this module now supports catching Unhandled Native Exceptions also along with the JS Exceptions ✌🏻🍻**
2121
There are **NO** breaking changes. So its safe to upgrade from v1 to v2. So there is no reason not to 😉.
2222

23+
**V2.9**
24+
- Adds support for executing previously set error handlers (now this module can work with other analytics modules)
25+
- Adds an improved approach for overwriting native error handlers.
26+
- Thanks @ [Damien Solimando](https://github.com/dsolimando)
27+
2328
**Example** repo can be found here:
2429
*[https://github.com/master-atul/react-native-exception-handler-example](https://github.com/master-atul/react-native-exception-handler-example) *
2530

@@ -128,7 +133,7 @@ setJSExceptionHandler((error, isFatal) => {
128133
// or hit google analytics to track crashes
129134
// or hit a custom api to inform the dev team.
130135
});
131-
136+
//=================================================
132137
// ADVANCED use case:
133138
const exceptionhandler = (error, isFatal) => {
134139
// your error handler function
@@ -156,17 +161,21 @@ setNativeExceptionHandler((exceptionString) => {
156161
//NOTE: alert or showing any UI change via JS
157162
//WILL NOT WORK in case of NATIVE ERRORS.
158163
});
159-
164+
//====================================================
160165
// ADVANCED use case:
161166
const exceptionhandler = (exceptionString) => {
162167
// your exception handler code here
163168
}
164-
setNativeExceptionHandler(exceptionhandler,forceAppQuit);
169+
setNativeExceptionHandler(exceptionhandler,forceAppQuit,executeDefaultHandler);
165170
// - exceptionhandler is the exception handler function
166171
// - forceAppQuit is an optional ANDROID specific parameter that defines
167-
// if the app should be force quit on error. default value is true.
168-
// To see usecase check the common issues section.
169-
172+
// if the app should be force quit on error. default value is true.
173+
// To see usecase check the common issues section.
174+
// - executeDefaultHandler is an optional boolean (both IOS, ANDROID)
175+
// It executes previous exception handlers if set by some other module.
176+
// It will come handy when you use any other crash analytics module along with this one
177+
// Default value is set to false. Set to true if you are using other analytics modules.
178+
170179
```
171180
It is recommended you set both the handlers.
172181

@@ -201,7 +210,39 @@ In Android and iOS you will see something like
201210
<img src="https://github.com/master-atul/react-native-exception-handler/raw/master/screens/ios_native_exception.png" width="300"/>
202211
</p>
203212

204-
**Modifying Android Native Exception handler UI** (NATIVE CODE HAS TO BE WRITTEN) *recommended that you do this in android studio*
213+
**Modifying Android Native Exception handler (RECOMMENDED APPROACH)**
214+
215+
(NATIVE CODE HAS TO BE WRITTEN) *recommended that you do this in android studio*
216+
217+
- In the `android/app/src/main/java/[...]/MainActivity.java`
218+
219+
```java
220+
import com.masteratul.exceptionhandler.ReactNativeExceptionHandlerModule;
221+
import com.masteratul.exceptionhandler.NativeExceptionHandlerIfc
222+
...
223+
...
224+
...
225+
public class MainApplication extends Application implements ReactApplication {
226+
...
227+
...
228+
@Override
229+
public void onCreate() {
230+
....
231+
....
232+
....
233+
ReactNativeExceptionHandlerModule.setNativeExceptionHandler(new NativeExceptionHandlerIfc() {
234+
@Override
235+
public void handleNativeException(Thread thread, Throwable throwable, Thread.UncaughtExceptionHandler originalHandler) {
236+
// Put your error handling code here
237+
}
238+
}//This will override the default behaviour of displaying the recover activity.
239+
}
240+
241+
```
242+
243+
**Modifying Android Native Exception handler UI (CUSTOM ACTIVITY APPROACH (OLD APPROACH).. LEAVING FOR BACKWARD COMPATIBILITY)**
244+
245+
(NATIVE CODE HAS TO BE WRITTEN) *recommended that you do this in android studio*
205246

206247
- Create an Empty Activity in the `android/app/src/main/java/[...]/`. For example lets say CustomErrorDialog.java
207248
- Customize your activity to look and behave however you need it to be.
@@ -431,6 +472,10 @@ This is specifically occuring when you use [wix library](http://wix.github.io/re
431472
setNativeExceptionHandler(nativeErrorCallback, false);
432473
```
433474

475+
### Previously defined exception handlers are not executed anymore
476+
477+
A lot of frameworks (especially analytics sdk's) implement global exception handlers. In order to keep these frameworks working while using react-native-exception-hanlder, you can pass a boolean value as third argument to `setNativeExceptionHandler(..., ..., true`) what will trigger the execution of the last global handler registered.
478+
434479

435480
## CONTRIBUTORS
436481
- [Atul R](https://github.com/master-atul)
@@ -447,6 +492,7 @@ setNativeExceptionHandler(nativeErrorCallback, false);
447492
- [TomMahle](https://github.com/TomMahle)
448493
- [Sébastien Krafft](https://github.com/skrafft)
449494
- [Mark Friedman](https://github.com/mark-friedman)
495+
- [Damien Solimando](https://github.com/dsolimando)
450496

451497
## TESTING NATIVE EXCEPTIONS/ERRORS
452498

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.masteratul.exceptionhandler;
2+
3+
public interface NativeExceptionHandlerIfc {
4+
void handleNativeException(Thread thread, Throwable throwable, Thread.UncaughtExceptionHandler originalHandler);
5+
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11

22
package com.masteratul.exceptionhandler;
3+
34
import android.app.Activity;
45
import android.content.Intent;
56
import android.util.Log;
67

8+
import com.facebook.react.bridge.Callback;
79
import com.facebook.react.bridge.ReactApplicationContext;
810
import com.facebook.react.bridge.ReactContextBaseJavaModule;
911
import com.facebook.react.bridge.ReactMethod;
10-
import com.facebook.react.bridge.Callback;
1112

1213
public class ReactNativeExceptionHandlerModule extends ReactContextBaseJavaModule {
1314

1415
private ReactApplicationContext reactContext;
1516
private Activity activity;
1617
private static Class errorIntentTargetClass = DefaultErrorScreen.class;
18+
private static NativeExceptionHandlerIfc nativeExceptionHandler;
1719
private Callback callbackHolder;
1820
private Thread.UncaughtExceptionHandler originalHandler;
1921

@@ -29,39 +31,52 @@ public String getName() {
2931

3032

3133
@ReactMethod
32-
public void setHandlerforNativeException(final boolean forceToQuit, Callback customHandler){
34+
public void setHandlerforNativeException(
35+
final boolean executeOriginalUncaughtExceptionHandler,
36+
final boolean forceToQuit,
37+
Callback customHandler) {
38+
3339
callbackHolder = customHandler;
3440
originalHandler = Thread.getDefaultUncaughtExceptionHandler();
3541

3642
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
43+
3744
@Override
3845
public void uncaughtException(Thread thread, Throwable throwable) {
46+
47+
String stackTraceString = Log.getStackTraceString(throwable);
48+
callbackHolder.invoke(stackTraceString);
49+
50+
if (nativeExceptionHandler != null) {
51+
nativeExceptionHandler.handleNativeException(thread, throwable, originalHandler);
52+
} else {
3953
activity = getCurrentActivity();
40-
String stackTraceString = Log.getStackTraceString(throwable);
41-
callbackHolder.invoke(stackTraceString);
42-
Log.d("ERROR",stackTraceString);
4354

44-
4555
Intent i = new Intent();
4656
i.setClass(activity, errorIntentTargetClass);
4757
i.putExtra("stack_trace_string",stackTraceString);
4858
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
49-
59+
5060
activity.startActivity(i);
5161
activity.finish();
5262

53-
if (originalHandler != null) {
63+
if (executeOriginalUncaughtExceptionHandler && originalHandler != null) {
5464
originalHandler.uncaughtException(thread, throwable);
5565
}
5666

5767
if (forceToQuit) {
58-
System.exit(0);
68+
System.exit(0);
5969
}
6070
}
71+
}
6172
});
6273
}
6374

6475
public static void replaceErrorScreenActivityClass(Class errorScreenActivityClass){
6576
errorIntentTargetClass = errorScreenActivityClass;
6677
}
78+
79+
public static void setNativeExceptionHandler(NativeExceptionHandlerIfc nativeExceptionHandler) {
80+
ReactNativeExceptionHandlerModule.nativeExceptionHandler = nativeExceptionHandler;
81+
}
6782
}

index.js

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,36 @@
1+
import { NativeModules, Platform } from "react-native";
12

2-
import {NativeModules, Platform} from 'react-native';
3+
const { ReactNativeExceptionHandler } = NativeModules;
34

4-
const {ReactNativeExceptionHandler} = NativeModules;
5-
6-
const noop = () => {};
5+
const noop = () => { };
76

87
export const setJSExceptionHandler = (customHandler = noop, allowedInDevMode = false) => {
9-
if ((typeof allowedInDevMode !== 'boolean') || (typeof customHandler !== 'function')) {
10-
console.log('setJSExceptionHandler is called with wrong argument types.. first argument should be callback function and second argument is optional should be a boolean');
11-
console.log('Not setting the JS handler .. please fix setJSExceptionHandler call');
8+
if (typeof allowedInDevMode !== "boolean" || typeof customHandler !== "function"){
9+
console.log("setJSExceptionHandler is called with wrong argument types.. first argument should be callback function and second argument is optional should be a boolean");
10+
console.log("Not setting the JS handler .. please fix setJSExceptionHandler call");
1211
return;
1312
}
1413
const allowed = allowedInDevMode ? true : !__DEV__;
1514
if (allowed) {
1615
global.ErrorUtils.setGlobalHandler(customHandler);
1716
console.error = (message, error) => global.ErrorUtils.reportError(error); // sending console.error so that it can be caught
1817
} else {
19-
console.log('Skipping setJSExceptionHandler: Reason: In DEV mode and allowedInDevMode = false');
18+
console.log("Skipping setJSExceptionHandler: Reason: In DEV mode and allowedInDevMode = false");
2019
}
2120
};
2221

2322
export const getJSExceptionHandler = () => global.ErrorUtils.getGlobalHandler();
2423

25-
export const setNativeExceptionHandler = (customErrorHandler = noop, forceApplicationToQuit = true) => {
26-
if ((typeof customErrorHandler !== 'function') || (typeof forceApplicationToQuit !== 'boolean')) {
27-
console.log('setNativeExceptionHandler is called with wrong argument types.. first argument should be callback function and second argument is optional should be a boolean');
28-
console.log('Not setting the native handler .. please fix setNativeExceptionHandler call');
24+
export const setNativeExceptionHandler = (customErrorHandler = noop, forceApplicationToQuit = true, executeDefaultHandler = false) => {
25+
if (typeof customErrorHandler !== "function" || typeof forceApplicationToQuit !== "boolean") {
26+
console.log("setNativeExceptionHandler is called with wrong argument types.. first argument should be callback function and second argument is optional should be a boolean");
27+
console.log("Not setting the native handler .. please fix setNativeExceptionHandler call");
2928
return;
3029
}
31-
if (Platform.OS === 'ios') {
32-
ReactNativeExceptionHandler.setHandlerforNativeException(customErrorHandler);
30+
if (Platform.OS === "ios") {
31+
ReactNativeExceptionHandler.setHandlerforNativeException(executeDefaultHandler, customErrorHandler);
3332
} else {
34-
ReactNativeExceptionHandler.setHandlerforNativeException(forceApplicationToQuit, customErrorHandler);
33+
ReactNativeExceptionHandler.setHandlerforNativeException(executeDefaultHandler, forceApplicationToQuit, customErrorHandler);
3534
}
3635
};
3736

0 commit comments

Comments
 (0)