Archives for : November2009

Revealed: “Next Exit”

Two months ago, in Bringing Your Own Maps, I went off on an atypical excursion into the realms of location-based applications and how an iPhone developer would need to license data from providers to develop apps that provide turn-by-turn directions or other routing and location-based search functionality.

That was your hint that I was up to something.

Today, spurred by the AppsFire App Star awards and its requirement of a public YouTube demo, I’m revealing the project I’ve been working on for the past two months: Next Exit.

As I’ve been blurbing it:

Next Exit is the safe, sane way to find gas, food, and lodging along US highways, with a no-fuss, one-thumb interface

Allow me to explain further:

Why Do I Need a Special-Purpose Map App?

To pin down why I wrote this app, I’ll go back to a Summer trip to California with the family. We were driving back from Disneyland to San Diego and needed to get something for the insanely picky kids to eat. As it turns out, California doesn’t have those blue “services at the next exit” signs that are common elsewhere in the country (well, in every state between Michigan and Florida, at least). I-5 also had no billboards in this stretch. So, short of actually managing to see the elusive Taco Bell itself before passing the exit, there was no practical way to figure out where to get off.

So, yeah, I did the obvious thing and searched the Maps application for “Taco Bell”. While driving. Not smart.

Screenshot 2009.11.29 14.25.05

This sucks for a couple of reasons… the most obvious being the driver distraction and the vastly increased likelihood you’ll crash into someone or something while fussing with the phone. But even if you do manage to send off a search, the results are sub-optimal: it will search where you are, not where you’re going, meaning it’s just as likely that you’ll get results five miles off your current route, or even behind you, as it is likely to find results that you can actually use.

Most people on long freeway drives want services that are right there on the highway. This means a search needs to be a lot smarter:

  • Figure out what road the user is on and what way he or she is going
  • Figure out where that road goes
  • Find exits along that road
  • Find services of certain types within a certain distance of those exits

Next Exit is the app that provides that kind of search.

Let’s Watch the Video

At this point, let me point you to the video demo that I prepared for the App Star contest. They wanted something around 30 seconds, which I submitted as the short version, but this longer version is still under a minute and shows off more stuff:


Gee, That Doesn’t Look So Hard

This is an app that looks simple but is actually quite complex underneath. If you read the original “Bringing Your Own Maps” post, you’ll recall that the iPhone OS’ “Map Kit” provides visuals for maps, but doesn’t actually have any location data behind it. A diagonal line marked “Market St.” is just that – a bunch of pixels, and nothing more. To have any concept of streets, you need to go to third-party map services. On the iPhone, this is compounded by the fact that your code needs to be in C/Obj-C, while most of the mapping APIs are written for the popular server-side scripting languages, or JavaScript (which speaks to the larger point that the mapping companies see their developer audience as web developers, not embedded or desktop developers). The only thing that’s really practical on the iPhone is a webservice or other network-oriented API that can be called from Cocoa Touch’s networking classes. The downside: lots of XML parsing on the receiving end.

Then there’s an even deeper question of how you even solve this problem. The mapping APIs are largely written from the point of view of “given a starting point and a destination, find a route.” But the question posed by this app is “given a starting point and a direction, find potential destinations.” My initial version searched ahead for exits, drawing lines between the furthest ones to account for turns in the road, but could get thrown off when the current highway meets another, as the other highway’s exits onto the current highway ended up in the search results and weren’t practical to remove. In the end, I developed a complex but more reliable system of finding road segments for the current freeway, arranging them to create a path, and then searching this path for exits. I’ll be writing more about this geo-logic in future updates.

Oh, and remember: I don’t have the luxury of doing these searches on a local database. This is all back-and-forth with MapQuest’s web server, swapping and parsing XML.

MapQuest? Really?

The location data is provided by MapQuest, under a commercial license. Why them? It helps that they replied to my initial request for licensing terms (unlike some of the other companies in this space). But perhaps more importantly, MapQuest’s entire API is accessible via their web-based XML protocol, which is slowly being supplanted by a set of equally powerful web services. By comparison, a lot of the good stuff in Google Maps is only practical with JavaScript — they have an HTTP API, but it has big holes — which perhaps suits their web-centric view of the world, but doesn’t help the embedded developer.

Also, MapQuest seems eager to work with developers and to understand the iPhone App Store market. They brought an engineer to a sales call with me, and he helped me figure out the find-and-arrange-segments logic that cured the early prototypes’ tendency to turn off onto unrelated interstates. So far, I’m really liking working with them.

