Allow launching inspector from dev menu
Reviewed By: davidaurelio Differential Revision: D4095356 fbshipit-source-id: 46e43578cdcd663316efb82dffde27b77294c5c0
This commit is contained in:
parent
18184a83f1
commit
f571d28e68
|
@ -19,6 +19,16 @@ public class Inspector {
|
||||||
|
|
||||||
private final HybridData mHybridData;
|
private final HybridData mHybridData;
|
||||||
|
|
||||||
|
public static boolean isSupported() {
|
||||||
|
try {
|
||||||
|
// This isn't a very nice way to do this but it works :|
|
||||||
|
instance().getPagesNative();
|
||||||
|
return true;
|
||||||
|
} catch (UnsatisfiedLinkError e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Page> getPages() {
|
public static List<Page> getPages() {
|
||||||
try {
|
try {
|
||||||
return Arrays.asList(instance().getPagesNative());
|
return Arrays.asList(instance().getPagesNative());
|
||||||
|
|
|
@ -162,6 +162,12 @@ public class DevServerHelper {
|
||||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void openInspector(String id) {
|
||||||
|
if (mInspectorPackagerConnection != null) {
|
||||||
|
mInspectorPackagerConnection.sendOpenEvent(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void closeInspectorConnection() {
|
public void closeInspectorConnection() {
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -42,6 +42,7 @@ import com.facebook.infer.annotation.Assertions;
|
||||||
import com.facebook.react.R;
|
import com.facebook.react.R;
|
||||||
import com.facebook.react.bridge.CatalystInstance;
|
import com.facebook.react.bridge.CatalystInstance;
|
||||||
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
||||||
|
import com.facebook.react.bridge.Inspector;
|
||||||
import com.facebook.react.bridge.JavaJSExecutor;
|
import com.facebook.react.bridge.JavaJSExecutor;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
|
@ -358,6 +359,19 @@ public class DevSupportManagerImpl implements DevSupportManager, PackagerCommand
|
||||||
handleReloadJS();
|
handleReloadJS();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (Inspector.isSupported()) {
|
||||||
|
options.put(
|
||||||
|
"Debug JS on-device (experimental)", new DevOptionHandler() {
|
||||||
|
@Override
|
||||||
|
public void onOptionSelected() {
|
||||||
|
List<Inspector.Page> pages = Inspector.getPages();
|
||||||
|
if (pages.size() > 0) {
|
||||||
|
// TODO: We should get the actual page id instead of the first one.
|
||||||
|
mDevServerHelper.openInspector(String.valueOf(pages.get(0).getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
options.put(
|
options.put(
|
||||||
mDevSettings.isReloadOnJSChangeEnabled()
|
mDevSettings.isReloadOnJSChangeEnabled()
|
||||||
? mApplicationContext.getString(R.string.catalyst_live_reload_off)
|
? mApplicationContext.getString(R.string.catalyst_live_reload_off)
|
||||||
|
|
|
@ -48,6 +48,15 @@ public class InspectorPackagerConnection {
|
||||||
mConnection.close();
|
mConnection.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendOpenEvent(String pageId) {
|
||||||
|
try {
|
||||||
|
JSONObject payload = makePageIdPayload(pageId);
|
||||||
|
sendEvent("open", payload);
|
||||||
|
} catch (JSONException | IOException e) {
|
||||||
|
FLog.e(TAG, "Failed to open page", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleProxyMessage(JSONObject message)
|
void handleProxyMessage(JSONObject message)
|
||||||
throws JSONException, IOException {
|
throws JSONException, IOException {
|
||||||
String event = message.getString("event");
|
String event = message.getString("event");
|
||||||
|
|
|
@ -8,31 +8,16 @@
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
var execFile = require('child_process').execFile;
|
const execFile = require('child_process').execFile;
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var opn = require('opn');
|
const path = require('path');
|
||||||
var path = require('path');
|
const launchChrome = require('../util/launchChrome');
|
||||||
|
|
||||||
function getChromeAppName() {
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'darwin':
|
|
||||||
return 'google chrome';
|
|
||||||
case 'win32':
|
|
||||||
return 'chrome';
|
|
||||||
default:
|
|
||||||
return 'google-chrome';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchChromeDevTools(port) {
|
function launchChromeDevTools(port) {
|
||||||
var debuggerURL = 'http://localhost:' + port + '/debugger-ui';
|
var debuggerURL = 'http://localhost:' + port + '/debugger-ui';
|
||||||
console.log('Launching Dev Tools...');
|
console.log('Launching Dev Tools...');
|
||||||
opn(debuggerURL, {app: [getChromeAppName()]}, function(err) {
|
launchChrome(debuggerURL);
|
||||||
if (err) {
|
|
||||||
console.error('Google Chrome exited with error:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapePath(path) {
|
function escapePath(path) {
|
||||||
|
@ -77,7 +62,7 @@ module.exports = function(options, isChromeConnected) {
|
||||||
// TODO: Remove this case in the future
|
// TODO: Remove this case in the future
|
||||||
console.log(
|
console.log(
|
||||||
'The method /launch-chrome-devtools is deprecated. You are ' +
|
'The method /launch-chrome-devtools is deprecated. You are ' +
|
||||||
' probably using an application created with an older CLI with the ' +
|
' probably using an application created with an older CLI with the ' +
|
||||||
' packager of a newer CLI. Please upgrade your application: ' +
|
' packager of a newer CLI. Please upgrade your application: ' +
|
||||||
'https://facebook.github.io/react-native/docs/upgrading.html');
|
'https://facebook.github.io/react-native/docs/upgrading.html');
|
||||||
launchDevTools(options, isChromeConnected);
|
launchDevTools(options, isChromeConnected);
|
||||||
|
|
|
@ -46,6 +46,7 @@ const parseUrl = require('url').parse;
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
const debug = require('debug')('ReactNativePackager:InspectorProxy');
|
const debug = require('debug')('ReactNativePackager:InspectorProxy');
|
||||||
|
const launchChrome = require('./launchChrome');
|
||||||
|
|
||||||
type DevicePage = {
|
type DevicePage = {
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -80,6 +81,10 @@ type DisconnectEvent = Message<'disconnect', {
|
||||||
pageId?: string,
|
pageId?: string,
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
type OpenEvent = Message<'open', {
|
||||||
|
pageId?: string,
|
||||||
|
}>;
|
||||||
|
|
||||||
type GetPages = Message<'getPages', ?Array<DevicePage>>;
|
type GetPages = Message<'getPages', ?Array<DevicePage>>;
|
||||||
|
|
||||||
type Event = WrappedEvent | ConnectEvent | DisconnectEvent | GetPages;
|
type Event = WrappedEvent | ConnectEvent | DisconnectEvent | GetPages;
|
||||||
|
@ -178,6 +183,8 @@ class Device {
|
||||||
this._handleWrappedEvent(message);
|
this._handleWrappedEvent(message);
|
||||||
} else if (message.event === 'disconnect') {
|
} else if (message.event === 'disconnect') {
|
||||||
this._handleDisconnect(message);
|
this._handleDisconnect(message);
|
||||||
|
} else if (message.event === 'open') {
|
||||||
|
this._handleOpen(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +204,13 @@ class Device {
|
||||||
this._removeConnection(pageId);
|
this._removeConnection(pageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_handleOpen(event: OpenEvent) {
|
||||||
|
const payload = nullthrows(event.payload);
|
||||||
|
const pageId = nullthrows(payload.pageId);
|
||||||
|
const url = DEVTOOLS_URL_BASE + makeInspectorPageUrl(this._id, pageId);
|
||||||
|
launchChrome(url);
|
||||||
|
}
|
||||||
|
|
||||||
_removeConnection(pageId: string) {
|
_removeConnection(pageId: string) {
|
||||||
const socket = this._connections.get(pageId);
|
const socket = this._connections.get(pageId);
|
||||||
if (socket) {
|
if (socket) {
|
||||||
|
@ -229,10 +243,7 @@ class InspectorProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
_makePage(server: Address, deviceId: string, deviceName: string, devicePage: DevicePage): Page {
|
_makePage(server: Address, deviceId: string, deviceName: string, devicePage: DevicePage): Page {
|
||||||
// The inspector frontend doesn't handle urlencoded params so we
|
const wsUrl = makeInspectorPageUrl(deviceId, devicePage.id);
|
||||||
// manually urlencode it and decode it on the other side in _createPageHandler
|
|
||||||
const query = querystring.escape(`device=${deviceId}&page=${devicePage.id}`);
|
|
||||||
const wsUrl = `localhost:${server.port}/inspector/page?${query}`;
|
|
||||||
return {
|
return {
|
||||||
id: `${deviceId}-${devicePage.id}`,
|
id: `${deviceId}-${devicePage.id}`,
|
||||||
title: devicePage.title,
|
title: devicePage.title,
|
||||||
|
@ -393,6 +404,13 @@ function escapeHtmlSpecialChar(char: string): string {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeInspectorPageUrl(deviceId: string, pageId: string): string {
|
||||||
|
// The inspector frontend doesn't handle urlencoded params so we
|
||||||
|
// manually urlencode it and decode it on the other side in _createPageHandler
|
||||||
|
const query = querystring.escape(`device=${deviceId}&page=${pageId}`);
|
||||||
|
return `localhost:8081/inspector/page?${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
function attachToServer(server: http.Server, pathPrefix: string): InspectorProxy {
|
function attachToServer(server: http.Server, pathPrefix: string): InspectorProxy {
|
||||||
const proxy = new InspectorProxy();
|
const proxy = new InspectorProxy();
|
||||||
proxy.attachToServer(server, pathPrefix);
|
proxy.attachToServer(server, pathPrefix);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const opn = require('opn');
|
||||||
|
|
||||||
|
function getChromeAppName(): string {
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'darwin':
|
||||||
|
return 'google chrome';
|
||||||
|
case 'win32':
|
||||||
|
return 'chrome';
|
||||||
|
default:
|
||||||
|
return 'google-chrome';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchChrome(url: string) {
|
||||||
|
opn(url, {app: [getChromeAppName()]}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('Google Chrome exited with error:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = launchChrome;
|
Loading…
Reference in New Issue