React native error handling (#350)

* added react native error handler package
* implement Mixpanel error tracking
This commit is contained in:
Akinwale Ariwodola 2018-11-01 05:31:38 +01:00 committed by GitHub
parent b76498852e
commit c9c0249d4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 7 deletions

5
app/package-lock.json generated
View file

@ -5272,6 +5272,11 @@
"react-native-drawer-layout": "1.3.2" "react-native-drawer-layout": "1.3.2"
} }
}, },
"react-native-exception-handler": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.9.0.tgz",
"integrity": "sha512-XRHhGH5aM4lSenX4zZBa07JaszJGXeF8cv1KY314Q4qJWOihKWLpkdvwqwsBieZ2iy8DPhdAVioQzw8JLD/Okw=="
},
"react-native-fast-image": { "react-native-fast-image": {
"version": "5.0.3", "version": "5.0.3",
"resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.0.3.tgz", "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.0.3.tgz",

View file

@ -13,6 +13,7 @@
"react": "16.2.0", "react": "16.2.0",
"react-native": "0.55.3", "react-native": "0.55.3",
"react-native-country-picker-modal": "^0.6.2", "react-native-country-picker-modal": "^0.6.2",
"react-native-exception-handler": "2.9.0",
"react-native-fast-image": "^5.0.3", "react-native-fast-image": "^5.0.3",
"react-native-fetch-blob": "^0.10.8", "react-native-fetch-blob": "^0.10.8",
"react-native-image-zoom-viewer": "^2.2.5", "react-native-image-zoom-viewer": "^2.2.5",

View file

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { setJSExceptionHandler } from 'react-native-exception-handler';
import { Provider, connect } from 'react-redux'; import { Provider, connect } from 'react-redux';
import { import {
AppRegistry, AppRegistry,
@ -31,6 +32,14 @@ import moment from 'moment';
import settingsReducer from './redux/reducers/settings'; import settingsReducer from './redux/reducers/settings';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
const globalExceptionHandler = (error, isFatal) => {
if (error && NativeModules.Mixpanel) {
NativeModules.Mixpanel.logException(isFatal, error.message ? error.message : "No message", error);
}
};
setJSExceptionHandler(globalExceptionHandler, true);
function isFunction(object) { function isFunction(object) {
return typeof object === 'function'; return typeof object === 'function';
} }

View file

@ -72,6 +72,13 @@ android {
} }
} }
ext {
compileSdkVersion = {{ android_api }}
buildToolsVersion = '{{ build_tools_version }}'
minSdkVersion = {{ args.min_sdk_version }}
targetSdkVersion = {{ android_api }}
}
subprojects { subprojects {
afterEvaluate {project -> afterEvaluate {project ->
if (project.hasProperty("android")) { if (project.hasProperty("android")) {
@ -84,6 +91,7 @@ subprojects {
} }
dependencies { dependencies {
compile project(':react-native-exception-handler')
compile project(':react-native-fast-image') compile project(':react-native-fast-image')
compile project(':react-native-fetch-blob') compile project(':react-native-fetch-blob')
compile project(':react-native-video') compile project(':react-native-video')

View file

@ -1,4 +1,6 @@
rootProject.name = 'browser' rootProject.name = 'browser'
include ':react-native-exception-handler'
project(':react-native-exception-handler').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-exception-handler/android')
include ':react-native-fast-image' include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-fast-image/android') project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, './react/node_modules/react-native-fast-image/android')
include ':react-native-fetch-blob' include ':react-native-fetch-blob'

View file

@ -9,11 +9,10 @@ class PyjniusRecipe(CythonRecipe):
version = '1.1.3' version = '1.1.3'
url = 'https://github.com/kivy/pyjnius/archive/{version}.zip' url = 'https://github.com/kivy/pyjnius/archive/{version}.zip'
name = 'pyjnius' name = 'pyjnius'
depends = [('python2', 'python3crystax'), ('genericndkbuild', 'sdl2', 'sdl'), 'six'] depends = [('python2', 'python3crystax'), 'genericndkbuild', 'six']
site_packages_name = 'jnius' site_packages_name = 'jnius'
patches = [('sdl2_jnienv_getter.patch', will_build('sdl2')), patches = [('genericndkbuild_jnienv_getter.patch', will_build('genericndkbuild'))]
('genericndkbuild_jnienv_getter.patch', will_build('genericndkbuild'))]
def postbuild_arch(self, arch): def postbuild_arch(self, arch):
super(PyjniusRecipe, self).postbuild_arch(arch) super(PyjniusRecipe, self).postbuild_arch(arch)

View file

@ -1,6 +1,7 @@
package io.lbry.browser.reactmodules; package io.lbry.browser.reactmodules;
import android.content.Context; import android.content.Context;
import android.widget.Toast;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactContextBaseJavaModule;
@ -23,7 +24,7 @@ public class MixpanelModule extends ReactContextBaseJavaModule {
"93b81fb957cb0ddcd3198c10853a6a95"; /* Production */ "93b81fb957cb0ddcd3198c10853a6a95"; /* Production */
private Context context; private Context context;
private MixpanelAPI mixpanel; private MixpanelAPI mixpanel;
public MixpanelModule(ReactApplicationContext reactContext) { public MixpanelModule(ReactApplicationContext reactContext) {
@ -36,7 +37,7 @@ public class MixpanelModule extends ReactContextBaseJavaModule {
public String getName() { public String getName() {
return "Mixpanel"; return "Mixpanel";
} }
@ReactMethod @ReactMethod
public void track(String name, ReadableMap payload) { public void track(String name, ReadableMap payload) {
JSONObject props = new JSONObject(); JSONObject props = new JSONObject();
@ -48,11 +49,39 @@ public class MixpanelModule extends ReactContextBaseJavaModule {
} }
} }
} catch (JSONException e) { } catch (JSONException e) {
// Cannot use props. Stick with empty props. // Cannot use props. Stick with empty props.
} }
if (mixpanel != null) { if (mixpanel != null) {
mixpanel.track(name, props); mixpanel.track(name, props);
} }
} }
@ReactMethod
public void logException(boolean fatal, String message, ReadableMap payload) {
JSONObject props = new JSONObject();
try {
props.put("Message", message);
if (payload != null) {
HashMap<String, Object> payloadMap = payload.toHashMap();
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
props.put(entry.getKey(), entry.getValue());
}
}
} catch (JSONException e) {
// Cannot use props. Stick with empty props.
}
if (mixpanel != null) {
mixpanel.track(fatal ? "Exception" : "Warning", props);
}
if (fatal) {
Toast.makeText(context,
"An application error occurred which has been automatically logged. " +
"If you keep seeing this message, please provide feedback to the LBRY " +
"team by emailing hello@lbry.io.",
Toast.LENGTH_LONG).show();
}
}
} }