diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.h b/packages/react-native/React/CoreModules/RCTDevMenu.h index b9b76f63e6e385..4886ce60173c09 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.h +++ b/packages/react-native/React/CoreModules/RCTDevMenu.h @@ -98,6 +98,8 @@ typedef NSString * (^RCTDevMenuItemTitleBlock)(void); */ + (instancetype)buttonItemWithTitleBlock:(RCTDevMenuItemTitleBlock)titleBlock handler:(dispatch_block_t)handler; +@property (nonatomic, assign, getter=isDisabled) BOOL disabled; + @end /** diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 1a970a7d086952..035355a038eb49 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -265,18 +265,20 @@ - (void)setDefaultJSBundle #if RCT_ENABLE_INSPECTOR if (devSettings.isDeviceDebuggingAvailable) { // On-device JS debugging (CDP). Render action to open debugger frontend. - [items - addObject: - [RCTDevMenuItem - buttonItemWithTitleBlock:^NSString * { - return @"Open Debugger"; - } - handler:^{ - [RCTInspectorDevServerHelper - openDebugger:bundleManager.bundleURL - withErrorMessage: - @"Failed to open debugger. Please check that the dev server is running and reload the app."]; - }]]; + BOOL isDisconnected = RCTInspectorDevServerHelper.isPackagerDisconnected; + NSString *title = isDisconnected + ? [NSString stringWithFormat:@"Connect to %@ to debug JavaScript", RCT_PACKAGER_NAME] + : @"Open Debugger"; + RCTDevMenuItem *item = [RCTDevMenuItem + buttonItemWithTitle:title + handler:^{ + [RCTInspectorDevServerHelper + openDebugger:bundleManager.bundleURL + withErrorMessage: + @"Failed to open debugger. Please check that the dev server is running and reload the app."]; + }]; + [item setDisabled:isDisconnected]; + [items addObject:item]; } #endif } @@ -390,9 +392,11 @@ - (void)setDefaultJSBundle NSArray *items = [self _menuItemsToPresent]; for (RCTDevMenuItem *item in items) { - [_actionSheet addAction:[UIAlertAction actionWithTitle:item.title + UIAlertAction *action = [UIAlertAction actionWithTitle:item.title style:UIAlertActionStyleDefault - handler:[self alertActionHandlerForDevItem:item]]]; + handler:[self alertActionHandlerForDevItem:item]]; + [action setEnabled:!item.isDisabled]; + [_actionSheet addAction:action]; } [_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" diff --git a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.h b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.h index 0c4dbc15cf4b8f..1c7ba7bd87ecdb 100644 --- a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.h +++ b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.h @@ -17,6 +17,7 @@ + (id)connectWithBundleURL:(NSURL *)bundleURL; + (void)disableDebugger; ++ (BOOL)isPackagerDisconnected; + (void)openDebugger:(NSURL *)bundleURL withErrorMessage:(NSString *)errorMessage; @end diff --git a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm index 662aa39eca56c7..293782881fd1f8 100644 --- a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -118,6 +118,17 @@ static void sendEventToAllConnections(NSString *event) } } ++ (BOOL)isPackagerDisconnected +{ + for (NSString *socketId in socketConnections) { + if ([socketConnections[socketId] isConnected]) { + return false; + } + } + + return true; +} + + (void)openDebugger:(NSURL *)bundleURL withErrorMessage:(NSString *)errorMessage { NSString *appId = [[[NSBundle mainBundle] bundleIdentifier]