├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── android ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── richardcao │ │ └── exceptionsmanager │ │ └── react │ │ ├── ExceptionsManager.java │ │ └── ExceptionsManagerModule.java ├── build.gradle ├── gradle.properties └── settings.gradle └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # node.js 25 | # 26 | node_modules/ 27 | npm-debug.log 28 | 29 | # Built application files 30 | *.apk 31 | *.ap_ 32 | 33 | # Files for the ART/Dalvik VM 34 | *.dex 35 | 36 | # Java class files 37 | *.class 38 | 39 | # Generated files 40 | bin/ 41 | gen/ 42 | out/ 43 | 44 | # Gradle files 45 | .gradle/ 46 | *.build/ 47 | 48 | # Local configuration file (sdk path, etc) 49 | local.properties 50 | 51 | # Log Files 52 | *.log 53 | 54 | # Intellij 55 | *.iml 56 | android/.idea/ 57 | android/gradle 58 | android/gradlew* 59 | android/app/local.properties 60 | android/app/build 61 | android/app/captures 62 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # node.js 25 | # 26 | node_modules/ 27 | npm-debug.log 28 | 29 | # Built application files 30 | *.apk 31 | *.ap_ 32 | 33 | # Files for the ART/Dalvik VM 34 | *.dex 35 | 36 | # Java class files 37 | *.class 38 | 39 | # Generated files 40 | bin/ 41 | gen/ 42 | out/ 43 | 44 | # Gradle files 45 | .gradle/ 46 | *.build/ 47 | 48 | # Local configuration file (sdk path, etc) 49 | local.properties 50 | 51 | # Log Files 52 | *.log 53 | 54 | # Intellij 55 | *.iml 56 | android/.idea/ 57 | android/gradle 58 | android/gradlew* 59 | android/app/local.properties 60 | android/app/build 61 | android/app/captures 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Richard-Cao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-exceptions-manager 2 | 3 | [![GitHub license][license-image]][license-url] 4 | [![NPM version][npm-image]][npm-url] 5 | [![Dependency Status][david-image]][david-url] 6 | [![Downloads][downloads-image]][npm-url] 7 | 8 | React-Native Crash Reporter In Release Version(**Do not trigger native crash**). 9 | 10 | # Linking 11 | 12 | ## Android 13 | 14 | - Add following lines into ```android/settings.gradle``` 15 | 16 | ``` 17 | include ':react-native-exceptions-manager' 18 | project(':react-native-exceptions-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-exceptions-manager/android/app') 19 | ``` 20 | 21 | - Add following lines into your ```android/app/build.gradle``` in section ```dependencies``` 22 | 23 | ``` 24 | compile project(':react-native-exceptions-manager') 25 | ``` 26 | 27 | - Add following lines into ```MainApplication.java``` 28 | 29 | ``` 30 | import com.richardcao.exceptionsmanager.react.ExceptionsManager; 31 | ... 32 | 33 | @Override 34 | protected List getPackages() { 35 | List packages = Arrays.asList( 36 | new MainReactPackage(), 37 | ...); 38 | ArrayList packageList = new ArrayList<>(packages); 39 | if (!BuildConfig.DEBUG) { 40 | packageList.add(new ExceptionsManager()); 41 | } 42 | return packageList; 43 | } 44 | ``` 45 | 46 | - Create a class named ```ReactNativeJSCrashReceiver``` in it. This is needed to get js crash message from `react-native-exceptions-manager`. 47 | 48 | ``` 49 | public class ReactNativeJSCrashReceiver extends BroadcastReceiver { 50 | @Override 51 | public void onReceive(Context context, Intent intent) { 52 | if (intent.getAction().equals("com.richardcao.android.REACT_NATIVE_CRASH_REPORT_ACTION")) { 53 | Throwable js = (Throwable) intent.getSerializableExtra("JavascriptException"); 54 | ...(handler or report js crash operate) 55 | Throwable e = (Throwable) intent.getSerializableExtra("Exception"); 56 | ...(handler or report native crash operate) 57 | } 58 | } 59 | } 60 | ``` 61 | 62 | - Add ```ReactNativeJSCrashReceiver``` declare in your ```AndroidManifest.xml``` 63 | 64 | ``` 65 | 69 | ... 70 | 71 | 72 | 73 | 74 | 75 | 76 | ``` 77 | 78 | ## iOS 79 | 80 | *//TODO* 81 | 82 | ## Who Use It 83 | - [reading: iReading App Write In React-Native][reading-url] 84 | 85 | 86 | ### MIT Licensed 87 | 88 | 89 | [license-image]: https://img.shields.io/badge/license-MIT-blue.svg 90 | [license-url]: https://raw.githubusercontent.com/Richard-Cao/react-native-exceptions-manager/master/LICENSE 91 | [npm-image]: https://img.shields.io/npm/v/react-native-exceptions-manager.svg?style=flat-square 92 | [npm-url]: https://npmjs.org/package/react-native-exceptions-manager 93 | [david-image]: http://img.shields.io/david/Richard-Cao/react-native-exceptions-manager.svg?style=flat-square 94 | [david-url]: https://david-dm.org/Richard-Cao/react-native-exceptions-manager 95 | [downloads-image]: http://img.shields.io/npm/dm/react-native-exceptions-manager.svg?style=flat-square 96 | [reading-url]: https://github.com/attentiveness/reading 97 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | ndk { 13 | abiFilters "armeabi-v7a", "x86" 14 | } 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile "com.facebook.react:react-native:+" 26 | } 27 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/richardcao/developer/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/richardcao/exceptionsmanager/react/ExceptionsManager.java: -------------------------------------------------------------------------------- 1 | package com.richardcao.exceptionsmanager.react; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by caolicheng on 2016/9/29. 15 | */ 16 | 17 | public class ExceptionsManager implements ReactPackage { 18 | 19 | @Override 20 | public List createNativeModules(ReactApplicationContext reactContext) { 21 | return Arrays.asList(new NativeModule[]{ 22 | // Modules from third-party 23 | new ExceptionsManagerModule(reactContext), 24 | }); 25 | } 26 | 27 | // Deprecated RN 0.47 28 | public List> createJSModules() { 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public List createViewManagers(ReactApplicationContext reactContext) { 34 | return Collections.emptyList(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/richardcao/exceptionsmanager/react/ExceptionsManagerModule.java: -------------------------------------------------------------------------------- 1 | package com.richardcao.exceptionsmanager.react; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import com.facebook.common.logging.FLog; 7 | import com.facebook.react.bridge.NativeModuleCallExceptionHandler; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 10 | import com.facebook.react.bridge.ReactMethod; 11 | import com.facebook.react.bridge.ReadableArray; 12 | import com.facebook.react.bridge.ReadableMap; 13 | import com.facebook.react.bridge.ReadableType; 14 | import com.facebook.react.common.ReactConstants; 15 | 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | /** 20 | * Created by caolicheng on 2016/9/29. 21 | */ 22 | 23 | public class ExceptionsManagerModule extends ReactContextBaseJavaModule { 24 | 25 | private final Context context; 26 | static private final Pattern mJsModuleIdPattern = Pattern.compile("(?:^|[/\\\\])(\\d+\\.js)$"); 27 | 28 | public ExceptionsManagerModule(ReactApplicationContext reactContext) { 29 | super(reactContext); 30 | this.context = reactContext; 31 | 32 | reactContext.setNativeModuleCallExceptionHandler(new NativeModuleCallExceptionHandler() { 33 | @Override 34 | public void handleException(Exception e) { 35 | Intent intent = new Intent(); 36 | intent.setAction("com.richardcao.android.REACT_NATIVE_CRASH_REPORT_ACTION"); 37 | intent.putExtra("Exception", e); 38 | context.sendBroadcast(intent); 39 | } 40 | }); 41 | } 42 | 43 | @Override 44 | public String getName() { 45 | return "RKExceptionsManager"; 46 | } 47 | 48 | @Override 49 | public boolean canOverrideExistingModule() { 50 | return true; 51 | } 52 | 53 | // If the file name of a stack frame is numeric (+ ".js"), we assume it's a lazily injected module 54 | // coming from a "random access bundle". We are using special source maps for these bundles, so 55 | // that we can symbolicate stack traces for multiple injected files with a single source map. 56 | // We have to include the module id in the stack for that, though. The ".js" suffix is kept to 57 | // avoid ambiguities between "module-id:line" and "line:column". 58 | static private String stackFrameToModuleId(ReadableMap frame) { 59 | if (frame.hasKey("file") && 60 | !frame.isNull("file") && 61 | frame.getType("file") == ReadableType.String) { 62 | final Matcher matcher = mJsModuleIdPattern.matcher(frame.getString("file")); 63 | if (matcher.find()) { 64 | return matcher.group(1) + ":"; 65 | } 66 | } 67 | return ""; 68 | } 69 | 70 | private String stackTraceToString(String message, ReadableArray stack) { 71 | StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n"); 72 | for (int i = 0; i < stack.size(); i++) { 73 | ReadableMap frame = stack.getMap(i); 74 | stringBuilder 75 | .append(frame.getString("methodName")) 76 | .append("@") 77 | .append(stackFrameToModuleId(frame)) 78 | .append(frame.getInt("lineNumber")); 79 | if (frame.hasKey("column") && 80 | !frame.isNull("column") && 81 | frame.getType("column") == ReadableType.Number) { 82 | stringBuilder 83 | .append(":") 84 | .append(frame.getInt("column")); 85 | } 86 | stringBuilder.append("\n"); 87 | } 88 | return stringBuilder.toString(); 89 | } 90 | 91 | @ReactMethod 92 | public void reportFatalException(String title, ReadableArray details, int exceptionId) { 93 | showOrThrowError(title, details, exceptionId); 94 | } 95 | 96 | private void showOrThrowError(String title, ReadableArray details, int exceptionId) { 97 | Intent intent = new Intent(); 98 | intent.setAction("com.richardcao.android.REACT_NATIVE_CRASH_REPORT_ACTION"); 99 | intent.putExtra("JavascriptException", new RuntimeException(stackTraceToString(title, details))); 100 | context.sendBroadcast(intent); 101 | } 102 | 103 | @ReactMethod 104 | public void reportSoftException(String title, ReadableArray details, int exceptionId) { 105 | FLog.e(ReactConstants.TAG, stackTraceToString(title, details)); 106 | } 107 | 108 | @ReactMethod 109 | public void updateExceptionMessage(String title, ReadableArray details, int exceptionId) { 110 | 111 | } 112 | 113 | @ReactMethod 114 | public void dismissRedbox() { 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-exceptions-manager", 3 | "version": "0.2.0", 4 | "description": "React-Native Crash Reporter(Do not trigger native crash).", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+ssh://git@github.com/Richard-Cao/react-native-exceptions-manager.git" 8 | }, 9 | "keywords": [ 10 | "crash", 11 | "react", 12 | "react-native", 13 | "exception" 14 | ], 15 | "peerDependencies": { 16 | "react-native": ">=0.33" 17 | }, 18 | "author": "Richard Cao ", 19 | "contributors": [ 20 | { 21 | "name": "Richard Cao", 22 | "email": "caolicheng921104@gmail.com" 23 | } 24 | ], 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/Richard-Cao/react-native-exceptions-manager/issues" 28 | }, 29 | "homepage": "https://github.com/Richard-Cao/react-native-exceptions-manager#readme" 30 | } 31 | --------------------------------------------------------------------------------