Add inspector attach to RN Dev Menu (Android)

Reviewed By: Hypuk

Differential Revision: D6405828

fbshipit-source-id: 9274c3e8748e6ce259357836dde7d53c4fce9fbf
This commit is contained in:
Paco Estevez Garcia 2017-12-05 06:51:08 -08:00 committed by Facebook Github Bot
parent de424cc291
commit 7c7108a1e8
6 changed files with 88 additions and 4 deletions

View File

@ -37,6 +37,11 @@ public class ReactSettingsForTests implements DeveloperSettings {
return false; return false;
} }
@Override
public boolean isNuclideJSDebugEnabled() {
return false;
}
@Override @Override
public boolean isRemoteJSDebugEnabled() { public boolean isRemoteJSDebugEnabled() {
return false; return false;

View File

@ -14,6 +14,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.modules.debug.interfaces.DeveloperSettings; import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
import com.facebook.react.packagerconnection.PackagerConnectionSettings; import com.facebook.react.packagerconnection.PackagerConnectionSettings;
@ -124,6 +125,11 @@ public class DevInternalSettings implements
mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_KEY, enabled).apply(); mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_KEY, enabled).apply();
} }
@Override
public boolean isNuclideJSDebugEnabled() {
return ReactBuildConfig.IS_INTERNAL_BUILD && ReactBuildConfig.DEBUG;
}
@Override @Override
public boolean isRemoteJSDebugEnabled() { public boolean isRemoteJSDebugEnabled() {
return mPreferences.getBoolean(PREFS_REMOTE_JS_DEBUG_KEY, false); return mPreferences.getBoolean(PREFS_REMOTE_JS_DEBUG_KEY, false);

View File

@ -12,8 +12,10 @@ package com.facebook.react.devsupport;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.widget.Toast;
import com.facebook.common.logging.FLog; import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Assertions;
import com.facebook.react.R;
import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants; import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.network.OkHttpCallUtil; import com.facebook.react.common.network.OkHttpCallUtil;
@ -73,6 +75,7 @@ public class DevServerHelper {
private static final String PACKAGER_STATUS_URL_FORMAT = "http://%s/status"; private static final String PACKAGER_STATUS_URL_FORMAT = "http://%s/status";
private static final String HEAP_CAPTURE_UPLOAD_URL_FORMAT = "http://%s/jscheapcaptureupload"; private static final String HEAP_CAPTURE_UPLOAD_URL_FORMAT = "http://%s/jscheapcaptureupload";
private static final String INSPECTOR_DEVICE_URL_FORMAT = "http://%s/inspector/device?name=%s&app=%s"; private static final String INSPECTOR_DEVICE_URL_FORMAT = "http://%s/inspector/device?name=%s&app=%s";
private static final String INSPECTOR_ATTACH_URL_FORMAT = "http://%s/nuclide/attach-debugger-nuclide?title=%s&app=%s&device=%s";
private static final String SYMBOLICATE_URL_FORMAT = "http://%s/symbolicate"; private static final String SYMBOLICATE_URL_FORMAT = "http://%s/symbolicate";
private static final String OPEN_STACK_FRAME_URL_FORMAT = "http://%s/open-stack-frame"; private static final String OPEN_STACK_FRAME_URL_FORMAT = "http://%s/open-stack-frame";
@ -224,6 +227,36 @@ public class DevServerHelper {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
public void attachDebugger(final Context context, final String title) {
new AsyncTask<Void, String, Boolean>() {
@Override
protected Boolean doInBackground(Void... ignore) {
return doSync();
}
public boolean doSync() {
try {
String attachToNuclideUrl = getInspectorAttachUrl(title);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(attachToNuclideUrl).build();
client.newCall(request).execute();
return true;
} catch (IOException e) {
FLog.e(ReactConstants.TAG, "Failed to send attach request to Inspector", e);
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
if (!result) {
String message = context.getString(R.string.catalyst_debugjs_nuclide_failure);
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void symbolicateStackTrace( public void symbolicateStackTrace(
Iterable<StackFrame> stackFrames, Iterable<StackFrame> stackFrames,
final SymbolicationListener listener) { final SymbolicationListener listener) {
@ -321,6 +354,16 @@ public class DevServerHelper {
mPackageName); mPackageName);
} }
public String getInspectorAttachUrl(String title) {
return String.format(
Locale.US,
INSPECTOR_ATTACH_URL_FORMAT,
AndroidInfoHelpers.getServerHost(),
title,
mPackageName,
AndroidInfoHelpers.getFriendlyDeviceName());
}
public BundleDownloader getBundleDownloader() { public BundleDownloader getBundleDownloader() {
return mBundleDownloader; return mBundleDownloader;
} }

View File

@ -110,6 +110,9 @@ public class DevSupportManagerImpl implements
private static final String EXOPACKAGE_LOCATION_FORMAT private static final String EXOPACKAGE_LOCATION_FORMAT
= "/data/local/tmp/exopackage/%s//secondary-dex"; = "/data/local/tmp/exopackage/%s//secondary-dex";
public static final String EMOJI_HUNDRED_POINTS_SYMBOL = " \uD83D\uDCAF";
public static final String EMOJI_FACE_WITH_NO_GOOD_GESTURE = " \uD83D\uDE45";
private final Context mApplicationContext; private final Context mApplicationContext;
private final ShakeDetector mShakeDetector; private final ShakeDetector mShakeDetector;
private final BroadcastReceiver mReloadAppBroadcastReceiver; private final BroadcastReceiver mReloadAppBroadcastReceiver;
@ -395,16 +398,36 @@ public class DevSupportManagerImpl implements
LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>(); LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
/* register standard options */ /* register standard options */
options.put( options.put(
mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() { mApplicationContext.getString(R.string.catalyst_reloadjs),
new DevOptionHandler() {
@Override @Override
public void onOptionSelected() { public void onOptionSelected() {
handleReloadJS(); handleReloadJS();
} }
}); });
if (mDevSettings.isNuclideJSDebugEnabled()) {
// The concatenation is applied directly here because XML isn't emoji-friendly
String nuclideJsDebugMenuItemTitle =
mApplicationContext.getString(R.string.catalyst_debugjs_nuclide)
+ EMOJI_HUNDRED_POINTS_SYMBOL;
options.put(
nuclideJsDebugMenuItemTitle,
new DevOptionHandler() {
@Override
public void onOptionSelected() {
mDevServerHelper.attachDebugger(mApplicationContext, "ReactNative");
}
});
}
String remoteJsDebugMenuItemTitle =
mDevSettings.isRemoteJSDebugEnabled()
? mApplicationContext.getString(R.string.catalyst_debugjs_off)
: mApplicationContext.getString(R.string.catalyst_debugjs);
if (mDevSettings.isNuclideJSDebugEnabled()) {
remoteJsDebugMenuItemTitle += EMOJI_FACE_WITH_NO_GOOD_GESTURE;
}
options.put( options.put(
mDevSettings.isRemoteJSDebugEnabled() ? remoteJsDebugMenuItemTitle,
mApplicationContext.getString(R.string.catalyst_debugjs_off) :
mApplicationContext.getString(R.string.catalyst_debugjs),
new DevOptionHandler() { new DevOptionHandler() {
@Override @Override
public void onOptionSelected() { public void onOptionSelected() {

View File

@ -39,6 +39,11 @@ public interface DeveloperSettings {
*/ */
boolean isElementInspectorEnabled(); boolean isElementInspectorEnabled();
/**
* @return Whether Nuclide JS debugging is enabled.
*/
boolean isNuclideJSDebugEnabled();
/** /**
* @return Whether remote JS debugging is enabled. * @return Whether remote JS debugging is enabled.
*/ */

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="catalyst_reloadjs" project="catalyst" translatable="false">Reload</string> <string name="catalyst_reloadjs" project="catalyst" translatable="false">Reload</string>
<string name="catalyst_debugjs_nuclide" project="catalyst" translatable="false">Debug JS in Nuclide</string>
<string name="catalyst_debugjs_nuclide_failure" project="catalyst" translatable="false">The request to attach Nuclide could not reach Metro Bundler!</string>
<string name="catalyst_debugjs" project="catalyst" translatable="false">Debug JS Remotely</string> <string name="catalyst_debugjs" project="catalyst" translatable="false">Debug JS Remotely</string>
<string name="catalyst_debugjs_off" project="catalyst" translatable="false">Stop Remote JS Debugging</string> <string name="catalyst_debugjs_off" project="catalyst" translatable="false">Stop Remote JS Debugging</string>
<string name="catalyst_hot_module_replacement" project="catalyst" translatable="false">Enable Hot Reloading</string> <string name="catalyst_hot_module_replacement" project="catalyst" translatable="false">Enable Hot Reloading</string>