Skip to content

Commit f571d28

Browse files
lexsFacebook Github Bot
authored andcommitted
Allow launching inspector from dev menu
Reviewed By: davidaurelio Differential Revision: D4095356 fbshipit-source-id: 46e43578cdcd663316efb82dffde27b77294c5c0
1 parent 18184a8 commit f571d28

File tree

7 files changed

+102
-26
lines changed

7 files changed

+102
-26
lines changed

ReactAndroid/src/main/java/com/facebook/react/bridge/Inspector.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ public class Inspector {
1919

2020
private final HybridData mHybridData;
2121

22+
public static boolean isSupported() {
23+
try {
24+
// This isn't a very nice way to do this but it works :|
25+
instance().getPagesNative();
26+
return true;
27+
} catch (UnsatisfiedLinkError e) {
28+
return false;
29+
}
30+
}
31+
2232
public static List<Page> getPages() {
2333
try {
2434
return Arrays.asList(instance().getPagesNative());

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ protected Void doInBackground(Void... params) {
162162
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
163163
}
164164

165+
public void openInspector(String id) {
166+
if (mInspectorPackagerConnection != null) {
167+
mInspectorPackagerConnection.sendOpenEvent(id);
168+
}
169+
}
170+
165171
public void closeInspectorConnection() {
166172
new AsyncTask<Void, Void, Void>() {
167173
@Override

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.facebook.react.R;
4343
import com.facebook.react.bridge.CatalystInstance;
4444
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
45+
import com.facebook.react.bridge.Inspector;
4546
import com.facebook.react.bridge.JavaJSExecutor;
4647
import com.facebook.react.bridge.ReactContext;
4748
import com.facebook.react.bridge.ReadableArray;
@@ -358,6 +359,19 @@ public void onOptionSelected() {
358359
handleReloadJS();
359360
}
360361
});
362+
if (Inspector.isSupported()) {
363+
options.put(
364+
"Debug JS on-device (experimental)", new DevOptionHandler() {
365+
@Override
366+
public void onOptionSelected() {
367+
List<Inspector.Page> pages = Inspector.getPages();
368+
if (pages.size() > 0) {
369+
// TODO: We should get the actual page id instead of the first one.
370+
mDevServerHelper.openInspector(String.valueOf(pages.get(0).getId()));
371+
}
372+
}
373+
});
374+
}
361375
options.put(
362376
mDevSettings.isReloadOnJSChangeEnabled()
363377
? mApplicationContext.getString(R.string.catalyst_live_reload_off)

ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorPackagerConnection.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ public void closeQuietly() {
4848
mConnection.close();
4949
}
5050

51+
public void sendOpenEvent(String pageId) {
52+
try {
53+
JSONObject payload = makePageIdPayload(pageId);
54+
sendEvent("open", payload);
55+
} catch (JSONException | IOException e) {
56+
FLog.e(TAG, "Failed to open page", e);
57+
}
58+
}
59+
5160
void handleProxyMessage(JSONObject message)
5261
throws JSONException, IOException {
5362
String event = message.getString("event");

local-cli/server/middleware/getDevToolsMiddleware.js

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,16 @@
88
*/
99
'use strict';
1010

11-
var child_process = require('child_process');
12-
var execFile = require('child_process').execFile;
13-
var fs = require('fs');
14-
var opn = require('opn');
15-
var path = require('path');
16-
17-
function getChromeAppName() {
18-
switch (process.platform) {
19-
case 'darwin':
20-
return 'google chrome';
21-
case 'win32':
22-
return 'chrome';
23-
default:
24-
return 'google-chrome';
25-
}
26-
}
11+
const child_process = require('child_process');
12+
const execFile = require('child_process').execFile;
13+
const fs = require('fs');
14+
const path = require('path');
15+
const launchChrome = require('../util/launchChrome');
2716

2817
function launchChromeDevTools(port) {
2918
var debuggerURL = 'http://localhost:' + port + '/debugger-ui';
3019
console.log('Launching Dev Tools...');
31-
opn(debuggerURL, {app: [getChromeAppName()]}, function(err) {
32-
if (err) {
33-
console.error('Google Chrome exited with error:', err);
34-
}
35-
});
20+
launchChrome(debuggerURL);
3621
}
3722

3823
function escapePath(path) {
@@ -77,7 +62,7 @@ module.exports = function(options, isChromeConnected) {
7762
// TODO: Remove this case in the future
7863
console.log(
7964
'The method /launch-chrome-devtools is deprecated. You are ' +
80-
' probably using an application created with an older CLI with the ' +
65+
' probably using an application created with an older CLI with the ' +
8166
' packager of a newer CLI. Please upgrade your application: ' +
8267
'https://facebook.github.io/react-native/docs/upgrading.html');
8368
launchDevTools(options, isChromeConnected);

local-cli/server/util/inspectorProxy.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const parseUrl = require('url').parse;
4646
const WebSocket = require('ws');
4747

4848
const debug = require('debug')('ReactNativePackager:InspectorProxy');
49+
const launchChrome = require('./launchChrome');
4950

5051
type DevicePage = {
5152
id: string,
@@ -80,6 +81,10 @@ type DisconnectEvent = Message<'disconnect', {
8081
pageId?: string,
8182
}>;
8283

84+
type OpenEvent = Message<'open', {
85+
pageId?: string,
86+
}>;
87+
8388
type GetPages = Message<'getPages', ?Array<DevicePage>>;
8489

8590
type Event = WrappedEvent | ConnectEvent | DisconnectEvent | GetPages;
@@ -178,6 +183,8 @@ class Device {
178183
this._handleWrappedEvent(message);
179184
} else if (message.event === 'disconnect') {
180185
this._handleDisconnect(message);
186+
} else if (message.event === 'open') {
187+
this._handleOpen(message);
181188
}
182189
}
183190

@@ -197,6 +204,13 @@ class Device {
197204
this._removeConnection(pageId);
198205
}
199206

207+
_handleOpen(event: OpenEvent) {
208+
const payload = nullthrows(event.payload);
209+
const pageId = nullthrows(payload.pageId);
210+
const url = DEVTOOLS_URL_BASE + makeInspectorPageUrl(this._id, pageId);
211+
launchChrome(url);
212+
}
213+
200214
_removeConnection(pageId: string) {
201215
const socket = this._connections.get(pageId);
202216
if (socket) {
@@ -229,10 +243,7 @@ class InspectorProxy {
229243
}
230244

231245
_makePage(server: Address, deviceId: string, deviceName: string, devicePage: DevicePage): Page {
232-
// The inspector frontend doesn't handle urlencoded params so we
233-
// manually urlencode it and decode it on the other side in _createPageHandler
234-
const query = querystring.escape(`device=${deviceId}&page=${devicePage.id}`);
235-
const wsUrl = `localhost:${server.port}/inspector/page?${query}`;
246+
const wsUrl = makeInspectorPageUrl(deviceId, devicePage.id);
236247
return {
237248
id: `${deviceId}-${devicePage.id}`,
238249
title: devicePage.title,
@@ -393,6 +404,13 @@ function escapeHtmlSpecialChar(char: string): string {
393404
);
394405
}
395406
407+
function makeInspectorPageUrl(deviceId: string, pageId: string): string {
408+
// The inspector frontend doesn't handle urlencoded params so we
409+
// manually urlencode it and decode it on the other side in _createPageHandler
410+
const query = querystring.escape(`device=${deviceId}&page=${pageId}`);
411+
return `localhost:8081/inspector/page?${query}`;
412+
}
413+
396414
function attachToServer(server: http.Server, pathPrefix: string): InspectorProxy {
397415
const proxy = new InspectorProxy();
398416
proxy.attachToServer(server, pathPrefix);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @flow
10+
*/
11+
'use strict';
12+
13+
const opn = require('opn');
14+
15+
function getChromeAppName(): string {
16+
switch (process.platform) {
17+
case 'darwin':
18+
return 'google chrome';
19+
case 'win32':
20+
return 'chrome';
21+
default:
22+
return 'google-chrome';
23+
}
24+
}
25+
26+
function launchChrome(url: string) {
27+
opn(url, {app: [getChromeAppName()]}, function(err) {
28+
if (err) {
29+
console.error('Google Chrome exited with error:', err);
30+
}
31+
});
32+
}
33+
34+
module.exports = launchChrome;

0 commit comments

Comments
 (0)