美文网首页工作生活
如何采集RN的js异常并上报

如何采集RN的js异常并上报

作者: jayhe | 来源:发表于2019-07-01 16:55 被阅读0次
  • React-Native内部已经实现了一套异常处理的流程,fetal和soft的error都会将堆栈信息回调回来
  • 我们可以通过hook RN的异常处理的方法,在其中加入自己的业务逻辑,比如:上报异常堆栈信息到服务器或者bugly

RN的异常处理

RN的异常处理主要是RCTAssert和RCTExceptionsManager处理的

RCTAssert

其中assert的fetal error处理,暴露了回调函数,我们设置成自己的函数即可

RCTSetFatalHandler(^(NSError *error) {
            YourRCTFatal(error);
        });
void YourRCTFatal(NSError *error) {
    // 搞些事情,比如上报bugly
}

RCTExceptionsManager

1. 异常处理管理类

提供了回调fetal和soft的异常的堆栈信息的方法;同时也提供代理去实现处理这些异常的方法

@protocol RCTExceptionsManagerDelegate <NSObject>

- (void)handleSoftJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;
- (void)handleFatalJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;

@optional
- (void)updateJSExceptionWithMessage:(nullable NSString *)message stack:(nullable NSArray *)stack exceptionId:(NSNumber *)exceptionId;

@end

@interface RCTExceptionsManager : NSObject <RCTBridgeModule>

- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate;

- (void)reportSoftException:(nullable NSString *)message stack:(nullable NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
- (void)reportFatalException:(nullable NSString *)message stack:(nullable NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;

@property (nonatomic, weak) id<RCTExceptionsManagerDelegate> delegate;

@property (nonatomic, assign) NSUInteger maxReloadAttempts;

@end

在bridge load的时候会new一个RCTExceptionsManager的实例,默认是没有设置delegate的,那么就走的是默认的异常处理的流程;

- (instancetype)initWithModuleClass:(Class)moduleClass
                             bridge:(RCTBridge *)bridge
{
  return [self initWithModuleClass:moduleClass
                    moduleProvider:^id<RCTBridgeModule>{ return [moduleClass new]; }
                            bridge:bridge];
}

2. 在异常处理中加入自己的业务逻辑,同时又不修改源代码
实现方式有2种

  • 实现一个类,遵从RCTExceptionsManagerDelegate代理,在代理内部处理自己的业务
  • hook的方式,hook reportSoftExceptionreportFatalException

3. 代理的方式
实现RCTExceptionsManager的类别,在类别中等待类的实例实例化之后,设置delegate为我们定义的遵循RCTExceptionsManagerDelegate协议的实例


@implementation RCTExceptionsManager (Extension)
- (void)batchDidComplete {
//    self.delegate = xxx
}

4. hook的方式

hook的灵活度比代理的方式要高,你可以插入代码逻辑也可以直接替换原实现

@implementation RCTExceptionsManager (CassExtension)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self aspect_hookSelector:@selector(init) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo) {
            [aspectInfo.instance hookMethods];
        } error:nil];
    });
}

- (void)hookMethods {
    // hook reportSoftException
    __weak typeof(self) weakSelf = self;
    [self aspect_hookSelector:@selector(reportSoftException:stack:exceptionId:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo>aspectInfo) {
        [weakSelf mine_reportSoftException:[aspectInfo.arguments safeObjectAtIndex:0]
                                     stack:[aspectInfo.arguments safeObjectAtIndex:1]
                               exceptionId:[aspectInfo.arguments safeObjectAtIndex:2]];
    } error:nil];
}

- (void)mine_reportSoftException:(nullable NSString *)message stack:(nullable NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId {
    [self.bridge.redBox showErrorMessage:message withStack:stack];
    
    if (self.delegate) {
        [self.delegate handleSoftJSExceptionWithMessage:message stack:stack exceptionId:exceptionId];
    }
    NSString *description = [@"Unhandled JS SoftException: " stringByAppendingString:message];
    NSDictionary *errorInfo = @{ NSLocalizedDescriptionKey: description, RCTJSStackTraceKey: stack };
    NSError *error = [NSError errorWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
    // 搞些事情,比如上报bugly
}
@end

RN js异常解析

异常上报之后,就能拿到报错的堆栈信息,我们需要结合sourcemap去解析到具体的js源码的位置

解析可以看这篇文章
通过SourceMap解析RN中的js异常

相关文章

网友评论

    本文标题:如何采集RN的js异常并上报

    本文链接:https://www.haomeiwen.com/subject/rohncctx.html