react-native/React/Modules/RCTExceptionsManager.m
Spencer Ahrens 68bb3a7e71 [ReactNative] orange box
Summary:
@public

There have been multiple instances of confusion about whether a redbox means the
developer did something they shouldn't but things will keep working, or if
something went horribly wrong and the app will crash in prod.  This diff
introduces an orange background color to the redbox for `console.error` and
`RCTLogError` to indicate that something bad happened, but that the app will
continue working.

Test Plan:
see orange error for geo permissions:

{F22541375}
2015-06-09 14:53:29 -08:00

108 lines
2.9 KiB
Objective-C

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTExceptionsManager.h"
#import "RCTDefines.h"
#import "RCTLog.h"
#import "RCTRedBox.h"
#import "RCTRootView.h"
@implementation RCTExceptionsManager
{
__weak id<RCTExceptionsManagerDelegate> _delegate;
NSUInteger _reloadRetries;
}
RCT_EXPORT_MODULE()
- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
{
if ((self = [super init])) {
_delegate = delegate;
_maxReloadAttempts = 0;
}
return self;
}
- (instancetype)init
{
return [self initWithDelegate:nil];
}
RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
stack:(NSArray *)stack)
{
// TODO(#7070533): report a soft error to the server
if (_delegate) {
[_delegate handleSoftJSExceptionWithMessage:message stack:stack];
return;
}
RCTRedBox *box = [RCTRedBox sharedInstance];
[box setNextBackgroundColor:[UIColor colorWithRed:0.9 green:0.4 blue:0.2 alpha:1]];
[box showErrorMessage:message withStack:stack];
}
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
stack:(NSArray *)stack)
{
if (_delegate) {
[_delegate handleFatalJSExceptionWithMessage:message stack:stack];
return;
}
[[RCTRedBox sharedInstance] showErrorMessage:message withStack:stack];
if (!RCT_DEBUG) {
static NSUInteger reloadRetries = 0;
const NSUInteger maxMessageLength = 75;
if (reloadRetries < _maxReloadAttempts) {
reloadRetries++;
[[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification
object:nil];
} else {
if (message.length > maxMessageLength) {
message = [[message substringToIndex:maxMessageLength] stringByAppendingString:@"..."];
}
NSMutableString *prettyStack = [NSMutableString stringWithString:@"\n"];
for (NSDictionary *frame in stack) {
[prettyStack appendFormat:@"%@@%@:%@\n", frame[@"methodName"], frame[@"lineNumber"], frame[@"column"]];
}
NSString *name = [@"Unhandled JS Exception: " stringByAppendingString:message];
[NSException raise:name format:@"Message: %@, stack: %@", message, prettyStack];
}
}
}
RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
stack:(NSArray *)stack)
{
if (_delegate) {
[_delegate updateJSExceptionWithMessage:message stack:stack];
return;
}
[[RCTRedBox sharedInstance] updateErrorMessage:message withStack:stack];
}
// Deprecated. Use reportFatalException directly instead.
RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
stack:(NSArray *)stack)
{
[self reportFatalException:message stack:stack];
}
@end