So When Does It Go On Sale?

I have one more major task to account for: in-app purchase. Since the use of the MapQuest service will create an ongoing cost for however long copies of the app remain in use, a free or one-time payment model is not going to work. A subscription model is more appropriate: pay as you go, stop paying if you stop using it.

The elaborate, turn-by-turn, singing-and-dancing apps like Tom Tom and Navigon are going for $100. Next Exit does a lot less – by design – and therefore should cost less. So I’m keeping it impulse-worthy:

  • $1.99 for the app and three months of service
  • $4.99 for each 12 months of service thereafter

Folks, that’s less than the cost of an upsized value meal… and with Next Exit, you’ll be able to find the road-side restaurants with the value meals you like, not the ones you’ll just settle for!

Anyways, with hopes of finishing in-app purchase (and an audit-trail server on my end… groan), finalizing things with MapQuest, and getting things through the App Store review process in the next few weeks, I’ve got a fighting chance of getting this out before people hit the roads for the holiday travel season. Or, if it comes out after Christmas, there’ll just be that many more new iPhones in play, looking for useful apps.

More, much more, to follow. For now, fingers are crossed that the Apps Star jury will like what they see. The prize in their contest is free publicity… exactly what a new app needs!

Work Song

It’s not like I don’t have better things to do, but on the verge of sending a build to testers, and knowing I would probably forget to update the version number sooner or later, I set about putting a build date into my Xcode project. And for fun, I did it one better.

First off, the build date is pretty easy. Open up your project’s targets and right-click to do an “Add → New Build Phase → New Run Script Build Phase”. Under the Target, you’ll see a gray box called “Run Script”. Drag this to the top of the list of build phases – we want to do this step first – and do a Cmd-I to bring up its inspector. By default, scripts run with /bin/sh, which is fine. For the script body, just enter:

date > builddate.txt

Do a build and inspect your project’s directory to verify that the builddate.txt file got created. It’ll look like this:

Tue Nov 24 10:29:31 EST 2009

Assuming the file got created, drag the file to the “Resources” folder in your project. This will add a new item to the “Copy Bundle Resources” build phase, which is exactly what you want: the script will create the file, and then the copy phase will copy the file to your bundle. You probably don’t want to source control builddate.txt, since it’ll be created as part of the build (of course, if you don’t, anyone who checks out your project will see those files in red, since they’re missing, until they kick off a build).

Now it’s easy in code to get the contents of this file into your GUI or wherever else you need it (in my case, this code is in the “about” view controller’s viewDidLoad:):

buildDateLabel.text = [NSString stringWithFormat:@ "Built on %@", 
	[NSString stringWithContentsOfFile:
		[[NSBundle mainBundle] pathForResource:@"builddate" ofType:@"txt"]
	encoding: NSUTF8StringEncoding error:nil]];

Oh, but that’s not enough. I decided it was necessary to also let my testers know what tunes they should be listening to. So I added the following AppleScript file (inspired by Erik Rasmussen’s) to the project:

set track_name to ""
set track_artist to ""
tell application "iTunes"
		if not (exists current track) then return "(nothing playing)"
		set track_name to (get name of current track)
		set track_artist to (get artist of current track)
	end try
end tell
set build_tune to track_artist & " - " & track_name

The script’s return value is a string with the artist name and the song name, with a separator. If you call the script from the shell, it’s trivial to then dump the returned string into a file. So, create another Run Script Build Phase (you might want to rename these phases from the generic “Run Script”, BTW). This time, the script is:

/usr/bin/osascript iTunesTrackReader.scpt > itunestrack.txt

Again, drag this build phase before the Copy Bundle Resources phase. Once you’ve done a build, the itunestrack.txt file will exist, and you should copy it to the Resources folder, so it will get copied into your app bundle.

In the code, the “artist – song” string got a little wide on the phone, so I used a two-line label and replaced the separator with a new-line:

NSString *twoLineString = [[NSString stringWithContentsOfFile:
	[[NSBundle mainBundle] pathForResource:@"itunestrack" ofType:@"txt"]
	encoding: NSUTF8StringEncoding error:nil]
	stringByReplacingOccurrencesOfString: @" - " withString: @" -n"];
iTunesLabel.text = twoLineString;

And here’s the result (click for full-size):

Screen shot 2009-11-24 at 10.28.00 AM

OK, probably could have made better use of two hours, but it’s checked in now. Plus, it’s like an automated version-naming system: “are you running the “American Idiot” build or the “Kind of Blue” build?”