15d8188f5SBen Roth// Copyright 2015-present 650 Industries. All rights reserved. 25d8188f5SBen Roth 35d8188f5SBen Roth#import "EXAppViewController.h" 45d8188f5SBen Roth#import "EXErrorRecoveryManager.h" 55d8188f5SBen Roth#import "EXKernel.h" 65d8188f5SBen Roth#import "EXKernelAppRecord.h" 75d8188f5SBen Roth#import "EXReactAppManager.h" 85d8188f5SBen Roth#import "EXReactAppExceptionHandler.h" 95d8188f5SBen Roth#import "EXUtil.h" 105d8188f5SBen Roth 115d8188f5SBen Roth#import <React/RCTBridge.h> 125d8188f5SBen Roth#import <React/RCTRedBox.h> 135d8188f5SBen Roth 145d8188f5SBen RothRCTFatalHandler handleFatalReactError = ^(NSError *error) { 155d8188f5SBen Roth [EXUtil performSynchronouslyOnMainThread:^{ 165d8188f5SBen Roth EXKernelAppRecord *record = [[EXKernel sharedInstance].serviceRegistry.errorRecoveryManager appRecordForError:error]; 175d8188f5SBen Roth if (!record) { 18e7ac6e4fSBen Roth // show the error on Home or on the main standalone app if we can't figure out who this error belongs to 19e7ac6e4fSBen Roth if ([EXKernel sharedInstance].appRegistry.homeAppRecord) { 205d8188f5SBen Roth record = [EXKernel sharedInstance].appRegistry.homeAppRecord; 21e7ac6e4fSBen Roth } else if ([EXKernel sharedInstance].appRegistry.standaloneAppRecord) { 22e7ac6e4fSBen Roth record = [EXKernel sharedInstance].appRegistry.standaloneAppRecord; 23e7ac6e4fSBen Roth } 245d8188f5SBen Roth } 255d8188f5SBen Roth if (record) { 265d8188f5SBen Roth [record.viewController maybeShowError:error]; 275d8188f5SBen Roth } 285d8188f5SBen Roth }]; 295d8188f5SBen Roth}; 305d8188f5SBen Roth 315d8188f5SBen RothNS_ASSUME_NONNULL_BEGIN 325d8188f5SBen Roth 335d8188f5SBen Roth@interface EXReactAppExceptionHandler () 345d8188f5SBen Roth 355d8188f5SBen Roth@property (nonatomic, weak) EXKernelAppRecord *appRecord; 365d8188f5SBen Roth 375d8188f5SBen Roth@end 385d8188f5SBen Roth 395d8188f5SBen Roth@implementation EXReactAppExceptionHandler 405d8188f5SBen Roth 415d8188f5SBen Roth- (instancetype)initWithAppRecord:(EXKernelAppRecord *)appRecord 425d8188f5SBen Roth{ 435d8188f5SBen Roth if (self = [super init]) { 445d8188f5SBen Roth _appRecord = appRecord; 455d8188f5SBen Roth } 465d8188f5SBen Roth return self; 475d8188f5SBen Roth} 485d8188f5SBen Roth 495d8188f5SBen RothRCT_NOT_IMPLEMENTED(- (instancetype)init) 505d8188f5SBen Roth 5171a1d7edSStanisław Chmiela- (void)handleSoftJSExceptionWithMessage:(nullable NSString *)message 5271a1d7edSStanisław Chmiela stack:(nullable NSArray<NSDictionary<NSString *, id> *> *)stack 535d8188f5SBen Roth exceptionId:(NSNumber *)exceptionId 54*529650a2SKudo Chien extraDataAsJSON:(nullable NSString *)extraDataAsJSON 555d8188f5SBen Roth{ 5696c67d7eSEvan Bacon // In RN 0.8 this was used to invoke the native red box errors (via `showErrorMessage`). 5796c67d7eSEvan Bacon // The invocation has since been moved into the method that invokes this delegate method. 5896c67d7eSEvan Bacon // https://github.com/facebook/react-native/commit/31b5b0ac010d44afe3e742e85c75a9ef9e72a9e0#diff-35e5d8a9e7e9ea80b2ccfd41b905b703 595d8188f5SBen Roth} 605d8188f5SBen Roth 6171a1d7edSStanisław Chmiela- (void)handleFatalJSExceptionWithMessage:(nullable NSString *)message 6271a1d7edSStanisław Chmiela stack:(nullable NSArray<NSDictionary<NSString *, id> *> *)stack 635d8188f5SBen Roth exceptionId:(NSNumber *)exceptionId 64*529650a2SKudo Chien extraDataAsJSON:(nullable NSString *)extraDataAsJSON 655d8188f5SBen Roth{ 665d8188f5SBen Roth NSString *description = [@"Unhandled JS Exception: " stringByAppendingString:message]; 675d8188f5SBen Roth NSDictionary *errorInfo = @{ NSLocalizedDescriptionKey: description, RCTJSStackTraceKey: stack }; 685d8188f5SBen Roth NSError *error = [NSError errorWithDomain:RCTErrorDomain code:0 userInfo:errorInfo]; 695d8188f5SBen Roth 70167fd314SWill Schurman [[EXKernel sharedInstance].serviceRegistry.errorRecoveryManager setError:error forScopeKey:_appRecord.scopeKey]; 715d8188f5SBen Roth 725d8188f5SBen Roth if ([self _isProdHome]) { 735d8188f5SBen Roth RCTFatal(error); 745d8188f5SBen Roth } 755d8188f5SBen Roth} 765d8188f5SBen Roth 7771a1d7edSStanisław Chmiela- (void)updateJSExceptionWithMessage:(nullable NSString *)message 7871a1d7edSStanisław Chmiela stack:(nullable NSArray *)stack 795d8188f5SBen Roth exceptionId:(NSNumber *)exceptionId 805d8188f5SBen Roth{ 815d8188f5SBen Roth [[self _bridgeForRecord].redBox updateErrorMessage:message withStack:stack]; 825d8188f5SBen Roth} 835d8188f5SBen Roth 845d8188f5SBen Roth#pragma mark - internal 855d8188f5SBen Roth 865d8188f5SBen Roth- (RCTBridge *)_bridgeForRecord 875d8188f5SBen Roth{ 885d8188f5SBen Roth return _appRecord.appManager.reactBridge; 895d8188f5SBen Roth} 905d8188f5SBen Roth 915d8188f5SBen Roth- (BOOL)_isProdHome 925d8188f5SBen Roth{ 935d8188f5SBen Roth if (RCT_DEBUG) { 945d8188f5SBen Roth return NO; 955d8188f5SBen Roth } 965d8188f5SBen Roth return (_appRecord && _appRecord == [EXKernel sharedInstance].appRegistry.homeAppRecord); 975d8188f5SBen Roth} 985d8188f5SBen Roth 995d8188f5SBen Roth@end 1005d8188f5SBen Roth 1015d8188f5SBen RothNS_ASSUME_NONNULL_END 102