Attach js_extra_data to JS errors on iOS

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 (https://github.com/facebook/react-native/commit/3a825c036065783aae6fb734028f986dbead80d7)), 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
This commit is contained in:
Gijs Weterings authored and Facebook GitHub Bot committed 2022-04-25 03:26:24 -07:00
1 parent 4f855c8a2a
commit a65ae8eff6
4 files changed
+31 -11

No files matched your search

+5
View File
@@ -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.
*/
+1
View File
@@ -14,6 +14,7 @@ NSString *const RCTJSRawStackTraceKey = @"RCTJSRawStackTraceKey";
NSString *const RCTObjCStackTraceKey = @"RCTObjCStackTraceKey";
NSString *const RCTFatalExceptionName = @"RCTFatalException";
NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey";
NSString *const RCTJSExtraDataKey = @"RCTJSExtraDataKey";
static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack";
+4 -2
View File
@@ -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
+21 -9
View File
@@ -35,7 +35,10 @@ RCT_EXPORT_MODULE()
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];
@@ -43,11 +46,15 @@ RCT_EXPORT_MODULE()
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];
@@ -55,7 +62,8 @@ RCT_EXPORT_MODULE()
if (_delegate) {
[_delegate handleFatalJSExceptionWithMessage:message
stack:stack
exceptionId:[NSNumber numberWithDouble:exceptionId]];
exceptionId:[NSNumber numberWithDouble:exceptionId]
extraDataAsJSON:extraDataAsJSON];
}
static NSUInteger reloadRetries = 0;
@@ -64,7 +72,8 @@ RCT_EXPORT_MODULE()
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]);
}
}
@@ -74,7 +83,7 @@ RCT_EXPORT_METHOD(reportSoftException
: (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
@@ -82,7 +91,7 @@ RCT_EXPORT_METHOD(reportFatalException
: (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
@@ -131,10 +140,13 @@ RCT_EXPORT_METHOD(reportException : (JS::NativeExceptionsManager::ExceptionData
[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];
}
}