diff --git a/packages/react-native/React/CoreModules/CoreModulesPlugins.h b/packages/react-native/React/CoreModules/CoreModulesPlugins.h index a3a7bce63f335d..e62d4d157bb070 100644 --- a/packages/react-native/React/CoreModules/CoreModulesPlugins.h +++ b/packages/react-native/React/CoreModules/CoreModulesPlugins.h @@ -50,7 +50,6 @@ Class RCTRedBoxCls(void) __attribute__((used)); Class RCTSourceCodeCls(void) __attribute__((used)); Class RCTStatusBarManagerCls(void) __attribute__((used)); Class RCTTimingCls(void) __attribute__((used)); -Class RCTWebSocketExecutorCls(void) __attribute__((used)); Class RCTWebSocketModuleCls(void) __attribute__((used)); Class RCTBlobManagerCls(void) __attribute__((used)); diff --git a/packages/react-native/React/CoreModules/CoreModulesPlugins.mm b/packages/react-native/React/CoreModules/CoreModulesPlugins.mm index fc1587becada12..ef961253ae073d 100644 --- a/packages/react-native/React/CoreModules/CoreModulesPlugins.mm +++ b/packages/react-native/React/CoreModules/CoreModulesPlugins.mm @@ -40,7 +40,6 @@ Class RCTCoreModulesClassProvider(const char *name) { {"SourceCode", RCTSourceCodeCls}, {"StatusBarManager", RCTStatusBarManagerCls}, {"Timing", RCTTimingCls}, - {"WebSocketExecutor", RCTWebSocketExecutorCls}, {"WebSocketModule", RCTWebSocketModuleCls}, {"BlobModule", RCTBlobManagerCls}, }; diff --git a/packages/react-native/React/CoreModules/RCTDevSettings.h b/packages/react-native/React/CoreModules/RCTDevSettings.h index 35a24b5d9191b2..29205b58041d7d 100644 --- a/packages/react-native/React/CoreModules/RCTDevSettings.h +++ b/packages/react-native/React/CoreModules/RCTDevSettings.h @@ -47,7 +47,6 @@ - (instancetype)initWithDataSource:(id)dataSource; @property (nonatomic, readonly) BOOL isHotLoadingAvailable; -@property (nonatomic, readonly) BOOL isRemoteDebuggingAvailable; @property (nonatomic, readonly) BOOL isDeviceDebuggingAvailable; @property (nonatomic, readonly) BOOL isJSCSamplingProfilerAvailable; diff --git a/packages/react-native/React/CoreModules/RCTDevSettings.mm b/packages/react-native/React/CoreModules/RCTDevSettings.mm index 346738bccb6362..4af9d9ef47520d 100644 --- a/packages/react-native/React/CoreModules/RCTDevSettings.mm +++ b/packages/react-native/React/CoreModules/RCTDevSettings.mm @@ -176,37 +176,6 @@ - (instancetype)initWithDataSource:(id)dataSource - (void)initialize { -#if RCT_DEV_SETTINGS_ENABLE_PACKAGER_CONNECTION - if (self.bridge) { - RCTBridge *__weak weakBridge = self.bridge; - _bridgeExecutorOverrideToken = [[RCTPackagerConnection sharedPackagerConnection] - addNotificationHandler:^(id params) { - if (params != (id)kCFNull && [params[@"debug"] boolValue]) { - weakBridge.executorClass = objc_lookUpClass("RCTWebSocketExecutor"); - } - } - queue:dispatch_get_main_queue() - forMethod:@"reload"]; - } - - if (numInitializedModules++ == 0) { - reloadToken = [[RCTPackagerConnection sharedPackagerConnection] - addNotificationHandler:^(id params) { - RCTTriggerReloadCommandListeners(@"Global hotkey"); - } - queue:dispatch_get_main_queue() - forMethod:@"reload"]; -#if RCT_DEV_MENU - devMenuToken = [[RCTPackagerConnection sharedPackagerConnection] - addNotificationHandler:^(id params) { - [self.bridge.devMenu show]; - } - queue:dispatch_get_main_queue() - forMethod:@"devMenu"]; -#endif - } -#endif - #if RCT_ENABLE_INSPECTOR if (self.bridge) { // We need this dispatch to the main thread because the bridge is not yet @@ -290,15 +259,6 @@ - (BOOL)isDeviceDebuggingAvailable #endif // RCT_ENABLE_INSPECTOR } -- (BOOL)isRemoteDebuggingAvailable -{ - if (RCTTurboModuleEnabled()) { - return NO; - } - Class jsDebuggingExecutorClass = objc_lookUpClass("RCTWebSocketExecutor"); - return (jsDebuggingExecutorClass != nil); -} - - (BOOL)isHotLoadingAvailable { if (self.bundleManager.bundleURL) { @@ -332,30 +292,6 @@ - (BOOL)isShakeToShowDevMenuEnabled return [[self settingForKey:kRCTDevSettingShakeToShowDevMenu] boolValue]; } -RCT_EXPORT_METHOD(setIsDebuggingRemotely : (BOOL)enabled) -{ - [self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingIsDebuggingRemotely]; - [self _remoteDebugSettingDidChange]; -} - -- (BOOL)isDebuggingRemotely -{ - return [[self settingForKey:kRCTDevSettingIsDebuggingRemotely] boolValue]; -} - -- (void)_remoteDebugSettingDidChange -{ - // This value is passed as a command-line argument, so fall back to reading from NSUserDefaults directly - NSString *executorOverride = [[NSUserDefaults standardUserDefaults] stringForKey:kRCTDevSettingExecutorOverrideClass]; - Class executorOverrideClass = executorOverride ? NSClassFromString(executorOverride) : nil; - if (executorOverrideClass) { - self.executorClass = executorOverrideClass; - } else { - BOOL enabled = self.isRemoteDebuggingAvailable && self.isDebuggingRemotely; - self.executorClass = enabled ? objc_getClass("RCTWebSocketExecutor") : nil; - } -} - RCT_EXPORT_METHOD(setProfilingEnabled : (BOOL)enabled) { [self _updateSettingWithValue:@(enabled) forKey:kRCTDevSettingProfilingEnabled]; @@ -450,11 +386,7 @@ - (void)setExecutorClass:(Class)executorClass { _executorClass = executorClass; if (self.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 && self.bridge.executorClass != objc_lookUpClass("RCTWebSocketExecutor")) { + if (executorClass == Nil) { return; } @@ -503,7 +435,6 @@ - (void)setupHMRClientWithAdditionalBundleURL:(NSURL *)bundleURL */ - (void)_synchronizeAllSettings { - [self _remoteDebugSettingDidChange]; [self _profilingSettingDidChange]; } @@ -563,10 +494,6 @@ - (BOOL)isHotLoadingAvailable { return NO; } -- (BOOL)isRemoteDebuggingAvailable -{ - return NO; -} + (BOOL)requiresMainQueueSetup { return NO; diff --git a/packages/react-native/React/CoreModules/RCTWebSocketExecutor.h b/packages/react-native/React/CoreModules/RCTWebSocketExecutor.h deleted file mode 100644 index 2c671d1f67796b..00000000000000 --- a/packages/react-native/React/CoreModules/RCTWebSocketExecutor.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import -#import - -#if RCT_DEV // Debug executors are only supported in dev mode - -@interface RCTWebSocketExecutor : NSObject - -- (instancetype)initWithURL:(NSURL *)URL; - -@end - -#endif diff --git a/packages/react-native/React/CoreModules/RCTWebSocketExecutor.mm b/packages/react-native/React/CoreModules/RCTWebSocketExecutor.mm deleted file mode 100644 index 1b7ffd29660d6a..00000000000000 --- a/packages/react-native/React/CoreModules/RCTWebSocketExecutor.mm +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import - -#import -#import -#import -#import -#import -#import - -#import -#import - -#import "CoreModulesPlugins.h" - -#if RCT_DEV // Debug executors are only supported in dev mode - -typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary *reply); - -@interface RCTWebSocketExecutor () - -@end - -@implementation RCTWebSocketExecutor { - SRWebSocket *_socket; - dispatch_queue_t _jsQueue; - NSMutableDictionary *_callbacks; - dispatch_semaphore_t _socketOpenSemaphore; - NSMutableDictionary *_injectedObjects; - NSURL *_url; - NSError *_setupError; -} - -RCT_EXPORT_MODULE() - -@synthesize bridge = _bridge; - -- (instancetype)initWithURL:(NSURL *)URL -{ - RCTAssertParam(URL); - - if ((self = [self init])) { - _url = URL; - } - return self; -} - -- (void)setUp -{ - if (!_url) { - NSInteger port = [[[_bridge bundleURL] port] integerValue] ?: RCT_METRO_PORT; - NSString *host = [[_bridge bundleURL] host] ?: @"localhost"; - NSString *URLString = - [NSString stringWithFormat:@"http://%@:%lld/debugger-proxy?role=client", host, (long long)port]; - _url = [RCTConvert NSURL:URLString]; - } - - _jsQueue = dispatch_queue_create("com.facebook.react.WebSocketExecutor", DISPATCH_QUEUE_SERIAL); - _socket = [[SRWebSocket alloc] initWithURL:_url]; - _socket.delegate = self; - _callbacks = [NSMutableDictionary new]; - _injectedObjects = [NSMutableDictionary new]; - [_socket setDelegateDispatchQueue:_jsQueue]; - - NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-js-devtools" relativeToURL:_url]; - - NSURLSession *session = [NSURLSession sharedSession]; - NSURLSessionDataTask *dataTask = - [session dataTaskWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){ - }]; - [dataTask resume]; - if (![self connectToProxy]) { - [self invalidate]; - NSString *error = [NSString stringWithFormat: - @"Connection to %@ timed out. Are you " - "running node proxy? If you are running on the device, check if " - "you have the right IP address in `RCTWebSocketExecutor.m`.", - _url]; - _setupError = RCTErrorWithMessage(error); - RCTFatal(_setupError); - return; - } - - NSInteger retries = 3; - BOOL runtimeIsReady = [self prepareJSRuntime]; - while (!runtimeIsReady && retries > 0) { - runtimeIsReady = [self prepareJSRuntime]; - retries--; - } - if (!runtimeIsReady) { - [self invalidate]; - NSString *error = - @"Runtime is not ready for debugging.\n " - "- Make sure Metro is running.\n" - "- Make sure the JavaScript Debugger is running and not paused on a " - "breakpoint or exception and try reloading again."; - _setupError = RCTErrorWithMessage(error); - RCTFatal(_setupError); - return; - } -} - -- (BOOL)connectToProxy -{ - _socketOpenSemaphore = dispatch_semaphore_create(0); - [_socket open]; - long connected = dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 15)); - return connected == 0 && _socket.readyState == SR_OPEN; -} - -- (BOOL)prepareJSRuntime -{ - __block NSError *initError; - dispatch_semaphore_t s = dispatch_semaphore_create(0); - [self sendMessage:@{@"method" : @"prepareJSRuntime"} - onReply:^(NSError *error, NSDictionary *reply) { - initError = error; - dispatch_semaphore_signal(s); - }]; - long runtimeIsReady = dispatch_semaphore_wait(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10)); - if (initError) { - RCTLogInfo(@"Websocket runtime setup failed: %@", initError); - } - return runtimeIsReady == 0 && initError == nil; -} - -- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message -{ - NSError *error = nil; - NSDictionary *reply = RCTJSONParse(message, &error); - NSNumber *messageID = reply[@"replyID"]; - RCTWSMessageCallback callback = _callbacks[messageID]; - if (callback) { - callback(error, reply); - [_callbacks removeObjectForKey:messageID]; - } -} - -- (void)webSocketDidOpen:(SRWebSocket *)webSocket -{ - dispatch_semaphore_signal(_socketOpenSemaphore); -} - -- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error -{ - dispatch_semaphore_signal(_socketOpenSemaphore); - RCTLogInfo(@"WebSocket connection failed with error %@", error); -} - -- (void)sendMessage:(NSDictionary *)message onReply:(RCTWSMessageCallback)callback -{ - static NSUInteger lastID = 10000; - - if (_setupError) { - callback(_setupError, nil); - return; - } - - dispatch_async(_jsQueue, ^{ - if (!self.valid) { - callback( - RCTErrorWithMessage( - @"Runtime is not ready for debugging. Make sure Metro is running and the Remote Debugging browser window is open."), - nil); - return; - } - - NSNumber *expectedID = @(lastID++); - self->_callbacks[expectedID] = [callback copy]; - NSMutableDictionary *messageWithID = [message mutableCopy]; - messageWithID[@"id"] = expectedID; - [self->_socket sendString:RCTJSONStringify(messageWithID, NULL) error:nil]; - }); -} - -- (void)executeApplicationScript:(NSData *)script - sourceURL:(NSURL *)URL - onComplete:(RCTJavaScriptCompleteBlock)onComplete -{ - // Hack: the bridge transitions out of loading state as soon as this method returns, which prevents us - // from completely invalidating the bridge and preventing an endless barage of RCTLog.logIfNoNativeHook - // calls if the JS execution environment is broken. We therefore block this thread until this message has returned. - dispatch_semaphore_t scriptSem = dispatch_semaphore_create(0); - - NSDictionary *message = @{ - @"method" : @"executeApplicationScript", - @"url" : RCTNullIfNil(URL.absoluteString), - @"inject" : _injectedObjects, - }; - [self sendMessage:message - onReply:^(NSError *socketError, NSDictionary *reply) { - if (socketError) { - onComplete(socketError); - } else { - NSString *error = reply[@"error"]; - onComplete(error ? RCTErrorWithMessage(error) : nil); - } - dispatch_semaphore_signal(scriptSem); - }]; - - dispatch_semaphore_wait(scriptSem, DISPATCH_TIME_FOREVER); -} - -- (void)flushedQueue:(RCTJavaScriptCallback)onComplete -{ - [self _executeJSCall:@"flushedQueue" arguments:@[] callback:onComplete]; -} - -- (void)callFunctionOnModule:(NSString *)module - method:(NSString *)method - arguments:(NSArray *)args - callback:(RCTJavaScriptCallback)onComplete -{ - [self _executeJSCall:@"callFunctionReturnFlushedQueue" arguments:@[ module, method, args ] callback:onComplete]; -} - -- (void)invokeCallbackID:(NSNumber *)cbID arguments:(NSArray *)args callback:(RCTJavaScriptCallback)onComplete -{ - [self _executeJSCall:@"invokeCallbackAndReturnFlushedQueue" arguments:@[ cbID, args ] callback:onComplete]; -} - -- (void)_executeJSCall:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete -{ - RCTAssert(onComplete != nil, @"callback was missing for exec JS call"); - NSDictionary *message = @{@"method" : method, @"arguments" : arguments}; - [self sendMessage:message - onReply:^(NSError *socketError, NSDictionary *reply) { - if (socketError) { - onComplete(nil, socketError); - return; - } - - NSError *jsonError; - id result = RCTJSONParse(reply[@"result"], &jsonError); - NSString *error = reply[@"error"]; - onComplete(result, error ? RCTErrorWithMessage(error) : jsonError); - }]; -} - -- (void)injectJSONText:(NSString *)script - asGlobalObjectNamed:(NSString *)objectName - callback:(RCTJavaScriptCompleteBlock)onComplete -{ - dispatch_async(_jsQueue, ^{ - self->_injectedObjects[objectName] = script; - onComplete(nil); - }); -} - -- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block -{ - RCTExecuteOnMainQueue(block); -} - -- (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block -{ - dispatch_async(dispatch_get_main_queue(), block); -} - -- (void)invalidate -{ - _socket.delegate = nil; - [_socket closeWithCode:1000 reason:@"Invalidated"]; - _socket = nil; -} - -- (BOOL)isValid -{ - return _socket != nil && _socket.readyState == SR_OPEN; -} - -- (void)dealloc -{ - RCTAssert(!self.valid, @"-invalidate must be called before -dealloc"); -} - -- (std::shared_ptr)getTurboModule: - (const facebook::react::ObjCTurboModule::InitParams &)params -{ - return nullptr; -} - -@end - -#endif - -Class RCTWebSocketExecutorCls(void) -{ -#if RCT_DEV - return RCTWebSocketExecutor.class; -#else - return nil; -#endif -} diff --git a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm index af931fd45ca10f..49d19e0018c81a 100644 --- a/packages/react-native/React/CxxBridge/RCTCxxBridge.mm +++ b/packages/react-native/React/CxxBridge/RCTCxxBridge.mm @@ -849,59 +849,6 @@ - (void)registerExtraModules - (void)registerExtraLazyModules { -#if RCT_DEBUG - // This is debug-only and only when Chrome is attached, since it expects all modules to be already - // available on start up. Otherwise, we can let the lazy module discovery to load them on demand. - Class executorClass = [_parentBridge executorClass]; - if (executorClass && [NSStringFromClass(executorClass) isEqualToString:@"RCTWebSocketExecutor"]) { - NSDictionary *moduleClasses = nil; - if ([self.delegate respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) { - moduleClasses = [self.delegate extraLazyModuleClassesForBridge:_parentBridge]; - } - - if (!moduleClasses) { - return; - } - - // This logic is mostly copied from `registerModulesForClasses:`, but with one difference: - // we must use the names provided by the delegate method here. - for (NSString *moduleName in moduleClasses) { - Class moduleClass = moduleClasses[moduleName]; - if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { - continue; - } - - // Check for module name collisions - RCTModuleData *moduleData = _moduleDataByName[moduleName]; - if (moduleData) { - if (moduleData.hasInstance) { - // Existing module was preregistered, so it takes precedence - continue; - } else if ([moduleClass new] == nil) { - // The new module returned nil from init, so use the old module - continue; - } else if ([moduleData.moduleClass new] != nil) { - // Use existing module since it was already loaded but not yet instantiated. - continue; - } - } - - int32_t moduleDataId = getUniqueId(); - BridgeNativeModulePerfLogger::moduleDataCreateStart([moduleName UTF8String], moduleDataId); - moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass - bridge:self - moduleRegistry:_objCModuleRegistry - viewRegistry_DEPRECATED:_viewRegistry_DEPRECATED - bundleManager:_bundleManager - callableJSModules:_callableJSModules]; - BridgeNativeModulePerfLogger::moduleDataCreateEnd([moduleName UTF8String], moduleDataId); - - _moduleDataByName[moduleName] = moduleData; - [_moduleClassesByID addObject:moduleClass]; - [_moduleDataByID addObject:moduleData]; - } - } -#endif } - (NSArray *)_initializeModules:(NSArray *)modules