1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | #import <React/RCTInspectorDevServerHelper.h>
|
9 |
|
10 | #if RCT_DEV
|
11 |
|
12 | #import <React/RCTLog.h>
|
13 | #import <UIKit/UIKit.h>
|
14 |
|
15 | #import <React/RCTDefines.h>
|
16 | #import <React/RCTInspectorPackagerConnection.h>
|
17 |
|
18 | static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";
|
19 |
|
20 | static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
|
21 | {
|
22 | NSString *host = [bundleURL host];
|
23 | if (!host) {
|
24 | host = @"localhost";
|
25 | }
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | return [NSString stringWithFormat:@"%@:%@", host, port];
|
33 | }
|
34 |
|
35 | static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
|
36 | {
|
37 | NSNumber *inspectorProxyPort = @8081;
|
38 | NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
|
39 | if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) {
|
40 | inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]];
|
41 | }
|
42 | NSString *escapedDeviceName = [[[UIDevice currentDevice] name]
|
43 | stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
|
44 | NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier]
|
45 | stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
|
46 | return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
|
47 | getServerHost(bundleURL, inspectorProxyPort),
|
48 | escapedDeviceName,
|
49 | escapedAppName]];
|
50 | }
|
51 |
|
52 | static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title)
|
53 | {
|
54 | NSNumber *metroBundlerPort = @8081;
|
55 | NSString *metroBundlerPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
|
56 | if (metroBundlerPortStr && [metroBundlerPortStr length] > 0) {
|
57 | metroBundlerPort = [NSNumber numberWithInt:[metroBundlerPortStr intValue]];
|
58 | }
|
59 | NSString *escapedDeviceName = [[[UIDevice currentDevice] name]
|
60 | stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
|
61 | NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier]
|
62 | stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
|
63 | return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@",
|
64 | getServerHost(bundleURL, metroBundlerPort),
|
65 | title,
|
66 | escapedDeviceName,
|
67 | escapedAppName]];
|
68 | }
|
69 |
|
70 | @implementation RCTInspectorDevServerHelper
|
71 |
|
72 | RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
73 |
|
74 | static NSMutableDictionary<NSString *, RCTInspectorPackagerConnection *> *socketConnections = nil;
|
75 |
|
76 | static void sendEventToAllConnections(NSString *event)
|
77 | {
|
78 | for (NSString *socketId in socketConnections) {
|
79 | [socketConnections[socketId] sendEventToAllConnections:event];
|
80 | }
|
81 | }
|
82 |
|
83 | static void displayErrorAlert(UIViewController *view, NSString *message)
|
84 | {
|
85 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
|
86 | message:message
|
87 | preferredStyle:UIAlertControllerStyleAlert];
|
88 | [view presentViewController:alert animated:YES completion:nil];
|
89 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2.5), dispatch_get_main_queue(), ^{
|
90 | [alert dismissViewControllerAnimated:YES completion:nil];
|
91 | });
|
92 | }
|
93 |
|
94 | + (void)attachDebugger:(NSString *)owner withBundleURL:(NSURL *)bundleURL withView:(UIViewController *)view
|
95 | {
|
96 | NSURL *url = getAttachDeviceUrl(bundleURL, owner);
|
97 |
|
98 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
99 | [request setHTTPMethod:@"GET"];
|
100 |
|
101 | __weak UIViewController *viewCapture = view;
|
102 | [[[NSURLSession sharedSession]
|
103 | dataTaskWithRequest:request
|
104 | completionHandler:^(
|
105 | __unused NSData *_Nullable data, __unused NSURLResponse *_Nullable response, NSError *_Nullable error) {
|
106 | UIViewController *viewCaptureStrong = viewCapture;
|
107 | if (error != nullptr && viewCaptureStrong != nullptr) {
|
108 | displayErrorAlert(viewCaptureStrong, @"The request to attach Nuclide couldn't reach Metro!");
|
109 | }
|
110 | }] resume];
|
111 | }
|
112 |
|
113 | + (void)disableDebugger
|
114 | {
|
115 | sendEventToAllConnections(kDebuggerMsgDisable);
|
116 | }
|
117 |
|
118 | + (RCTInspectorPackagerConnection *)connectWithBundleURL:(NSURL *)bundleURL
|
119 | {
|
120 | NSURL *inspectorURL = getInspectorDeviceUrl(bundleURL);
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | if (socketConnections == nil) {
|
126 | socketConnections = [NSMutableDictionary new];
|
127 | }
|
128 |
|
129 | NSString *key = [inspectorURL absoluteString];
|
130 | RCTInspectorPackagerConnection *connection = socketConnections[key];
|
131 | if (!connection || !connection.isConnected) {
|
132 | connection = [[RCTInspectorPackagerConnection alloc] initWithURL:inspectorURL];
|
133 | socketConnections[key] = connection;
|
134 | [connection connect];
|
135 | }
|
136 |
|
137 | return connection;
|
138 | }
|
139 |
|
140 | @end
|
141 |
|
142 | #endif
|