12

When testing iPhone apps that connect to my local machine's server, I need to enter my computer's local IP address as opposed to localhost in order to test with devices other than the simulator. This gets annoying with dynamic IP addresses and when multiple developers are testing. Is there a code snippet that can get the IP address of the computer that is compiling code, and NOT the IP the address of the device that the application is running on (preferably in C or Objective-C, and not Swift)?

mverderese
  • 5,314
  • 6
  • 27
  • 36
  • look http://stackoverflow.com/questions/6807788/how-to-get-ip-address-of-iphone-programatically – websky Jan 29 '15 at 15:42
  • @websky this is to get the IP address of the device running the application, not the computer that compiled the application, correct? – mverderese Jan 29 '15 at 15:44
  • Which IP address? Macs are multi homing. – uchuugaka Jan 30 '15 at 05:37
  • @uchuugaka the router's local ipv4 address such as `192.168.1.10` – mverderese Jan 30 '15 at 19:03
  • Right my point is it's an easy assumption that there's one possible address. If the code is going to be used elsewhere conditions can be different. Some network devices will reassign addresses such as when the connection uses DHCP it may seem constant but can change unexpectedly – uchuugaka Jan 31 '15 at 00:54
  • Good point. The script run in the Xcode build phase could be setup to match a specific expected ip format (such as only ips in the 192.168.0.0/16 subnet). Sure this may not work for every person, but it would definitely be a good place to start. – mverderese Jan 31 '15 at 01:01

3 Answers3

11

1) Add a "Run Script" in the "Build Phases" tab of your Xcode project that contains this:

export SERVER_IP=`ipconfig getifaddr en0`

Note: change "en0" to whichever interface matches your machine. en0 is the wifi on my machine and my hard-wire is en3. Do an "ifconfig -a" in Terminal to get the list of all of your adapters and see which is which for your machine

2) Go to your project file. Click the Project itself in the left menu then Build Settings in the right side. Go to "Apple LLVM 6.0 - Custom Compiler Flags". Under "Other C Flags" -> "Debug" define a new value called -DSERVER_IP=${SERVER_IP}

This will map your build script's results into a #DEFINE in your project

3) In your code use SERVER_IP just like you would any other #DEFINE and it will always have the value of the computer that built the code.

Chris Morse
  • 326
  • 1
  • 9
  • This is very close to what I'm looking for but I'm running into a small problem. First I had to put the "Run Script" phase before the "Compile Sources" phase so that the macro is there before compile time, but when I try to build I'm getting this error: `Script-272AC20F1A7A8F7A00E654B7.sh: line 2: export: `=192.168.1.10': not a valid identifier` – mverderese Jan 29 '15 at 16:20
  • Sorry! Typo on my part... I shouldn't have put the $ in the SERVER_IP name. I've editing by original answer to correct that. – Chris Morse Jan 30 '15 at 04:49
  • 1
    No worries! Getting closer but still having an issue. The script phase builds successfully, but this code segment `+(NSString*)appServerUrlPrefix {return SERVER_IP;}` results in `Non-void method 'appServerUrlPrefix' should return a value`. I have `-DSERVER_IP=${SERVER_IP}` under "DEBUG" for "Other C Flags". `NSLog(@"SERVER_IP: %@", SERVER_IP);` results in `Expected expression` error. Thanks again for the help! – mverderese Jan 30 '15 at 19:00
  • Does `SERVER_IP` change colors in Xcode? If so, the compiler is seeing the #DEFINE definition. Now the hard(er) part. That's not going to be a NSString, it'll be a cstring. So you need to either construct a NSString from that Cstring. (Look at +stringFromCString:encoding) or see if you can change the `-DSERVER_IP=\`${SERVER_IP}\`` to `-DSERVER_IP=@\`${SERVER_IP}\`` or something like that. – Chris Morse Jan 30 '15 at 19:56
  • Yes, the `SERVER_IP` changes to the orange marco color, but `NSString *string = [NSString stringWithCString:SERVER_IP encoding:NSUTF16StringEncoding]; NSLog(@"String: %@", string);` results in `Use of undeclared identifier 'encoding'` and `NSLog(@"String: %s", SERVER_IP);` results in `Expected expression`. It seems like the macro exists, but is not formatted correctly or something. I even tried changing it to `-DLOCAL_SERVER_IP=${SERVER_IP}` thinking it maybe a scope issue with `SERVER_IP` but got the same results. – mverderese Jan 30 '15 at 20:14
  • I just realized what's wrong (but I'm not near an Xcode where I can test it...) The quotes are missing! Try `-DSERVER_IP="\`${SERVER_IP}\`"` You may need to try escaping the quotes with \. – Chris Morse Jan 31 '15 at 02:18
  • 1
    What version of Xcode are you guys running? This doesn't work at all for me. Each run script phase executes in a separate shell. To prove it I created two Run Script phases. The first runs "echo mypid: $$" the next runs "echo mypid2: $$; exit 1". The print out shows two separate pids, which means env vars cant be used between the phases. I'm using Xcode 6.3 – David Apr 10 '15 at 15:55
  • I just tried with Xcode 5.1.1 and it doesn't work there either – David Apr 10 '15 at 16:06
  • How do I call/use SERVER_IP value from a Swift file? I actually set it up in Swift Other Flags under Build Settings – denis_lor Jan 28 '19 at 11:16
9

I got this working by having a run script set the computer's IP address in the app's plist, then reading the plist value in code.

1) In your Info.plist file, add a key/value pair that will contain your computer's IP address. For this example, we'll add a key of "CompanyNameDevServerIP", of type "String". Note that this key/value pair should be prefixed uniquely, so that it doesn't conflict with Apple's keys (see here for more info).

2) In the "Build Phases" tab, add a run script that contains the following:

if [ "$CONFIGURATION" == "Debug" ]; then
  echo -n ${TARGET_BUILD_DIR}/${INFOPLIST_PATH} | xargs -0 /usr/libexec/PlistBuddy -c "Set :CompanyNameDevServerIP `ipconfig getifaddr en0`"
else
  echo -n ${TARGET_BUILD_DIR}/${INFOPLIST_PATH} | xargs -0 /usr/libexec/PlistBuddy -c "Delete :CompanyNameDevServerIP"
fi

This sets the computer's IP address in the plist that gets bundled with the build, but only in debug builds. (It's removed from the plist file in release builds.)

  • Hat tip to this blog post for providing this technique.
  • You may need to use a different interface other than en0 (see here for more info).

3) In code, retrieve this plist value to get your computer's IP address:

NSString *serverIP = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CompanyNameDevServerIP"];
Community
  • 1
  • 1
Jed Lau
  • 326
  • 1
  • 3
  • 9
  • 1
    FYI... If you have upgraded to Xcode 10, the new build system has broken this solution. (PlistBuddy can't find the Info.plist for some reasons). A workaround is to stay with the Legacy Build System under File/Workspace Settings. – Billy Sep 19 '18 at 19:41
  • @Billy Do I have to switch my entire project to Legacy Build System just to make it work? – denis_lor Jan 28 '19 at 14:07
  • I haven't tried using different build systems for different projects in the same workspace. My intuition would be: you just need the legacy build system for the project that contains the code in Step 3). – Billy Jan 30 '19 at 02:02
  • No, it will not work. I am using Xcode 11 and the new build system. This will fail in step 2 itself throwing 'info.plist not found' error because of the above mentioned reason. – Divyanshu Juneja Jan 22 '20 at 09:40
  • I'm not sure why you're invoking your PlistBuddy command through echo | xargs, you can simply pass the plist's path to the command : /usr/libexec/PlistBuddy -c "Add :CompanyNameDevServerIP string `ipconfig getifaddr en0`" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" – Guillaume Laurent Mar 05 '21 at 23:19
1

If you need this at compile time, you can just add a "Run Script" in the "Build Phases" tab of your Xcode project. Putting this into the source code will naturally return the IP address of where the code is running, not where it was built.

This script will return the primary IP address. You can modify the script to edit a Plist or whatever you need from there. PlistBuddy works well for modifying plist files at build time.

ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
picciano
  • 22,341
  • 9
  • 69
  • 82