Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject dev machine IP on Android and improve error message when connection fails #49166

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/react-native/ReactAndroid/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import com.facebook.react.tasks.internal.utils.*
import de.undercouch.gradle.tasks.download.Download
import java.nio.file.Paths
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.net.NetworkInterface
import java.net.Inet4Address

plugins {
id("maven-publish")
Expand Down Expand Up @@ -467,6 +469,14 @@ fun enableWarningsAsErrors(): Boolean {
return value?.toString()?.toBoolean() ?: false
}

fun getHostIpAddress(): String =
NetworkInterface.getNetworkInterfaces().asSequence()
.filter { it.isUp && !it.isLoopback }
.flatMap { it.inetAddresses.asSequence() }
.filter { it is Inet4Address && !it.isLoopbackAddress }
.map { it.hostAddress }
.firstOrNull() ?: "127.0.0.1"

val packageReactNdkLibsForBuck by
tasks.registering(Copy::class) {
dependsOn("mergeDebugNativeLibs")
Expand Down Expand Up @@ -523,6 +533,7 @@ android {
buildConfigField("int", "EXOPACKAGE_FLAGS", "0")
buildConfigField("boolean", "UNSTABLE_ENABLE_FUSEBOX_RELEASE", "false")
buildConfigField("boolean", "ENABLE_PERFETTO", "false")
buildConfigField("String", "REACT_NATIVE_DEV_SERVER_IP", "\"${getHostIpAddress()}\"")

resValue("integer", "react_native_dev_server_port", reactNativeDevServerPort())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import android.graphics.Typeface;
import android.hardware.SensorManager;
import android.os.Build;
import android.text.InputType;
import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
Expand Down Expand Up @@ -62,6 +64,8 @@
import com.facebook.react.devsupport.interfaces.StackFrame;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
import com.facebook.react.modules.systeminfo.AndroidInfoHelpers;
import com.facebook.react.packagerconnection.PackagerConnectionSettings;
import com.facebook.react.packagerconnection.RequestHandler;
import java.io.File;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -376,24 +380,91 @@ public void onOptionSelected() {
return;
}

final EditText input = new EditText(context);
input.setHint("localhost:8081");
PackagerConnectionSettings settings = mDevSettings.getPackagerConnectionSettings();
final String currentHost = settings.getDebugServerHost();
settings.setDebugServerHost("");
final String defaultHost = settings.getDebugServerHost();
settings.setDebugServerHost(currentHost);

LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
int paddingSmall = (int) (4 * context.getResources().getDisplayMetrics().density);
int paddingLarge = (int) (16 * context.getResources().getDisplayMetrics().density);
layout.setPadding(paddingLarge, paddingLarge, paddingLarge, paddingLarge);

AlertDialog bundleLocationDialog =
final TextView label = new TextView(context);
label.setText(mApplicationContext.getString(R.string.catalyst_change_bundle_location_input_label));
label.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));

final EditText input = new EditText(context);
// This makes it impossible to enter a newline in the input field
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setHint(mApplicationContext.getString(R.string.catalyst_change_bundle_location_input_hint));
input.setBackgroundResource(android.R.drawable.edit_text);
input.setHintTextColor(0xFFCCCCCC);
input.setTextColor(0xFF000000);
input.setText(currentHost);

final Button defaultHostSuggestion = new Button(context);
defaultHostSuggestion.setText(defaultHost);
defaultHostSuggestion.setTextSize(12);
defaultHostSuggestion.setAllCaps(false);
defaultHostSuggestion.setOnClickListener(v -> input.setText(defaultHost));

final Button localhostSuggestion = new Button(context);
localhostSuggestion.setText("localhost:8081");
localhostSuggestion.setTextSize(12);
localhostSuggestion.setAllCaps(false);
localhostSuggestion.setOnClickListener(v -> input.setText("localhost:8081"));

LinearLayout suggestionRow = new LinearLayout(context);
suggestionRow.setOrientation(LinearLayout.HORIZONTAL);
suggestionRow.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
));
suggestionRow.addView(defaultHostSuggestion);
suggestionRow.addView(localhostSuggestion);

final TextView instructions = new TextView(context);
instructions.setText(mApplicationContext.getString(R.string.catalyst_change_bundle_location_instructions, AndroidInfoHelpers.getAdbReverseTcpCommand(mApplicationContext)));
final LinearLayout.LayoutParams instructionsParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
instructionsParams.setMargins(0, paddingSmall, 0, paddingLarge);
instructions.setLayoutParams(instructionsParams);

