Skip to content

Commit

Permalink
Add inspector attach to RN Dev Menu (iOS)
Browse files Browse the repository at this point in the history
Reviewed By: Hypuk

Differential Revision: D6405831

fbshipit-source-id: ffecfbf85a35fad4d0c9a823c5e637a6b9e202ee
  • Loading branch information
pakoito authored and facebook-github-bot committed Dec 5, 2017
1 parent d71d28f commit de424cc
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
19 changes: 18 additions & 1 deletion React/DevSupport/RCTDevMenu.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@

#if RCT_DEV

#if RCT_ENABLE_INSPECTOR
#import "RCTInspectorDevServerHelper.h"
#endif

NSString *const RCTShowDevMenuNotification = @"RCTShowDevMenuNotification";

@implementation UIWindow (RCTDevMenu)
Expand Down Expand Up @@ -199,6 +203,14 @@ - (void)addItem:(RCTDevMenuItem *)item
[bridge reload];
}]];

if (devSettings.isNuclideDebuggingAvailable) {
[items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"Debug JS in Nuclide %@", @"\U0001F4AF"] handler:^{
#if RCT_ENABLE_INSPECTOR
[RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL withView: RCTPresentedViewController()];
#endif
}]];
}

if (!devSettings.isRemoteDebuggingAvailable) {
[items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Remote JS Debugger Unavailable" handler:^{
UIAlertController *alertController = [UIAlertController
Expand All @@ -209,7 +221,12 @@ - (void)addItem:(RCTDevMenuItem *)item
}]];
} else {
[items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{
return devSettings.isDebuggingRemotely ? @"Stop Remote JS Debugging" : @"Debug JS Remotely";
NSString *title = devSettings.isDebuggingRemotely ? @"Stop Remote JS Debugging" : @"Debug JS Remotely";
if (devSettings.isNuclideDebuggingAvailable) {
return [NSString stringWithFormat:@"%@ %@", title, @"\U0001F645"];
} else {
return title;
}
} handler:^{
devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely;
}]];
Expand Down
5 changes: 5 additions & 0 deletions React/DevSupport/RCTInspectorDevServerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#import <Foundation/Foundation.h>
#import <JavaScriptCore/JSBase.h>
#import <UIKit/UIKit.h>

#import <React/RCTDefines.h>

#if RCT_DEV
Expand All @@ -11,6 +13,9 @@
+ (void)connectForContext:(JSGlobalContextRef)context
withBundleURL:(NSURL *)bundleURL;
+ (void)disableDebugger;
+ (void)attachDebugger:(NSString *)owner
withBundleURL:(NSURL *)bundleURL
withView:(UIViewController *)view;
@end

#endif
55 changes: 50 additions & 5 deletions React/DevSupport/RCTInspectorDevServerHelper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#import <jschelpers/JSCWrapper.h>
#import <UIKit/UIKit.h>
#import <React/RCTLog.h>

#import "RCTDefines.h"
#import "RCTInspectorPackagerConnection.h"
Expand All @@ -12,16 +13,13 @@

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

static NSString *getDebugServerHost(NSURL *bundleURL)
static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
{
NSString *host = [bundleURL host];
if (!host) {
host = @"localhost";
}

// Inspector Proxy is run on a separate port (from packager).
NSNumber *port = @8082;

// this is consistent with the Android implementation, where http:// is the
// hardcoded implicit scheme for the debug server. Note, packagerURL
// technically looks like it could handle schemes/protocols other than HTTP,
Expand All @@ -32,14 +30,26 @@

static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
{
NSNumber *inspectorProxyPort = @8082;
NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
getDebugServerHost(bundleURL),
getServerHost(bundleURL, inspectorProxyPort),
escapedDeviceName,
escapedAppName]];
}

static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title)
{
NSNumber *metroBundlerPort = @8081;
NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@",
getServerHost(bundleURL, metroBundlerPort),
title,
escapedDeviceName,
escapedAppName]];
}

@implementation RCTInspectorDevServerHelper

Expand All @@ -54,6 +64,41 @@ static void sendEventToAllConnections(NSString *event)
}
}

static void displayErrorAlert(UIViewController *view, NSString *message) {
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
[view presentViewController:alert animated:YES completion:nil];
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2.5),
dispatch_get_main_queue(),
^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
}

+ (void)attachDebugger:(NSString *)owner
withBundleURL:(NSURL *)bundleURL
withView:(UIViewController *)view
{
NSURL *url = getAttachDeviceUrl(bundleURL, owner);

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"GET"];

__weak UIViewController *viewCapture = view;
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData *_Nullable data,
NSURLResponse *_Nullable response,
NSError *_Nullable error) {
UIViewController *viewCaptureStrong = viewCapture;
if (error != nullptr && viewCaptureStrong != nullptr) {
displayErrorAlert(viewCaptureStrong, @"The request to attach Nuclide couldn't reach Metro Bundler!");
}
}] resume];
}

+ (void)disableDebugger
{
sendEventToAllConnections(kDebuggerMsgDisable);
Expand Down
1 change: 1 addition & 0 deletions React/Modules/RCTDevSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
@property (nonatomic, readonly) BOOL isHotLoadingAvailable;
@property (nonatomic, readonly) BOOL isLiveReloadAvailable;
@property (nonatomic, readonly) BOOL isRemoteDebuggingAvailable;
@property (nonatomic, readonly) BOOL isNuclideDebuggingAvailable;

This comment has been minimized.

Copy link
@chirag04

chirag04 Dec 5, 2017

Contributor

is nuclide the official debugger now? looks odd to have nuclide specific code here in RN. cc @shergin @hramos

This comment has been minimized.

Copy link
@shergin

shergin Dec 5, 2017

Contributor

IDK cc @pakoito

This comment has been minimized.

Copy link
@pakoito

pakoito Dec 5, 2017

Author Contributor

We're currently experimenting internally with better integration with Nuclide. If something comes out of it, we'll make sure to let you know!

This comment has been minimized.

Copy link
@shergin

shergin Dec 8, 2017

Contributor

@pakoito That's cool!
Sorry for n00b question, but how deeply is it tight to Nuclide specific internals? Can we share/open this debugging API for all, to make, let's say, developing VisualStudio Code debugger possible?

This comment has been minimized.

Copy link
@pakoito

pakoito Dec 12, 2017

Author Contributor

It's too early to tell right now as we're focusing exclusively on Nuclide integration.

@property (nonatomic, readonly) BOOL isJSCSamplingProfilerAvailable;

/**
Expand Down
9 changes: 9 additions & 0 deletions React/Modules/RCTDevSettings.mm
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ - (id)settingForKey:(NSString *)key
return [_dataSource settingForKey:key];
}

- (BOOL)isNuclideDebuggingAvailable
{
#if RCT_ENABLE_INSPECTOR
return true;
#else
return false;
#endif //RCT_ENABLE_INSPECTOR
}

- (BOOL)isRemoteDebuggingAvailable
{
Class jsDebuggingExecutorClass = objc_lookUpClass("RCTWebSocketExecutor");
Expand Down

0 comments on commit de424cc

Please sign in to comment.