Skip to content

Commit

Permalink
Attach js_extra_data to JS errors on iOS
Browse files Browse the repository at this point in the history
Summary:
Changelog:
[iOS][Fixed] - Expose the extraData dict attached to JavaScript errors to the native ExceptionManager on iOS, similar to Android

Attaching the `extraData` dict to JavaScript crash reports is something that was done for Android only in 2019 (D16133080 (facebook@3a825c0)), and somehow we never really got around to adding it in iOS. This diff finally adds the capability to iOS as well. `extraData` can be used to attach various bits of data to a crash report for better debugging and categorization. As with the Android implementation, `extraData` is not attached if the `reportException` API is not used.

Reviewed By: dmitryrykun

Differential Revision: D35743658

fbshipit-source-id: de4060cb6e514db1d85907441a8962f98e9b8392
  • Loading branch information
GijsWeterings authored and facebook-github-bot committed Apr 25, 2022
1 parent 4f855c8 commit a65ae8e
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 11 deletions.
5 changes: 5 additions & 0 deletions React/Base/RCTAssert.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ RCT_EXTERN NSString *const RCTObjCStackTraceKey;
*/
RCT_EXTERN NSString *const RCTFatalExceptionName;

/**
* Stringified JSON object containing extra data to attach to the error from JavaScript.
*/
RCT_EXTERN NSString *const RCTJSExtraDataKey;

/**
* A block signature to be used for custom assertion handling.
*/
Expand Down
1 change: 1 addition & 0 deletions React/Base/RCTAssert.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
NSString *const RCTObjCStackTraceKey = @"RCTObjCStackTraceKey";
NSString *const RCTFatalExceptionName = @"RCTFatalException";
NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey";
NSString *const RCTJSExtraDataKey = @"RCTJSExtraDataKey";

static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack";

Expand Down
6 changes: 4 additions & 2 deletions React/CoreModules/RCTExceptionsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ NS_ASSUME_NONNULL_BEGIN

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

@optional
- (void)updateJSExceptionWithMessage:(nullable NSString *)message
Expand Down
30 changes: 21 additions & 9 deletions React/CoreModules/RCTExceptionsManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,35 @@ - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
return self;
}

- (void)reportSoft:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(double)exceptionId
- (void)reportSoft:(NSString *)message
stack:(NSArray<NSDictionary *> *)stack
exceptionId:(double)exceptionId
extraDataAsJSON:(nullable NSString *)extraDataAsJSON
{
RCTRedBox *redbox = [_moduleRegistry moduleForName:"RedBox"];
[redbox showErrorMessage:message withStack:stack errorCookie:(int)exceptionId];

if (_delegate) {
[_delegate handleSoftJSExceptionWithMessage:message
stack:stack
exceptionId:[NSNumber numberWithDouble:exceptionId]];
exceptionId:[NSNumber numberWithDouble:exceptionId]
extraDataAsJSON:extraDataAsJSON];
}
}

- (void)reportFatal:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(double)exceptionId
- (void)reportFatal:(NSString *)message
stack:(NSArray<NSDictionary *> *)stack
exceptionId:(double)exceptionId
extraDataAsJSON:(nullable NSString *)extraDataAsJSON
{
RCTRedBox *redbox = [_moduleRegistry moduleForName:"RedBox"];
[redbox showErrorMessage:message withStack:stack errorCookie:(int)exceptionId];

if (_delegate) {
[_delegate handleFatalJSExceptionWithMessage:message
stack:stack
exceptionId:[NSNumber numberWithDouble:exceptionId]];
exceptionId:[NSNumber numberWithDouble:exceptionId]
extraDataAsJSON:extraDataAsJSON];
}

static NSUInteger reloadRetries = 0;
Expand All @@ -64,7 +72,8 @@ - (void)reportFatal:(NSString *)message stack:(NSArray<NSDictionary *> *)stack e
RCTTriggerReloadCommandListeners(@"JS Crash Reload");
} else if (!RCT_DEV) {
NSString *description = [@"Unhandled JS Exception: " stringByAppendingString:message];
NSDictionary *errorInfo = @{NSLocalizedDescriptionKey : description, RCTJSStackTraceKey : stack};
NSDictionary *errorInfo =
@{NSLocalizedDescriptionKey : description, RCTJSStackTraceKey : stack, RCTJSExtraDataKey : extraDataAsJSON};
RCTFatal([NSError errorWithDomain:RCTErrorDomain code:0 userInfo:errorInfo]);
}
}
Expand All @@ -74,15 +83,15 @@ - (void)reportFatal:(NSString *)message stack:(NSArray<NSDictionary *> *)stack e
: (NSArray<NSDictionary *> *)stack exceptionId
: (double)exceptionId)
{
[self reportSoft:message stack:stack exceptionId:exceptionId];
[self reportSoft:message stack:stack exceptionId:exceptionId extraDataAsJSON:nil];
}

RCT_EXPORT_METHOD(reportFatalException
: (NSString *)message stack
: (NSArray<NSDictionary *> *)stack exceptionId
: (double)exceptionId)
{
[self reportFatal:message stack:stack exceptionId:exceptionId];
[self reportFatal:message stack:stack exceptionId:exceptionId extraDataAsJSON:nil];
}

RCT_EXPORT_METHOD(updateExceptionMessage
Expand Down Expand Up @@ -131,10 +140,13 @@ - (void)reportFatal:(NSString *)message stack:(NSArray<NSDictionary *> *)stack e
[stackArray addObject:frameDict];
}

NSDictionary *extraData = (NSDictionary *)data.extraData();
NSString *extraDataAsJSON = RCTJSONStringify(extraData, NULL);

if (data.isFatal()) {
[self reportFatal:message stack:stackArray exceptionId:exceptionId];
[self reportFatal:message stack:stackArray exceptionId:exceptionId extraDataAsJSON:extraDataAsJSON];
} else {
[self reportSoft:message stack:stackArray exceptionId:exceptionId];
[self reportSoft:message stack:stackArray exceptionId:exceptionId extraDataAsJSON:extraDataAsJSON];
}
}

Expand Down

0 comments on commit a65ae8e

Please sign in to comment.