Overview

There are three types of application builds we need to do for React Native development: debug, debug on target device, and production. As React Native is currently set up, you need to edit your AppDelegate.m file to switch between these three.

If you have done any kind of development beyond running your app in an iOS simulator, you are familiar with this bit of the AppDelegate.m file for your project:

The localhost URL in “OPTION 1” is fine until you try to debug your application on a physical device. Then the URL has to be changed to the IP address of your development host machine before you build and run. Depending on the version of React Native you are using in your project, you may have to change that URL back to localhost to debug in the simulator again.

When you want to build a production version of your app, you need to change your product scheme to Production and edit your AppDelegate.m to enable OPTION 2.

It’s a bit messier when you have a laptop and use it while out and about so it’s IP address changes dynamically. Similarly, if you are working with a team of people, each of them have systems with differing IP addresses and everyone editing the AppDelegate.m file is sure to cause conflicts and hassles.

Surely there is a better way.

Andrew Phillipo posted his solution on GitHub here: https://github.com/facebook/react-native/issues/4245. The solution presented here is inspired by his effort, and should automate and fix this issue with Native React.

In this gist, I have made a couple of improvements to Andrew’s Run Script:

First, there was only one PLISTCMD in his version, the one on line 5 in my version. When I tried to do a build with his Run Script, I got an error, “SERVER_IP” does not exist. In my version, I first attempt to ADD the SERVER_IP value (lines 3–4) and then attempt to set the SERVER_IP value (lines 5–6) in the project’s Info.plist file. Note the “|| true” at the end of lines 4 and 6 — this prevents the script from aborting on the failure of either PlistBuddy command. The command line to determine your development machine’s current IP is within the $() on lines 3 and 5 — you can copy and paste this into a terminal to verify it works:

$ ifconfig | grep inet\ | tail -1 | cut -d “ “ -f 2

Second, I replaced the entire OPTION 1 vs OPTION 2 logic in AppDelegate.m with preprocessor directives to generate the proper option based upon your actual IP address. See this gist:

Third, I fixed the logic in RTWebSocketExecutor.m in React Native to use the IP address we set in the Run Script. The code for setting up the WebSocket is buried in the React Native core source, and it is hardcoded to localhost:8081. This breaks debugging in chrome while executing on a physical device. My fix solves this issue. See this gist:

Step by step instructions

Until the changes are made to React Native, you can follow these instructions to fix your projects to benefit from these proposed changes.

We will be editing the two files indicated on the left. We will be adding a Run Script in the Build Phases.

Step 1: Add Run Script

Click on the plus sign indicated in the screenshot above. Select “New Run Script Phase” from the popup menu.

The Run Script appears at the end of the Build Phase items list:

Click on the arrow to open it.

In the code block, we’re going to copy from the first gist I presented and paste it verbatim.

Step 2: Edit AppDelegate.m

For your convenience, the code to add to AppDelegate.m is in the second gist above.

Note: I used #if 0 … #endif to remove the original code. I left it in the source file for reference.

Also note the #warning for DEBUG DEVICE is hit — this is because I have selected my iPhone as the build target.

If I choose one of the simulators as target, the #warning for DEBUG SIMULATOR is hit:

To build a production version, I select my phone as target again and then I select Product -> Scheme -> Edit Scheme:

On the dialog that pops up, select Run on the left and set Build Configuration to Release:

In AppDelegate.m, the #warning for PRODUCTION DEVICE is hit.

Step 3: Fix the hardcodedhard coded URL in RCTWebSocketExecutor.m

Note that I commented out the original return statement and get the proper IP from the plist file, similar logic as was added to AppDelegate.m. The code for this init function is in the third gist above.

Conclusion

These trivial changes should improve your workflow when using React Native. It is especially effective if you develop on more than one machine or are part of a team. You will no longer be required to frequently edit the AppDelegate.m file for the three build scenarios. The number of merge conflicts you experience should be fewer since this file won’t be edited to contain per-user custom IP addresses.

If you like this work and want to see it become part of React Native, let the team know by commenting on the issue here: https://github.com/facebook/react-native/issues/4245.