Add ability to customize error messages and stacks within the iOS redbox

Reviewed By: javache

Differential Revision: D3517605

fbshipit-source-id: a2efba80bbe1f6c74bf4e01f7807389962cb2463
This commit is contained in:
David Goldman 2016-07-18 11:27:55 -07:00 committed by Facebook Github Bot 0
parent 83336130ef
commit 9d2e6a2f8a
6 changed files with 124 additions and 1 deletions

View File

@ -0,0 +1,25 @@
/**
* 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 <Foundation/Foundation.h>
@class RCTErrorInfo;
/**
* Provides an interface to customize React Native error messages and stack
* traces from exceptions.
*/
@protocol RCTErrorCustomizer <NSObject>
/**
* Customizes the given error, returning the passed info argument if no
* customization is required.
*/
- (nonnull RCTErrorInfo *)customizeErrorInfo:(nonnull RCTErrorInfo *)info;
@end

25
React/Base/RCTErrorInfo.h Normal file
View File

@ -0,0 +1,25 @@
/**
* 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 <Foundation/Foundation.h>
@class RCTJSStackFrame;
/**
* An ObjC wrapper for React Native errors.
*/
@interface RCTErrorInfo : NSObject
@property (nonatomic, copy, readonly) NSString *errorMessage;
@property (nonatomic, copy, readonly) NSArray<RCTJSStackFrame *> *stack;
- (instancetype)initWithErrorMessage:(NSString *)errorMessage
stack:(NSArray<RCTJSStackFrame *> *)stack;
@end

26
React/Base/RCTErrorInfo.m Normal file
View File

@ -0,0 +1,26 @@
/**
* 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 "RCTErrorInfo.h"
#import "RCTJSStackFrame.h"
@implementation RCTErrorInfo
- (instancetype)initWithErrorMessage:(NSString *)errorMessage
stack:(NSArray<RCTJSStackFrame *> *)stack {
self = [super init];
if (self) {
_errorMessage = [errorMessage copy];
_stack = [stack copy];
}
return self;
}
@end

View File

@ -11,9 +11,11 @@
#import "RCTBridge.h"
#import "RCTBridgeModule.h"
#import "RCTErrorCustomizer.h"
@interface RCTRedBox : NSObject <RCTBridgeModule>
- (void)registerErrorCustomizer:(id<RCTErrorCustomizer>)errorCustomizer;
- (void)showError:(NSError *)error;
- (void)showErrorMessage:(NSString *)message;
- (void)showErrorMessage:(NSString *)message withDetails:(NSString *)details;

View File

@ -12,6 +12,7 @@
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTDefines.h"
#import "RCTErrorInfo.h"
#import "RCTUtils.h"
#import "RCTJSStackFrame.h"
@ -314,12 +315,42 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
@implementation RCTRedBox
{
RCTRedBoxWindow *_window;
NSMutableArray<id<RCTErrorCustomizer>> *_errorCustomizers;
}
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE()
- (void)registerErrorCustomizer:(id<RCTErrorCustomizer>)errorCustomizer
{
dispatch_async(dispatch_get_main_queue(), ^{
if (!self->_errorCustomizers) {
self->_errorCustomizers = [NSMutableArray array];
}
if (![self->_errorCustomizers containsObject:errorCustomizer]) {
[self->_errorCustomizers addObject:errorCustomizer];
}
});
}
// WARNING: Should only be called from the main thread/dispatch queue.
- (RCTErrorInfo *)_customizeError:(RCTErrorInfo *)error
{
RCTAssertMainQueue();
if (!self->_errorCustomizers) {
return error;
}
for (id<RCTErrorCustomizer> customizer in self->_errorCustomizers) {
RCTErrorInfo *newInfo = [customizer customizeErrorInfo:error];
if (newInfo) {
error = newInfo;
}
}
return error;
}
- (void)showError:(NSError *)error
{
[self showErrorMessage:error.localizedDescription withDetails:error.localizedFailureReason];
@ -367,7 +398,12 @@ RCT_EXPORT_MODULE()
self->_window = [[RCTRedBoxWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self->_window.actionDelegate = self;
}
[self->_window showErrorMessage:message withStack:stack isUpdate:isUpdate];
RCTErrorInfo *errorInfo = [[RCTErrorInfo alloc] initWithErrorMessage:message
stack:stack];
errorInfo = [self _customizeError:errorInfo];
[self->_window showErrorMessage:errorInfo.errorMessage
withStack:errorInfo.stack
isUpdate:isUpdate];
});
}
@ -422,6 +458,7 @@ RCT_EXPORT_METHOD(dismiss)
@implementation RCTRedBox
+ (NSString *)moduleName { return nil; }
- (void)registerErrorCustomizer:(id<RCTErrorCustomizer>)errorCustomizer {}
- (void)showError:(NSError *)message {}
- (void)showErrorMessage:(NSString *)message {}
- (void)showErrorMessage:(NSString *)message withDetails:(NSString *)details {}

View File

@ -80,6 +80,7 @@
352DCFF01D19F4C20056D623 /* RCTI18nUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 352DCFEF1D19F4C20056D623 /* RCTI18nUtil.m */; };
391E86A41C623EC800009732 /* RCTTouchEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 391E86A21C623EC800009732 /* RCTTouchEvent.m */; };
3D1E68DB1CABD13900DD7465 /* RCTDisplayLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1E68D91CABD13900DD7465 /* RCTDisplayLink.m */; };
3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; };
58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@ -274,6 +275,9 @@
3D1E68D91CABD13900DD7465 /* RCTDisplayLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDisplayLink.m; sourceTree = "<group>"; };
3DB910701C74B21600838BBE /* RCTWebSocketProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketProxy.h; sourceTree = "<group>"; };
3DB910711C74B21600838BBE /* RCTWebSocketProxyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketProxyDelegate.h; sourceTree = "<group>"; };
3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorCustomizer.h; sourceTree = "<group>"; };
3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = "<group>"; };
3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = "<group>"; };
58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@ -554,6 +558,9 @@
83CBBA491A601E3B00E9B192 /* Base */ = {
isa = PBXGroup;
children = (
3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */,
3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */,
3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */,
68EFE4ED1CF6EB3900A1DE13 /* RCTBundleURLProvider.m */,
68EFE4EC1CF6EB3000A1DE13 /* RCTBundleURLProvider.h */,
83CBBA4A1A601E3B00E9B192 /* RCTAssert.h */,
@ -755,6 +762,7 @@
14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */,
142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */,
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */,
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */,