-
Notifications
You must be signed in to change notification settings - Fork 672
Open
Description
React Native DevTools not working on iOS physical device - Shows "Connect to Metro to debug JavaScript"
Description
I'm unable to open the React Native DevTools on iOS physical devices in React Native 0.82.1. When I start Metro and press j in the terminal, the DevTools don't open. Similarly, when I open the Dev Menu it only shows the message "Connect to Metro to debug JavaScript" insted of open devtool. The app connects to Metro bundler successfully and hot reload works fine, but the debugger won't open at all.
Important notes:
- ✅ Works fine on Android physical devices
- ✅ Metro bundler is running and app connects successfully (reload works)
- ❌ DevTools not working on iOS physical device
- 🔄 Recently migrated AppDelegate from Objective-C (.mm) to Swift
Environment
React Native Info
React Native: 0.82.1
Node: v24.2.0
iOS: 15.5+
Platform: iOS (Physical Device)
Hermes: Enabled
New Architecture: Enabled
Device
- Physical iPhone device (not simulator)
- Connected via USB and same WiFi network as development machine
Steps to Reproduce
- Create/use React Native 0.82.1 project with Hermes and New Architecture enabled
- Migrate AppDelegate from Objective-C to Swift (files shown below)
- Build and run on physical iOS device
- Shake device to open Dev Menu
- Tap "Open Debugger"
- Expected: Chrome DevTools opens with Hermes debugger
- Actual: Shows message "Connect to Metro to debug JavaScript" but debugger doesn't open
Relevant Code
AppDelegate.swift (Converted from .mm)
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import Firebase
import RNBootSplash
import FBSDKCoreKit
import AppTrackingTransparency
import GoogleSignIn
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
// Initialize Firebase
if FirebaseApp.app() == nil {
var googleServiceInfofilePath = ""
#if DEV
googleServiceInfofilePath = Bundle.main.path(forResource: "GoogleServices-Info-Dev", ofType: "plist") ?? ""
#else
googleServiceInfofilePath = Bundle.main.path(forResource: "GoogleServices-Info", ofType: "plist") ?? ""
#endif
FirebaseApp.configure()
}
// Initialize Facebook SDK
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
// Request App Tracking Transparency (iOS 14+)
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization { _ in
AppEvents.shared.activateApp()
}
} else {
AppEvents.shared.activateApp()
}
// Setup React Native
let delegate = ReactNativeDelegate()
let factory = RCTReactNativeFactory(delegate: delegate)
delegate.dependencyProvider = RCTAppDependencyProvider()
reactNativeDelegate = delegate
reactNativeFactory = factory
window = UIWindow(frame: UIScreen.main.bounds)
factory.startReactNative(
withModuleName: "Fin1",
in: window,
launchOptions: launchOptions
)
return true
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return Orientation.getOrientation()
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Add any other URL handlers you're using (e.g. Facebook SDK)
return ApplicationDelegate.shared.application(app, open: url, options: options) ||
GIDSignIn.sharedInstance.handle(url) ||
RCTLinkingManager.application(app, open: url, options: options)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
}
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
override func sourceURL(for bridge: RCTBridge) -> URL? {
self.bundleURL()
}
override func customize(_ rootView: RCTRootView) {
super.customize(rootView)
RNBootSplash.initWithStoryboard("BootSplash", rootView: rootView)
}
override func bundleURL() -> URL? {
#if DEBUG
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}
Previous AppDelegate.mm (Original - Before Swift Conversion)
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <Firebase.h>
#import "RNSplashScreen.h"
#import <FBSDKCoreKit/FBSDKCoreKit-swift.h>
#import "Orientation.h"
#import <React/RCTLinkingManager.h>
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"Fin1";
self.dependencyProvider = [RCTAppDependencyProvider new];
if ([FIRApp defaultApp] == nil) {
NSString *googleServiceInfofilePath = @"";
#if DEV
googleServiceInfofilePath = [[NSBundle mainBundle] pathForResource:@"GoogleServices-Info-Dev" ofType:@"plist"];
#else
googleServiceInfofilePath = [[NSBundle mainBundle] pathForResource:@"GoogleServices-Info" ofType:@"plist"];
#endif
[FIRApp configure];
}
[FBSDKApplicationDelegate.sharedInstance initializeSDK];
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self bundleURL];
}
- (NSURL *)bundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [Orientation getOrientation];
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
// - (BOOL)application:(UIApplication *)application
// openURL:(NSURL *)url
// options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
// // Add any custom logic here.
// return [[FBSDKApplicationDelegate sharedInstance]application:application
// openURL:url
// options:options];
// }
@endmetro.config.js
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const {
wrapWithReanimatedMetroConfig,
} = require('react-native-reanimated/metro-config');
/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('@react-native/metro-config').MetroConfig}
*/
const config = {};
const mergedConfig = mergeConfig(getDefaultConfig(__dirname), config);
module.exports = wrapWithReanimatedMetroConfig(mergedConfig);Podfile
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/scripts/react_native_pods.rb",
{paths: [process.argv[1]]},
)', __dir__]).strip
platform :ios, 15.5
prepare_react_native_project!
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
project 'Fin1',
'Dev.Debug' => :debug,
'Dev.Release' => :release
target 'Fin1' do
config = use_native_modules!
use_frameworks! :linkage => :static
$RNFirebaseAsStaticFramework = true
use_react_native!(
:path => config[:reactNativePath],
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/..",
:fabric_enabled => true,
:hermes_enabled => true,
:new_arch_enabled => true
)
pod 'XCDYouTubeKit'
pod 'FBSDKCoreKit'
post_install do |installer|
react_native_post_install(
installer,
config[:reactNativePath],
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)
bitcode_strip_path = `xcrun --find bitcode_strip`.chop!
def strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
framework_path = File.join(Dir.pwd, framework_relative_path)
command = "#{bitcode_strip_path} #{framework_path} -r -o #{framework_path}"
puts "Stripping bitcode: #{command}"
system(command)
end
framework_paths = [
"Pods/VdoFramework/VdoFramework.xcframework/ios-arm64/VdoFramework.framework/VdoFramework"
]
framework_paths.each do |framework_relative_path|
strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
end
end
end
What I've Tried
- ✅ Verified Hermes is enabled in Podfile
- ✅ Cleaned build folder and reinstalled pods multiple times
- ✅ Verified Metro bundler is running and accessible
- ✅ Checked
chrome://inspect- no "Hermes React Native" target appears - ✅ Tried pressing
jin Metro terminal - no debugger opens - ✅ Verified app is built in Debug mode (Dev.Debug configuration)
- ✅ Both Mac and iPhone are on same WiFi network
- ✅ Manually configured bundler IP address via "Configure Bundler" in Dev Menu
- ❌ Still can't open debugger
Additional Context
- This issue started after upgrading from an earlier React Native version where debugging worked fine
- Android physical device debugging works perfectly with the same setup
- The Swift conversion was done carefully to match the Objective-C implementation
Questions
- Is there a known issue with React Native DevTools on iOS physical devices in 0.82.1?
- Could the Swift migration be causing debugger initialization issues?
- Are there additional configurations needed for physical device debugging in 0.82+?
Any help would be greatly appreciated! This is blocking our development workflow on iOS devices.
Metadata
Metadata
Assignees
Labels
No labels