RN捕获异常

来源:互联网 发布:xp映射网络驱动器 编辑:程序博客网 时间:2024/04/19 18:00

目的

思路

  1. alert 是否统一在rn中写,还是在原生中写?

  2. 拼接字符串 (系统+版本号+项目+info)

  3. 在信分期的项目中用现金贷的接口

android

init//getName()show()exit()//当UncaughtException发生时会转入该函数来处理uncaughtException()//自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.handleException()//收集设备参数信息collectDeviceInfo()//保存错误信息到文件中getCatchString()//testtestException()
CrashHandler.javapackage com.xfq.app;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.Promise;import com.facebook.react.bridge.LifecycleEventListener;import android.Manifest;import android.content.Context;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Build;import android.os.Environment;import android.os.Handler;import android.os.Looper;import android.widget.Toast;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.io.StringWriter;import java.io.Writer;import java.lang.Thread.UncaughtExceptionHandler;import java.lang.reflect.Field;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;public class CrashHandler extends ReactContextBaseJavaModule implements UncaughtExceptionHandler {    private Promise jsPromise;    // 系统默认的UncaughtException处理类    private UncaughtExceptionHandler mDefaultHandler = null;    // 程序的Context对象    private Context mContext = null;    // 用来存储设备信息和异常信息    private Map<String, String> infos = new HashMap<String, String>();    /**     * 初始化     */    public CrashHandler(ReactApplicationContext reactContext) {        super(reactContext);        mContext = reactContext;        // 获取系统默认的UncaughtException处理器        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();        // // 设置该CrashHandler为程序的默认处理器        Thread.setDefaultUncaughtExceptionHandler(this);    }    @Override    public String getName() {        return "UncaughtExceptionHandler";    }    @ReactMethod    public void show(Promise promise) {        this.jsPromise = promise;        testException();    }    @ReactMethod    public void exit() {        System.exit(0);        // ActivityManager.AppExit(mContext);    }    /**     * 当UncaughtException发生时会转入该函数来处理     */    @Override    public void uncaughtException(Thread thread, Throwable ex) {        if (!handleException(ex) && mDefaultHandler != null) {            // 如果用户没有处理则让系统默认的异常处理器来处理            mDefaultHandler.uncaughtException(thread, ex);        }    }    /**     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.     *      * @param ex     * @return true:如果处理了该异常信息;否则返回false.     */    private boolean handleException(final Throwable ex) {        if (ex == null) {            return false;        }        // 收集设备参数信息//        collectDeviceInfo(mContext);        this.jsPromise.resolve(getCatchString(ex));        return true;    }    /**     * 收集设备参数信息     *      * @param ctx     */    public void collectDeviceInfo(Context ctx) {        try {            PackageManager pm = ctx.getPackageManager();            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);            if (pi != null) {                String versionName = pi.versionName == null ? "null" : pi.versionName;                String versionCode = pi.versionCode + "";                infos.put("versionName", versionName);                infos.put("versionCode", versionCode);                infos.put("Build.VERSION.SDK_INT",Build.VERSION.SDK_INT+"");            }        } catch (Exception e) {        }        Field[] fields = Build.class.getDeclaredFields();        for (Field field : fields) {            try {                field.setAccessible(true);                infos.put(field.getName(), field.get(null).toString());//              LogUtil.d(TAG, field.getName() + " : " + field.get(null));            } catch (Exception e) {            }        }    }    /**     * 保存错误信息到文件中     *      * @param ex     * @return 返回文件名称,便于将文件传送到服务器     */    private String getCatchString(Throwable ex) {        StringBuffer sb = new StringBuffer();        for (Map.Entry<String, String> entry : infos.entrySet()) {            String key = entry.getKey();            String value = entry.getValue();            sb.append(key + "=" + value + "\n");        }        Writer writer = new StringWriter();        PrintWriter printWriter = new PrintWriter(writer);        ex.printStackTrace(printWriter);        Throwable cause = ex.getCause();        while (cause != null) {            cause.printStackTrace(printWriter);            cause = cause.getCause();        }        printWriter.close();        String result = writer.toString();        sb.append(result);        return sb.toString();    }    public void testException() {        new Thread(new Runnable()                   {            public void run()            {                try {                    Thread.currentThread().sleep(3000);//阻断3秒                } catch (InterruptedException e) {                    e.printStackTrace();                }                String msg = "";                System.out.println(msg.charAt(1));            }        }).start();    }}
CrashHandlerPackage.javapackage com.xfq.app;import com.facebook.react.ReactPackage;import com.facebook.react.bridge.JavaScriptModule;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Map;import java.util.Arrays;import java.util.List;import java.util.Collections;import java.util.ArrayList;public class CrashHandlerPackage implements ReactPackage {    @Override    public List<Class<? extends JavaScriptModule>> createJSModules() {        return Collections.emptyList();    }    @Override    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {        return Collections.emptyList();    }    @Override    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {        List<NativeModule> modules = new ArrayList<>();        modules.add(new CrashHandler(reactContext));        return modules;    }}

ios

.h////  UncaughtExceptionHandler.h//  XinfenqiApp////  Created by yyt on 2016/10/8.//  Copyright © 2016年 Facebook. All rights reserved.//#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import "RCTBridgeModule.h"@interface UncaughtExceptionHandler : NSObject <RCTBridgeModule>{  BOOL dismissed;}@property RCTPromiseResolveBlock resolve;@property RCTPromiseRejectBlock reject;@endvoid HandleException(NSException *exception);void SignalHandler(int signal);void InstallUncaughtExceptionHandler(void);
////  UncaughtExceptionHandler.m//  XinfenqiApp////  Created by yyt on 2016/10/8.//  Copyright © 2016年 Facebook. All rights reserved.//#import "UncaughtExceptionHandler.h"#include <libkern/OSAtomic.h>#include <execinfo.h>NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";volatile int32_t UncaughtExceptionCount = 0;const int32_t UncaughtExceptionMaximum = 10;const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;static UncaughtExceptionHandler *defaultHandler = nil;@implementation UncaughtExceptionHandlerRCT_EXPORT_MODULE();RCT_EXPORT_METHOD(show:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){  defaultHandler = self;  dispatch_sync(dispatch_get_main_queue(), ^(){    //    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];    //    self.resolve = resolve;//    self.reject = reject;    InstallUncaughtExceptionHandler();//    [self performSelector:@selector(ssss) withObject:nil afterDelay:5.0];  });}RCT_EXPORT_METHOD(exit){  exit(0);}+ (NSArray *)backtrace{  void* callstack[128];  int frames = backtrace(callstack, 128);  char **strs = backtrace_symbols(callstack, frames);  int i;  NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];  for (       i = UncaughtExceptionHandlerSkipAddressCount;       i < UncaughtExceptionHandlerSkipAddressCount +       UncaughtExceptionHandlerReportAddressCount;       i++)  {    [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];  }  free(strs);  return backtrace;}- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex{  if (anIndex == 0)  {    dismissed = YES;  }else if (anIndex==1) {    NSLog(@"ssssssss");  }}- (void)validateAndSaveCriticalApplicationData{}- (void)handleException:(NSException *)exception{  [self validateAndSaveCriticalApplicationData];  self.resolve([exception reason]);  /*  UIAlertView *alert =  [[UIAlertView alloc]    initWithTitle:NSLocalizedString(@"抱歉,程序出现了异常", nil)    message:[NSString stringWithFormat:NSLocalizedString(                                                         @"如果点击继续,程序有可能会出现其他的问题,建议您还是点击退出按钮并重新打开\n\n"                                                         @"异常原因如下:\n%@\n%@", nil),             [exception reason],             [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]    delegate:self    cancelButtonTitle:NSLocalizedString(@"退出", nil)    otherButtonTitles:NSLocalizedString(@"继续", nil), nil];  [alert show];   */  CFRunLoopRef runLoop = CFRunLoopGetCurrent();  CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);  while (!dismissed)  {    for (NSString *mode in (__bridge NSArray *)allModes)    {      CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);    }  }  CFRelease(allModes);  NSSetUncaughtExceptionHandler(NULL);  signal(SIGABRT, SIG_DFL);  signal(SIGILL, SIG_DFL);  signal(SIGSEGV, SIG_DFL);  signal(SIGFPE, SIG_DFL);  signal(SIGBUS, SIG_DFL);  signal(SIGPIPE, SIG_DFL);  if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])  {    kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);  }  else  {    [exception raise];  }}@endvoid HandleException(NSException *exception){  int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);  if (exceptionCount > UncaughtExceptionMaximum)  {    return;  }  NSArray *callStack = [UncaughtExceptionHandler backtrace];  NSMutableDictionary *userInfo =  [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];  [userInfo   setObject:callStack   forKey:UncaughtExceptionHandlerAddressesKey];  [defaultHandler   performSelectorOnMainThread:@selector(handleException:)   withObject:   [NSException    exceptionWithName:[exception name]    reason:[exception reason]    userInfo:userInfo]   waitUntilDone:YES];}void SignalHandler(int signal){  int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);  if (exceptionCount > UncaughtExceptionMaximum)  {    return;  }  NSMutableDictionary *userInfo =  [NSMutableDictionary   dictionaryWithObject:[NSNumber numberWithInt:signal]   forKey:UncaughtExceptionHandlerSignalKey];  NSArray *callStack = [UncaughtExceptionHandler backtrace];  [userInfo   setObject:callStack   forKey:UncaughtExceptionHandlerAddressesKey];  [defaultHandler   performSelectorOnMainThread:@selector(handleException:)   withObject:   [NSException    exceptionWithName:UncaughtExceptionHandlerSignalExceptionName    reason:    [NSString stringWithFormat:     NSLocalizedString(@"Signal %d was raised.", nil),     signal]    userInfo:    [NSDictionary     dictionaryWithObject:[NSNumber numberWithInt:signal]     forKey:UncaughtExceptionHandlerSignalKey]]   waitUntilDone:YES];}void InstallUncaughtExceptionHandler(void){  NSSetUncaughtExceptionHandler(&HandleException);  signal(SIGABRT, SignalHandler);  signal(SIGILL, SignalHandler);  signal(SIGSEGV, SignalHandler);  signal(SIGFPE, SignalHandler);  signal(SIGBUS, SignalHandler);  signal(SIGPIPE, SignalHandler);}

RN

如果是RN的代码错误,在alert之前,程序以及崩溃,alert无法调用显示。

异常之后,就再也调用不了原生模块了

const ErrorUtils = require('ErrorUtils');getCrash(){  var str = moment().format("YYYY-MM-DD HH:mm")+'|' + DeviceInfo.getBrand()+ DeviceInfo.getModel()+'|' + DeviceInfo.getSystemVersion()+'|' + DeviceInfo.getBundleId()+'|' + DeviceInfo.getVersion()+'|'  if (!__DEV__) {    ErrorUtils.setGlobalHandler(error => {      console.log("很抱歉error---",str + error);      this.showAlert()    })  }  NativeModules.UncaughtExceptionHandler.show()  .then(data => {    console.log('获取异常info',str + data)    this.showAlert()  })}
0 0