final Button applyChangesButton = new Button(context);
applyChangesButton.setText(mApplicationContext.getString(R.string.catalyst_change_bundle_location_apply));

final Button cancelButton = new Button(context);
cancelButton.setText(mApplicationContext.getString(R.string.catalyst_change_bundle_location_cancel));

layout.addView(label);
layout.addView(input);
layout.addView(suggestionRow);
layout.addView(instructions);
layout.addView(applyChangesButton);
layout.addView(cancelButton);

final AlertDialog bundleLocationDialog =
new AlertDialog.Builder(context)
.setTitle(mApplicationContext.getString(R.string.catalyst_change_bundle_location))
.setView(input)
.setPositiveButton(
android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String host = input.getText().toString();
mDevSettings.getPackagerConnectionSettings().setDebugServerHost(host);
handleReloadJS();
}
})
.setView(layout)
.create();

applyChangesButton.setOnClickListener(v -> {
String host = input.getText().toString();
mDevSettings.getPackagerConnectionSettings().setDebugServerHost(host);
handleReloadJS();
bundleLocationDialog.dismiss();
});
cancelButton.setOnClickListener(v -> {
bundleLocationDialog.dismiss();
});

bundleLocationDialog.show();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package com.facebook.react.modules.systeminfo
import android.content.Context
import android.os.Build
import com.facebook.common.logging.FLog
import com.facebook.react.BuildConfig
import com.facebook.react.R
import java.io.BufferedReader
import java.io.InputStreamReader
Expand Down Expand Up @@ -92,7 +93,7 @@ public object AndroidInfoHelpers {
getMetroHostPropValue().isNotEmpty() -> getMetroHostPropValue()
isRunningOnGenymotion() -> GENYMOTION_LOCALHOST
isRunningOnStockEmulator() -> EMULATOR_LOCALHOST
else -> DEVICE_LOCALHOST
else -> BuildConfig.REACT_NATIVE_DEV_SERVER_IP
}
return String.format(Locale.US, "%s:%d", ipAddress, port)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ loadScriptFromAssets(AAssetManager* manager, const std::string& assetName) {
}

throw std::runtime_error(folly::to<std::string>(
"Unable to load script. Make sure you're "
"either running Metro (run 'npx react-native start') or that your bundle '",
assetName,
"' is packaged correctly for release."));
"Unable to load script.\n\n"
"Make sure you're running Metro ('npx react-native start') or that your "
"bundle '", assetName, "' is packaged correctly for release.\n\n"
"The device must be on the same WiFi as your laptop to connect to Metro.\n\n"
"To use USB instead, shake the device to open the dev menu and set "
"the bundler location to \"localhost:8081\" and run:\n"
" adb reverse tcp:8081 tcp:8081"));
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
<string name="catalyst_reload" project="catalyst" translatable="false">Reload</string>
<string name="catalyst_reload_error" project="catalyst" translatable="false">Failed to load bundle. Try restarting the bundler or reconnecting your device.</string>
<string name="catalyst_change_bundle_location" project="catalyst" translatable="false">Change Bundle Location</string>
<string name="catalyst_change_bundle_location_input_label" project="catalyst" translatable="false">Provide a custom bundler address and port:</string>
<string name="catalyst_change_bundle_location_input_hint" project="catalyst" translatable="false">127.0.0.1:8081</string>
<string name="catalyst_change_bundle_location_instructions" project="catalyst" translatable="false">If you experience slow reloads or unstable network connection, you can route data via USB cable instead of WiFi:\n 1. Connect your device via USB\n 2. Set the bundle location to `localhost:8081`\n 3. Run this command in your terminal:\n&#160;&#160;&#160;&#160;&#160;&#160;`%1$s`</string>
<string name="catalyst_change_bundle_location_apply" project="catalyst" translatable="false">Apply Changes</string>
<string name="catalyst_change_bundle_location_cancel" project="catalyst" translatable="false">Cancel</string>
<string name="catalyst_open_debugger_error" project="catalyst" translatable="false">Failed to open DevTools. Please check that the dev server is running and reload the app.</string>
<string name="catalyst_debug_open" project="catalyst" translatable="false">Open DevTools</string>
<string name="catalyst_debug_open_disabled" project="catalyst" translatable="false">Connect to the bundler to debug JavaScript</string>
Expand Down