From 66fedc6eb7530182f41d107dcf348639b854778b Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 26 Mar 2015 18:17:11 -0700 Subject: [PATCH] [Init] Add an executor provider to RCTBridge's init method If you construct an RCTBridge you may want to configure the executor. However the constructor synchronously calls `setUp` and initializes the executor. Instead, let the code that constructs the bridge specify an executor source, which controls how the executor is provided. This allows for customizing the web view executor with a UIWebView of your choice, or configuring the URL of the debugger proxy that the web socket executor connects to. Now that RCTRootView takes a bridge in one of its initializers, it is possible to create a bridge with a custom executor and then use that to set up a root view as well. Test Plan: Run the UIExplorer app and confirm I am able to connect to the plain JSContext via Safari. Hit Cmd-D, pick Chrome and see Chrome open a Tab. Hit Cmd-N and see that I can connect to a plain JSContext again. Shake the simulator and select "Enable Safari Debugging" and see that I can connect to the UIWebView from Safari. tl;dr the keyboard shortcuts and dev menu work as expected. Fixes #288 --- React/Base/RCTBridge.h | 17 ++- React/Base/RCTBridge.m | 28 +++-- React/Base/RCTDevMenu.m | 125 +++++++++++------------ React/Base/RCTJavaScriptExecutor.h | 4 +- React/Base/RCTJavaScriptExecutorSource.h | 21 ++++ React/Base/RCTRootView.h | 10 +- React/Base/RCTRootView.m | 2 - React/Base/RCTStandardExecutorSource.h | 26 +++++ React/Base/RCTStandardExecutorSource.m | 48 +++++++++ React/React.xcodeproj/project.pbxproj | 8 ++ 10 files changed, 197 insertions(+), 92 deletions(-) create mode 100644 React/Base/RCTJavaScriptExecutorSource.h create mode 100644 React/Base/RCTStandardExecutorSource.h create mode 100644 React/Base/RCTStandardExecutorSource.m diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index 5f84ed9dacc6c9..630f8640b281fe 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -17,6 +17,7 @@ @class RCTBridge; @class RCTEventDispatcher; +@protocol RCTJavaScriptExecutorSource; /** * This notification triggers a reload of all bridges currently running. @@ -36,7 +37,7 @@ extern NSString *const RCTJavaScriptDidFailToLoadNotification; /** * This block can be used to instantiate modules that require additional * init parameters, or additional configuration prior to being used. - * The bridge will call this block to instatiate the modules, and will + * The bridge will call this block to instantiate the modules, and will * be responsible for invalidating/releasing them when the bridge is destroyed. * For this reason, the block should always return new module instances, and * module instances should not be shared between bridges. @@ -57,13 +58,18 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); * The designated initializer. This creates a new bridge on top of the specified * executor. The bridge should then be used for all subsequent communication * with the JavaScript code running in the executor. Modules will be automatically - * instantiated using the default contructor, but you can optionally pass in an + * instantiated using the default constructor, but you can optionally pass in an * array of pre-initialized module instances if they require additional init * parameters or configuration. */ - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleProvider:(RCTBridgeModuleProviderBlock)block - launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER; + launchOptions:(NSDictionary *)launchOptions + executorSource:(id)executorSource NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithBundleURL:(NSURL *)bundleURL + moduleProvider:(RCTBridgeModuleProviderBlock)block + launchOptions:(NSDictionary *)launchOptions; /** * This method is used to call functions in the JavaScript application context. @@ -90,7 +96,10 @@ static const char *__rct_import_##module##_##method##__ = #module"."#method; */ @property (nonatomic, copy) NSURL *bundleURL; -@property (nonatomic, strong) Class executorClass; +/** + * The source of JavaScript executors used by this bridge. + */ +@property (nonatomic, strong, readonly) id executorSource; /** * The event dispatcher is a wrapper around -enqueueJSCall:args: that provides a diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index 47c7f59420c91d..33aed8d5f3f9b6 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -27,6 +27,7 @@ #import "RCTRootView.h" #import "RCTSourceCode.h" #import "RCTSparseArray.h" +#import "RCTStandardExecutorSource.h" #import "RCTUtils.h" NSString *const RCTReloadNotification = @"RCTReloadNotification"; @@ -764,6 +765,17 @@ @implementation RCTBridge - (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleProvider:(RCTBridgeModuleProviderBlock)block launchOptions:(NSDictionary *)launchOptions +{ + return [self initWithBundleURL:bundleURL + moduleProvider:block + launchOptions:launchOptions + executorSource:[[RCTStandardExecutorSource alloc] init]]; +} + +- (instancetype)initWithBundleURL:(NSURL *)bundleURL + moduleProvider:(RCTBridgeModuleProviderBlock)block + launchOptions:(NSDictionary *)launchOptions + executorSource:(id)executorSource { RCTAssertMainThread(); @@ -776,6 +788,7 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL _bundleURL = bundleURL; _moduleProvider = block; _launchOptions = [launchOptions copy]; + _executorSource = executorSource; [self bindKeys]; [self setUp]; } @@ -932,8 +945,8 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge /** * Initialize executor to allow enqueueing calls */ - Class executorClass = self.executorClass ?: [RCTContextExecutor class]; - _javaScriptExecutor = RCTCreateExecutor(executorClass); + _javaScriptExecutor = [_parentBridge.executorSource executor]; + RCTSetNewExecutorID(_javaScriptExecutor); _latestJSExecutor = _javaScriptExecutor; /** @@ -971,16 +984,9 @@ - (void)reload [_parentBridge reload]; } -- (Class)executorClass +- (id)executorSource { - return _parentBridge.executorClass; -} - -- (void)setExecutorClass:(Class)executorClass -{ - RCTAssertMainThread(); - - _parentBridge.executorClass = executorClass; + return _parentBridge.executorSource; } - (BOOL)isLoading diff --git a/React/Base/RCTDevMenu.m b/React/Base/RCTDevMenu.m index 2416e974c1757f..fd4f30ca4b489f 100644 --- a/React/Base/RCTDevMenu.m +++ b/React/Base/RCTDevMenu.m @@ -16,7 +16,9 @@ #import "RCTLog.h" #import "RCTPerfStats.h" #import "RCTProfile.h" -#import "RCTRootView.h" +#import "RCTRedBox.h" +#import "RCTJavaScriptExecutorSource.h" +#import "RCTStandardExecutorSource.h" #import "RCTSourceCode.h" #import "RCTUtils.h" @@ -45,7 +47,7 @@ - (void)RCT_motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event @interface RCTDevMenu () -@property (nonatomic, strong) Class executorClass; +@property (nonatomic, assign) RCTStandardExecutorType executorType; @end @@ -114,7 +116,7 @@ - (instancetype)init [commands registerKeyCommandWithInput:@"n" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { - weakSelf.executorClass = Nil; + weakSelf.executorType = RCTStandardExecutorTypeDefault; }]; #endif @@ -148,7 +150,7 @@ - (void)updateSettings self.profilingEnabled = [_settings[@"profilingEnabled"] ?: @NO boolValue]; self.liveReloadEnabled = [_settings[@"liveReloadEnabled"] ?: @NO boolValue]; self.showFPS = [_settings[@"showFPS"] ?: @NO boolValue]; - self.executorClass = NSClassFromString(_settings[@"executorClass"]); + self.executorType = [_settings[@"executorType"] ?: @(RCTStandardExecutorTypeDefault) unsignedIntegerValue]; } - (void)jsLoaded:(NSNotification *)notification @@ -177,7 +179,7 @@ - (void)jsLoaded:(NSNotification *)notification // Hit these setters again after bridge has finished loading self.profilingEnabled = _profilingEnabled; self.liveReloadEnabled = _liveReloadEnabled; - self.executorClass = _executorClass; + self.executorType = _executorType; }); } @@ -231,16 +233,24 @@ - (void)toggle return; } - NSString *debugTitleChrome = _executorClass && _executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Debug in Chrome"; - NSString *debugTitleSafari = _executorClass && _executorClass == NSClassFromString(@"RCTWebViewExecutor") ? @"Disable Safari Debugging" : @"Debug in Safari"; - NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor"; - UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil - otherButtonTitles:@"Reload", debugTitleChrome, debugTitleSafari, fpsMonitor, nil]; + otherButtonTitles:@"Reload", nil]; + + if ([_bridge.executorSource isKindOfClass:[RCTStandardExecutorSource class]]) { + RCTStandardExecutorSource *source = (RCTStandardExecutorSource *)_bridge.executorSource; + RCTStandardExecutorType executorType = source.executorType; + NSString *debugTitleChrome = (executorType == RCTStandardExecutorTypeWebSocket) ? @"Disable Chrome Debugging" : @"Debug in Chrome"; + NSString *debugTitleSafari = (executorType == RCTStandardExecutorTypeUIWebView) ? @"Disable Safari Debugging" : @"Debug in Safari"; + [actionSheet addButtonWithTitle:debugTitleChrome]; + [actionSheet addButtonWithTitle:debugTitleSafari]; + } + + NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor"; + [actionSheet addButtonWithTitle:fpsMonitor]; [actionSheet addButtonWithTitle:@"Inspect Element"]; @@ -275,47 +285,25 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger return; } - switch (buttonIndex) { - case 0: { - [self reload]; - break; - } - case 1: { - Class cls = NSClassFromString(@"RCTWebSocketExecutor"); - if (!cls) { - [[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable" - message:@"You need to include the RCTWebSocket library to enable Chrome debugging" - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil] show]; - return; - } - self.executorClass = (_executorClass == cls) ? Nil : cls; - break; - } - case 2: { - Class cls = NSClassFromString(@"RCTWebViewExecutor"); - self.executorClass = (_executorClass == cls) ? Nil : cls; - break; - } - case 3: { - self.showFPS = !_showFPS; - break; - } - case 4: { - [_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil]; - break; - } - case 5: { - self.liveReloadEnabled = !_liveReloadEnabled; - break; - } - case 6: { - self.profilingEnabled = !_profilingEnabled; - break; - } - default: - break; + if (buttonIndex == 0) { + [self reload]; + return; + } + + // Note: after supporting iOS 8+, use UIAlertController which has a more cohesive API + NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex]; + if ([buttonTitle containsString:@"Chrome"]) { + [self _toggleExecutorType:RCTStandardExecutorTypeWebSocket]; + } else if ([buttonTitle containsString:@"Safari"]) { + [self _toggleExecutorType:RCTStandardExecutorTypeUIWebView]; + } else if ([buttonTitle containsString:@"FPS Monitor"]) { + self.showFPS = !_showFPS; + } else if ([buttonTitle containsString:@"Inspect Element"]) { + [_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil]; + } else if ([buttonTitle containsString:@"Live Reload"]) { + self.liveReloadEnabled = !_liveReloadEnabled; + } else if ([buttonTitle containsString:@"Profiling"]) { + self.profilingEnabled = !_profilingEnabled; } } @@ -358,27 +346,28 @@ - (void)setLiveReloadEnabled:(BOOL)enabled } } -- (void)setExecutorClass:(Class)executorClass +- (void)_toggleExecutorType:(RCTStandardExecutorType)executorType { - if (_executorClass != executorClass) { - _executorClass = executorClass; - [self updateSetting:@"executorClass" value: NSStringFromClass(executorClass)]; + if (_executorType == executorType) { + self.executorType = RCTStandardExecutorTypeDefault; + } else { + self.executorType = executorType; } +} - if (_bridge.executorClass != executorClass) { - - // TODO (6929129): we can remove this special case test once we have better - // support for custom executors in the dev menu. But right now this is - // needed to prevent overriding a custom executor with the default if a - // custom executor has been set directly on the bridge - if (executorClass == Nil && - (_bridge.executorClass != NSClassFromString(@"RCTWebSocketExecutor") && - _bridge.executorClass != NSClassFromString(@"RCTWebViewExecutor"))) { - return; - } +- (void)setExecutorType:(RCTStandardExecutorType)executorType +{ + if (_executorType != executorType) { + _executorType = executorType; + [self updateSetting:@"executorType" value:@(executorType)]; + } - _bridge.executorClass = executorClass; - [self reload]; + if ([_bridge.executorSource isKindOfClass:[RCTStandardExecutorSource class]]) { + RCTStandardExecutorSource *source = (RCTStandardExecutorSource *)_bridge.executorSource; + if (source.executorType != executorType) { + source.executorType = executorType; + [_bridge reload]; + } } } diff --git a/React/Base/RCTJavaScriptExecutor.h b/React/Base/RCTJavaScriptExecutor.h index 8f1eb8a98c076a..fa495a3f559641 100644 --- a/React/Base/RCTJavaScriptExecutor.h +++ b/React/Base/RCTJavaScriptExecutor.h @@ -61,14 +61,12 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error); @end static const char *RCTJavaScriptExecutorID = "RCTJavaScriptExecutorID"; -__used static id RCTCreateExecutor(Class executorClass) +__used static void RCTSetNewExecutorID(id executor) { static NSUInteger executorID = 0; - id executor = [[executorClass alloc] init]; if (executor) { objc_setAssociatedObject(executor, RCTJavaScriptExecutorID, @(++executorID), OBJC_ASSOCIATION_RETAIN); } - return executor; } __used static NSNumber *RCTGetExecutorID(id executor) diff --git a/React/Base/RCTJavaScriptExecutorSource.h b/React/Base/RCTJavaScriptExecutorSource.h new file mode 100644 index 00000000000000..38557649ef4eb3 --- /dev/null +++ b/React/Base/RCTJavaScriptExecutorSource.h @@ -0,0 +1,21 @@ +/** + * 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 + +@protocol RCTJavaScriptExecutor; + +@protocol RCTJavaScriptExecutorSource + +/** + * Return a new JavaScript executor to run a React application. + */ +- (id)executor; + +@end diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h index d55094c3727328..278b7e532ea861 100644 --- a/React/Base/RCTRootView.h +++ b/React/Base/RCTRootView.h @@ -11,6 +11,8 @@ #import "RCTBridge.h" +@class RCTStandardExecutorSource; + @interface RCTRootView : UIView /** @@ -51,11 +53,11 @@ @property (nonatomic, copy) NSDictionary *initialProperties; /** - * The class of the RCTJavaScriptExecutor to use with this view. - * If not specified, it will default to using RCTContextExecutor. - * Changes will take effect next time the bundle is reloaded. + * The source of the JavaScript executors that this RCTRootView uses. Set the + * executor type through the provider and reload the RCTRootView for a new + * executor. */ -@property (nonatomic, strong) Class executorClass; +@property (nonatomic, strong, readonly) RCTStandardExecutorSource *executorSource; /** * The backing view controller of the root view. diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index e9a8170eb01ab1..e4713b94fa9733 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -13,7 +13,6 @@ #import "RCTAssert.h" #import "RCTBridge.h" -#import "RCTContextExecutor.h" #import "RCTEventDispatcher.h" #import "RCTKeyCommands.h" #import "RCTLog.h" @@ -22,7 +21,6 @@ #import "RCTUIManager.h" #import "RCTUtils.h" #import "RCTView.h" -#import "RCTWebViewExecutor.h" #import "UIView+React.h" @interface RCTBridge (RCTRootView) diff --git a/React/Base/RCTStandardExecutorSource.h b/React/Base/RCTStandardExecutorSource.h new file mode 100644 index 00000000000000..ecd39fde30d1b6 --- /dev/null +++ b/React/Base/RCTStandardExecutorSource.h @@ -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 + +#import "RCTJavaScriptExecutorSource.h" + +typedef NS_ENUM(NSUInteger, RCTStandardExecutorType) { + RCTStandardExecutorTypeDefault, + RCTStandardExecutorTypeUIWebView, + RCTStandardExecutorTypeWebSocket, +}; + +@interface RCTStandardExecutorSource : NSObject + +@property (nonatomic) RCTStandardExecutorType executorType; + +- (id)executor; + +@end diff --git a/React/Base/RCTStandardExecutorSource.m b/React/Base/RCTStandardExecutorSource.m new file mode 100644 index 00000000000000..739cf30a43fb15 --- /dev/null +++ b/React/Base/RCTStandardExecutorSource.m @@ -0,0 +1,48 @@ +// Copyright 2015-present Facebook. All rights reserved. + +#import "RCTStandardExecutorSource.h" + +#import "RCTContextExecutor.h" +#import "RCTJavaScriptExecutor.h" +#import "RCTLog.h" +#import "RCTWebViewExecutor.h" + +@implementation RCTStandardExecutorSource + +- (instancetype)init +{ + if (self = [super init]) { + _executorType = RCTStandardExecutorTypeDefault; + } + return self; +} + +- (id)executor +{ + switch (_executorType) { + case RCTStandardExecutorTypeDefault: + return [[RCTContextExecutor alloc] init]; + case RCTStandardExecutorTypeUIWebView: { + Class executorClass = NSClassFromString(@"RCTWebViewExecutor"); + if (!executorClass) { + RCTLogError(@"Safari debugger is available only in development mode"); + executorClass = [RCTContextExecutor class]; + } + return [[executorClass alloc] init]; + } + case RCTStandardExecutorTypeWebSocket: { + Class executorClass = NSClassFromString(@"RCTWebSocketExecutor"); + if (!executorClass) { + [[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable" + message:@"You need to include the RCTWebSocket library to enable Chrome debugging" + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil] show]; + executorClass = [RCTContextExecutor class]; + } + return [[executorClass alloc] init]; + } + } +} + +@end diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index cf05f4e39c9c21..25faa4a7a81b66 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -57,6 +57,7 @@ 58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; }; 58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; }; 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; }; + 78B543961ADA560C00791665 /* RCTStandardExecutorSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 78B543951ADA560C00791665 /* RCTStandardExecutorSource.m */; }; 830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; }; 830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 830BA4541A8E3BDA00D53203 /* RCTCache.m */; }; 832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; }; @@ -192,6 +193,9 @@ 58114A4F1AAE93D500E7D092 /* RCTAsyncLocalStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAsyncLocalStorage.h; sourceTree = ""; }; 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = ""; }; 58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDatePickerManager.h; sourceTree = ""; }; + 78B543941ADA560C00791665 /* RCTStandardExecutorSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStandardExecutorSource.h; sourceTree = ""; }; + 78B543951ADA560C00791665 /* RCTStandardExecutorSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStandardExecutorSource.m; sourceTree = ""; }; + 78B543AD1ADC604F00791665 /* RCTJavaScriptExecutorSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptExecutorSource.h; sourceTree = ""; }; 830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = ""; }; 830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = ""; }; 830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = ""; }; @@ -402,6 +406,7 @@ 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */, 83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */, 83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */, + 78B543AD1ADC604F00791665 /* RCTJavaScriptExecutorSource.h */, 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */, 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */, 83CBBA4D1A601E3B00E9B192 /* RCTLog.h */, @@ -410,6 +415,8 @@ 83CBBA591A601E9000E9B192 /* RCTRedBox.m */, 830A229C1A66C68A008503DA /* RCTRootView.h */, 830A229D1A66C68A008503DA /* RCTRootView.m */, + 78B543941ADA560C00791665 /* RCTStandardExecutorSource.h */, + 78B543951ADA560C00791665 /* RCTStandardExecutorSource.m */, 00C1A2B11AC0B7E000E89A1C /* RCTDevMenu.h */, 00C1A2B21AC0B7E000E89A1C /* RCTDevMenu.m */, 83BEE46C1A6D19BC00B5863B /* RCTSparseArray.h */, @@ -523,6 +530,7 @@ 13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */, 13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */, 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */, + 78B543961ADA560C00791665 /* RCTStandardExecutorSource.m in Sources */, 13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */, 146459261B06C49500B389AA /* RCTFPSGraph.m in Sources */, 14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,