Maps.appfor the iPhone, which not only scrolls, pans, and zooms properly, but is also a whole lot faster than the browser based version.
So I didn't really want to play with the browser based version of Google Maps on my iPod, I wanted to play with the mobile version. So the obvious thing to do would be to hack the mobile version of
Maps.appto support the Sky. It's just a different tile set, shouldn't be too hard?
There is nothing obvious in the plist files associated with the Maps application or the
GMM.frameworkitself, but this is only really to be expected. So I pulled out my hex editor of choice, I recommend Hex Fiend by the way, to see what I could be done. Initially, and unfortunately somewhat optimistically, I thought that it should just be a case of tracking down the strings containing the URLs where Maps pulls tiles from the remote server, and changing these to point to the Sky tile server instead. But after poking around for a while inside the
GMM.frameworkthis didn't look like it was going to be too easy, at least without decompiling the code. However I did discover references to a SQL database which the application was using as a tile cache for downloaded tiles. Pulling this database off the phone an into SQLLite on my desktop let me examine the schema, which has three separate tables,
images(zoom int, x int, y int, flags int, length int, data blob);
index1 on images (zoom,x,y,flags);
zwere self explanatory. That's just the
yposition of the tile at zoom level
z. The flags looks to be whether the tile is a map (flag is 2) or satellite (flag is 3) tile, the blob was presumably the tile itself and
lengthwas obviously the length of the binary blob in bytes. Probably...
The obvious strategy at this point was to download all the tiles, and yes, I mean all the tiles, from the Google Sky tile server, and poke them into the tile cache database in the appropriate places to fake out the
Maps.appapplication into thinking it didn't have to go to the web to download those tiles after all.
Oddly enough the maps tiles served by Google Maps for Sky are JPG files, and the maps tiles in the cache database are PNG files. The JPG's also seem to be 256×256 pixels in size, while the tiles in the cache file are 128×128 pixels in size. So we had a bit of an issue here. I could either take the thousands of downloaded tiles, convert them to PNG, and split them up into smaller tiles, or I could just try throwing them into the cache and see what happened. Want to take a guess at which one I chose to do first?
eatblob.cout of the SQLite tutorial, I hacked together a quick script to push all 5,461 tiles (zoom level 0 to zoom level 6) into the cache database. Copying the new enlarged database back onto my iPod, I restarted the iPod and fired up
Maps.appbut things didn't exactly go as planned. Predictably I didn't get the mapping between the
y's of the Sky tiles and the Map tiles quite right. In fact I got my
y's round the wrong way in one of my scripts. Second time was the charm though...
SMC in Google Maps on an Jailbroken iPod touch
Basically at this point I've got Google Maps for Sky working on my iPod touch under Firmware 1.1.2. This hack will presumably also work on the iPhone since my
Maps.appwas taken off a Jailbroken iPhone in the first place, after all my iPod touch didn't ship with the Maps application in the first place...
Despite all this there are still predictably some problems with the current implementation. First and foremost, the Sky map only occupies the upper left quarter of Earth map when zoomed out all the way out. The best explanation I can come up with for this is simply the fact I haven't yet cut my "big" tiles into quarters. If generate 4×(128×128) tiles out of each of my current 256×256 tiles at each of the current zoom levels then I reckon I'll fill the map.
Of course even with this solved there are two fundamental problems which means that this project is almost entirely an intellectual exercise. The current lack of zoom levels in the Sky data means than when you zoom in far enough you eventually drop back down onto the Earth. For instance the SMC is located somewhere over Marrakech, and if you zoom in far enough sub-Saharan Africa starts to poke through the star field. This could probably be lived with except for the fact that the only way to find the SMC in the first place is do a search for Marrakech, after all the search utility still thinks it's looking at the Earth's surface.
The other major problem is that the
Maps.appapplication doesn't actually have the Maps API, the very thing I need so that I can manipulate the map at the very basic level of even adding a placemark. There are presumably hidden hooks into the application, and maybe those will appear in the Apple SDK due in February . But there still isn't any word on the licensing provisions for the SDK. Who knows if I can get access to it, especially if there is a issue surrounding the digital signatures rumoured to be needed for an "official" application. Finding the money needed, possibly a lot of money, for the SDK could be an interesting proposition. That's even if those hooks exist in the first place.
Anyway, the easiest thing for you to do if you want to replicate my hack is to download the hacked database file (29MB) I generated and copy it into
/var/root/Library/Caches/MapTiles/. Make sure you make a copy of your existing
MapTiles.sqlitedbdatabase before dropping the new one ontop of it, you'll probably want to back out of the hack at some point. After copying the database file into the right place, simply reboot your iPhone or iPod touch. At that point it should all just work...
If you're crazy enough to want to waste your time playing around with this I've attached the source code that will let you rebuild the
MapTiles.sqlitedbdatabase directly from the Sky tile servers. Hopefully the guys at Google won't be too cross, as I doubt the handful of people crazy enough to go off and duplicate this stunt will add any significant load to the tile servers...
|download_tiles.pl||Download all of the tiles from the server|
|eatblob.c||Program to push the tiles in the the SQLite DB|
|getdelim.c getdelim.h||Needed by eatblob.c|
|getline.c getline.h||Needed by eatblob.c|
|push_tiles.pl||Script to run eatblob.c in harness for all tiles.|
Of course if you don't want to get your hands dirty with the insides of the Maps application, you can always just watch the video...