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

Feature Request: Automatically Bundle Metro Bundler IP Address for Android #870

Open
hrastnik opened this issue Jan 23, 2025 · 5 comments
Open

Comments

@hrastnik
Copy link

Description

As a long-time React Native developer (7 years professionally), I’ve noticed a quality-of-life improvement that could greatly enhance the Android developer experience. Currently, when building for iOS, the IP address of the computer where the Metro Bundler is running gets bundled into the app automatically. This ensures the app can always find the bundler, even when disconnected from USB.

On Android, however, this process isn’t as smooth. If the USB cable gets disconnected (intentionally or accidentally), developers must manually shake the device to open the dev menu and enter the IP address. This process is tedious and error-prone, especially for newcomers who may not fully understand how the bundler communicates with the device. Often, they resort to rerunning yarn android or similar commands unnecessarily.

Proposal

I propose that Android should adopt the same behavior as iOS by bundling the local computer’s IP address into the app during the build process. Here’s how it could work:

When connected via USB, the app uses the localhost address through adb reverse (the current behavior).
If USB is disconnected, the app seamlessly falls back to the bundled IP address to communicate with the Metro Bundler over Wi-Fi.

Discussion points

I’d love to hear thoughts from the community and the React Native team on this idea. Are there potential challenges I might have overlooked? Would this align with the project’s goals and vision?

If the idea seems viable, I’m also open to contributing a pull request to implement this feature, with some guidance from the maintainers.

Thank you for considering this request!

@cortinico
Copy link
Member

This has been discussed yesterday on Bluesky here:
https://bsky.app/profile/cortini.co/post/3lgdeitzkqs2i

tl;dr: potentially doable but there are caveats like, what happens when the device changes network. Long story short, this is something Expo/Community CLI can include as part of their launch commands.

Also, I'd like to have folks from the DevX team (such as @huntie) chime in on this discussion as they're owning this workflow.

@hrastnik
Copy link
Author

When the device switches networks, it will behave similarly to iOS by losing its connection to the bundler. However, this scenario seems far less likely compared to the device being disconnected from the cable, whether accidentally or intentionally.

That said, I believe it’s possible to implement a solution that routes traffic via the cable when connected and falls back to IP when no cable is detected. This would provide the best of both worlds.

One idea I’ve considered, though it might verge on over-engineering, is for Metro to share its IP with the device. The device could store this information and use it if the localhost connection fails.

For example, Metro could add a header to its responses containing the IP address and port. The device could track the last IP it connected to and, if the localhost connection (over cable) fails, fall back to the stored IP.

This approach avoids hardcoding anything on the Android side and provides a dynamic fallback mechanism.

@shirakaba
Copy link

shirakaba commented Jan 24, 2025

Thanks for linking the thread! Great to have some common interest in this and another approach to consider.

Response to proposal

When connected via USB, the app uses the localhost address through adb reverse (the current behavior).
If USB is disconnected, the app seamlessly falls back to the bundled IP address to communicate with the Metro Bundler over Wi-Fi.

One idea I’ve considered, though it might verge on over-engineering, is for Metro to share its IP with the device. The device could store this information and use it if the localhost connection fails.

I don't think iOS bothers doing that kind of fallback, so any kind of fallback or switching may just be overcomplicating things. I think it just uses the LAN IP in all cases. Well, strictly, if the LAN IP was not found in the expected file $DEST/ip.txt, then it does fall back to localhost – but I mean to say that it doesn't do any sort of intelligent switching after that initial setup.

The advantage of connecting unconditionally to the LAN IP would be that I think you wouldn't need any special setup at all for connecting over Wi-Fi. You could freely disconnect and reconnect the USB cable, or use Wi-Fi exclusively, just like on iOS. Much easier for onboarding users, and simple at the implementation level, too.

Response to caveats

what happens when the device changes network

I think it's an acceptable pitfall, and on par with the iOS user experience anyway (which I would say is superior).

Although adb reverse may be more robust in theory, there have been 122 issues filed containing the term adb reverse tcp:8081 tcp:8081, showing that this is a common stumbling block for Android users.

If the device changes network, the user will quickly find something is wrong and may be able to work out that it was due to a network change. But if they can't connect in the first place, they may lose a lot of time and faith.

this is something Expo/Community CLI can include as part of their launch commands.

This is a fair point and probably perfectly viable, but possibly more work. Both CLIs have a run command and a start command. I often use the start command and then run via Android Studio instead of via CLI, so that I can debug native code. I am not sure whether the adb reverse command would get triggered or not if running via Android Studio instead of CLI.

Incidentally, it seems there was a previous discussion on this, though it fizzled out.

I think though, if iOS does it in Core, it would make sense to stay symmetrical and do it in React Native Android's core as well.

Summary

The iOS user experience is great for both USB and Wi-Fi and I think simply doing the same thing iOS does would be a great improvement for React Native Android users, especially first-time users.

@hrastnik
Copy link
Author

The iOS user experience is great for both USB and Wi-Fi and I think simply doing the same thing iOS does would be a great improvement for React Native Android users, especially first-time users.

It’s a solid proposal and definitely simplifies things for most users. That said, I do worry about edge cases where Wi-Fi isn’t reliable or available.

For instance, I’ve had older test devices that struggled with Wi-Fi, and loading the bundle over the network was way slower than using USB. There have also been times when I didn’t have Wi-Fi at all and needed to run a local project via cable, something that wouldn’t work as easily if IP was the default.

That said, I think this could be solved pretty neatly:

  • Default to the IP method for simplicity since it works well for most.
  • Offer an easy fallback, like a package.json script to run adb reverse tcp:8081 tcp:8081 and set the bundle location to localhost:8081 (we're only missing a simple way to set the bundle location via cli)

@huntie
Copy link
Collaborator

huntie commented Jan 24, 2025

High level feedback

Proposal sounds good. Specifically:

  • Doing the same thing iOS does (and no more). Network change is a discountable edge case.
  • But, we also need the additional USB → Wi-Fi fallback behaviour (@hrastnik's point is really valuable).

Taking this forward

We probably don't have capacity to prioritise this soon, so:

  • We'd strongly welcome any external PRs that adhere to this design.
  • I'd like to invite any further feedback/support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants