views:

67

answers:

5

I'm working on some iPhone apps that communicate with an HTTP-based API server (which happens to be Rails, but that's irrelevant here), and oftentimes I've been bitten by the IP (un)reachability from the iPhone device to my MacBook Pro - the iPhone device must hit the URLs on the MBP.

Right now, I have something like this in Config.h:

#if (TARGET_IPHONE_SIMULATOR)
// for iPhone Simulator
#define API_BASE  @"http://127.0.0.1:3000/api"
#else
// for iPhone Device
#define API_BASE  @"http://10.0.0.1:3000/api"
#endif

It works fine, as long as: 1. you work by yourself, 2. or you have full control over the DHCP server, 3. or you can work only with the iPhone simulator and use the loopback address (that is, without push notification or in-app purchase).

But I work remotely with other people, often from cafes or libraries, so it bothers me a lot - now I have to manually find my MBP's assigned IP address, rewrite the above constant API_BASE from "10.0.0.1" to the new address, and not forget to revert to the original before committing to git or svn.

Is there any ways to programatically get the IP address of the development machine from inside Xcode and send it to the iPhone device on a per-build basis?

UPDATE

Using Bonjour is not enough because every machine in the team has a different name.

A: 

You could use bonjour.

Seth
A: 

I usually build a form or control for editing the server address. The button for the form would only be available in debug builds (make it ugly and red so you don't ship it :-) ) then have it hidden in release builds.

abdollar
you enter the address on the iPhone? hmm I don't see why it's any better than rewriting the IP on Xcode...
kenn
if your server is on your laptop and you will always take it with you - then this is no better - but if you start hosting your server and have different servers for testing and production or you have a team of people. Anyway, it looks like its just you so I can see why you don't care.
abdollar
We work as a team, and we have one staging, one production, many development environments. We sure have staging/production specific constants as well, switching between environments using `ifdef`, but I omitted here because it's irrelevant (however it might be another interesting topic!). The point is, we work both on server/client at the same time, so each of us needs a local editable copy of the server/client code.
kenn
if everyone on your team has a local copy of the client and server - then you are right - its no better. If you have some client engineers that don't have servers then let them edit the address on a debug build of the client
abdollar
A: 

This is a classic way but modifying environ and getting it by using NSProcessInfo won't work?

sekimura
How do you integrate it and pass the host info to the iPhone?
kenn
+2  A: 

Since it's already a URL, you could use the hostname instead of the IP, and it'll be resolved with Bonjour. For example, the laptop I'm using to write this is called Jura, which means it has a Bonjour hostname of jura.local.

You can find out the Bonjour DNS name of your computer by heading to the Sharing preferences pane. Under computer name, there's a sentence that starts, "Computers on your local network..." and ends with the name you want to use.

Then you can change the above code to:

#define API_BASE  @"http://my-macbook-pro.local:3000/api"

because the same mechanism will resolve the URL in the simulator and on the device.

Graeme Mathieson
Thanks, it's definitely better than specifying IP address, but it doesn't work when you work in a team, as each computer has a different name.
kenn
+1  A: 

OK, so it needs to work with multiple development environments, which means Bonjour's not going to cut it.

I'm not terribly familiar with the XCode build environment. Can you set environment variables that are evaluated by a shell in some way? If you can somehow get the following evaluated:

DEV_IP_ADDRESS=$(/sbin/ifconfig |awk '/inet 127.0.0.1/ { next } /inet / { print $2; exit }')

then passed in as a preprocessor define:

gcc <...> -DDEV_IP_ADDRESS="${DEV_IP_ADDRESS}"

and, in the code:

#define API_BASE "http://" DEV_IP_ADDRESS ":3000/api"

(I'm rusty, but I dimly recall that the preprocessor concats consecutive strings, right?)

If you can join 'em up, that should do the trick. :-)

Or you can combine with bonjour to make the arcane hackery a little more bearable. Chances are $HOSTNAME is already defined in your environment, so if you can get that in as a preprocessor #define you're sorted.

Graeme Mathieson
Thanks again Graeme, it almost did! I set `-DDEV_IP_ADDRESS=\"${HOSTNAME}\"` in the "Other C Flags" (equals to OTHER_CFLAGS) section on the target setting, but somehow Xcode converted it to `-DDEV_IP_ADDRESS=\"\"` as I type that on in the dialog, which actually makes it a null string on the build. It seems like interacting with shell variable is not allowed on the UI? Related topic: http://lists.apple.com/archives/Xcode-users/2008/Sep/msg00062.html
kenn