Skip to content

Commit

Permalink
Add "Open Debugger" and "Open React DevTools" to iOS dev menu
Browse files Browse the repository at this point in the history
Summary:
This diff introduces a new "Open Debugger" menu item for VMs that support on device debugging and for opening the React DevTools in Flipper. Provided so that we don't drift too far from the Android code.

Changelog: [Internal]

Reviewed By: RSNara

Differential Revision: D20784270

fbshipit-source-id: 6bb16431d25a6c093a583e2e041b8cffa6765ddd
  • Loading branch information
rickhanlonii authored and facebook-github-bot committed Apr 16, 2020
1 parent 1908d50 commit a9bac17
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 22 deletions.
60 changes: 48 additions & 12 deletions React/CoreModules/RCTDevMenu.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@
#import <React/RCTLog.h>
#import <React/RCTReloadCommand.h>
#import <React/RCTUtils.h>

#import "CoreModulesPlugins.h"

#if RCT_DEV_MENU

#if RCT_ENABLE_INSPECTOR
#import <React/RCTInspectorDevServerHelper.h>
#endif
Expand Down Expand Up @@ -221,13 +219,59 @@ - (void)setDefaultJSBundle
}]];

if (!devSettings.isProfilingEnabled) {
if (!devSettings.isRemoteDebuggingAvailable) {
#if RCT_ENABLE_INSPECTOR
if (devSettings.isDeviceDebuggingAvailable) {
// For on-device debugging we link out to Flipper.
// Since we're assuming Flipper is available, also include the DevTools.
// Note: For parity with the Android code.

// Reset the old debugger setting so no one gets stuck.
// TODO: Remove in a few weeks.
if (devSettings.isDebuggingRemotely) {
devSettings.isDebuggingRemotely = false;
}
[items addObject:[RCTDevMenuItem
buttonItemWithTitleBlock:^NSString * {
return @"Open Debugger";
}
handler:^{
[RCTInspectorDevServerHelper
openURL:@"flipper://null/Hermesdebuggerrn?device=React%20Native"
withBundleURL:bridge.bundleURL
withErrorMessage:@"Failed to open Flipper. Please check that Metro is runnning."];
}]];

[items addObject:[RCTDevMenuItem
buttonItemWithTitleBlock:^NSString * {
return @"Open React DevTools";
}
handler:^{
[RCTInspectorDevServerHelper
openURL:@"flipper://null/React?device=React%20Native"
withBundleURL:bridge.bundleURL
withErrorMessage:@"Failed to open Flipper. Please check that Metro is runnning."];
}]];
} else if (devSettings.isRemoteDebuggingAvailable) {
#else
if (devSettings.isRemoteDebuggingAvailable) {
#endif
// For remote debugging, we open up Chrome running the app in a web worker.
// Note that this requires async communication, which will not work for Turbo Modules.
[items addObject:[RCTDevMenuItem
buttonItemWithTitleBlock:^NSString * {
return devSettings.isDebuggingRemotely ? @"Stop Debugging" : @"Debug with Chrome";
}
handler:^{
devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely;
}]];
} else {
// If neither are available, we're defaulting to a message that tells you about remote debugging.
[items
addObject:[RCTDevMenuItem
buttonItemWithTitle:@"Debugger Unavailable"
handler:^{
NSString *message = RCTTurboModuleEnabled()
? @"Debugging is not currently supported when TurboModule is enabled."
? @"Debugging with Chrome is not supported when TurboModules are enabled."
: @"Include the RCTWebSocket library to enable JavaScript debugging.";
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:@"Debugger Unavailable"
Expand All @@ -246,14 +290,6 @@ - (void)setDefaultJSBundle
animated:YES
completion:NULL];
}]];
} else {
[items addObject:[RCTDevMenuItem
buttonItemWithTitleBlock:^NSString * {
return devSettings.isDebuggingRemotely ? @"Stop Debugging" : @"Debug";
}
handler:^{
devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely;
}]];
}
}

Expand Down
2 changes: 1 addition & 1 deletion React/CoreModules/RCTDevSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
@property (nonatomic, readonly) BOOL isHotLoadingAvailable;
@property (nonatomic, readonly) BOOL isLiveReloadAvailable;
@property (nonatomic, readonly) BOOL isRemoteDebuggingAvailable;
@property (nonatomic, readonly) BOOL isNuclideDebuggingAvailable;
@property (nonatomic, readonly) BOOL isDeviceDebuggingAvailable;
@property (nonatomic, readonly) BOOL isJSCSamplingProfilerAvailable;

/**
Expand Down
2 changes: 1 addition & 1 deletion React/CoreModules/RCTDevSettings.mm
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ - (id)settingForKey:(NSString *)key
return [_dataSource settingForKey:key];
}

- (BOOL)isNuclideDebuggingAvailable
- (BOOL)isDeviceDebuggingAvailable
{
#if RCT_ENABLE_INSPECTOR
return self.bridge.isInspectable;
Expand Down
1 change: 1 addition & 0 deletions React/DevSupport/RCTInspectorDevServerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

+ (RCTInspectorPackagerConnection *)connectWithBundleURL:(NSURL *)bundleURL;
+ (void)disableDebugger;
+ (void)openURL:(NSString *)url withBundleURL:(NSURL *)bundleURL withErrorMessage:(NSString *)errorMessage;
@end

#endif
41 changes: 33 additions & 8 deletions React/DevSupport/RCTInspectorDevServerHelper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@

static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";

static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
static NSString *getServerHost(NSURL *bundleURL)
{
NSNumber *port = @8081;
NSString *portStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
if (portStr && [portStr length] > 0) {
port = [NSNumber numberWithInt:[portStr intValue]];
}

NSString *host = [bundleURL host];
if (!host) {
host = @"localhost";
Expand All @@ -34,21 +40,19 @@

static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
{
NSNumber *inspectorProxyPort = @8081;
NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) {
inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]];
}
NSString *escapedDeviceName = [[[UIDevice currentDevice] name]
stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier]
stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
getServerHost(bundleURL, inspectorProxyPort),
getServerHost(bundleURL),
escapedDeviceName,
escapedAppName]];
}

static NSURL *getOpenUrlEndpoint(NSURL *bundleURL)
{
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/open-url", getServerHost(bundleURL)]];
}
@implementation RCTInspectorDevServerHelper

RCT_NOT_IMPLEMENTED(-(instancetype)init)
Expand All @@ -62,6 +66,27 @@ static void sendEventToAllConnections(NSString *event)
}
}

+ (void)openURL:(NSString *)url withBundleURL:(NSURL *)bundleURL withErrorMessage:(NSString *)errorMessage
{
NSURL *endpoint = getOpenUrlEndpoint(bundleURL);

NSDictionary *jsonBodyDict = @{@"url" : url};
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:endpoint];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:jsonBodyData];

[[[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(
__unused NSData *_Nullable data, __unused NSURLResponse *_Nullable response, NSError *_Nullable error) {
if (error != nullptr) {
RCTLogWarn(@"%@", errorMessage);
}
}] resume];
}

+ (void)disableDebugger
{
sendEventToAllConnections(kDebuggerMsgDisable);
Expand Down

0 comments on commit a9bac17

Please sign in to comment.