Archive for October 19, 2007

OpenStreetMap on the iPhone!

The iPhone is amazing. And the Maps application is pretty special. Only problem with it is that Google Maps is the only available data source. Well I’ve just been working on that. Now, there’s OpenStreetMap on the iPhone

OSM Central London on the iPhone
OSM Isle of Wight on the IPhone

These are screenshots of OpenStreetMap tiles, viewed in the native iPhone Maps application. Wooooooo

How you can do it

So it’s pretty easy to try it out. You’ll need to have jailbreak’d your phone (I used iBrickr, there’s plenty of other methods out there, even for 1.1.1). Download the maps tile cache db, and copy it over to your phone, using scp or whatever. The tile cache db is about 30 MB, so please only download if you’re going to try it. Also, I’ve had the Maps App crash occasionally when browsing the Maps, though nothing fatal .. so use at your own risk.


download http://brainoff.com/media/LondonZ17.sqlitedb

cp to /var/root/Library/Caches/MapTiles/MapTiles.sqlitedb on your phone

restart your phone

How its done

My first idea was to modify the configuration or constant that the Maps App used for constructing Google Maps tile requests. Andrew helped with decompiling and pointers to other files, but we had no luck as yet. But looking at the app or at the GMM module in a hex editor, there appeared to be SQL inserts of tile pointers .. perhaps Maps was using a database to cache requested tiles. Searching through the filesystem found MapTiles.sqlitedb. That db has just two tables..


sqlite> .schema
CREATE TABLE images(zoom int, x int, y int, flags int, length int, data blob);
CREATE TABLE version(version int);
CREATE INDEX index1 on images (zoom,x,y,flags);

images was simply storing the zoom, x, and y of each tile. flags was set to ’2′ for street maps, ’3′ for aerial imagery. length appeared to be the size of the data blob. And data was the png. So simply adding new rows to this table, with OpenStreetMap tiles rather than Google, would have the Map app using OSM.

I needed to grab a bunch of OSM tiles. Asked on #osm, and Almien helpfully contributed a script to download all tiles on a zoom level within a bbox.

And I needed to easily insert BLOBs of the tile pngs into the sqlite db. This sqlite tutorial had just the right code, eatblob.c. I wrote a script which walked through the directory of downloaded tiles, and insert each one into a copy of MapTiles.sqlitedb. All of central London at zoom 18 took a while to download and insert, and came out at 60 MB.

Actually, there’s nothing particularly OSM about this method. Could download Yahoo or Multimap or yea Google tiles, and stuff them into the cache db.

Issues

There are the crashes I mentioned. Haven’t debugged this yet, but I figure this is surmountable. Perhaps the file size of the tiles are too large.

The Maps App zoom levels are off by one. What it calls zoom level 13, are actually being tiled as if it was zoom level 14.
(zoom off by 1). Perhaps the tiles on the iPhone are half the width and height of normal tiles? I haven’t looked into this and its late, so I don’t even know if that’s a plausible explanation.

There’s still a little Google logo in the lower left corner, need to replace that too!

Last thing, don’t know how the cache is refreshed. It’s not going to grow without bound — when and why are things expired from the cache?

Other Methods

There are probably better ways to do this. One would be to modify the Map.app binary, or whatever module or library or configuration file that stores the url or ip address used when constructing requests for Google Maps tiles, and modifying that to request directly from OSM. Or write a provider independent version of the Map App — tiling seems to be part of a core library in the phone, it looks like Safari uses the same stuff to zoom in and out on web pages. If anyone starts looking into this, drop me a line.

Comments (14)