Saturday, July 14, 2012

Custom Map Tiles (Part 5 - offline maps on iOS)

In this post I'm going to create an iOS mapping application, with the added benefit of using my own map tiles served offline, i.e, deployed with the application without requiring network connection.

I'm going to use a library called MapBox-ios-sdk and the tiles will be created using TileMill and served in the .mbtiles format.

Mapping in iOS isn't something new. There's a standard component called MapKit that's been available for some time, and there's loads of information on it all over the web. Anyway, I have two problems with it:
  • Map-Tiles are fetched over the network. Offline mapping apps are a "no-go".
  • You can't use your own map tiles.

There's a library called Route-Me that tries to provide a similar look&feel as MapKit, but allowing a much more broader range of options for MapTiles, including offline support.

Anyway, the hard part is choosing the "right" Route-Me. Let me explain:

Route-Me is hosted in GitHub. Thus, if you're familiar with GitHub (or Git for that matter), it allows you to fork a specific project and work on it independently, and eventually pull some changes onto the main project (or not). Thus we have:

  • Route-Me/Route-Me 
    • Alpstein/Route-Me  (forked from Route-Me/Route-Me)
      • MapBox/MapBox-ios-sdk (forked from Alpstein/Route-Me)
(There are much more forks. These are the most important)

The Alpstein fork eventually changed a lot, and is now much different that the original project. In my opinion it has in-fact surpassed the master (hence the Star Wars reference).

When I left you, I was but the learner; now *I* am the master. 
Then, to make matters even more confusing, MapBox launched their own fork, adding some new features specific to their technology, like supporting MapBox cloud storage and the UTFGrid specification.

Anyway,  it seems to me that MapBox-ios-sdk won't derail much from the Alpstein fork. Also, those guys from MapBox know their way around maps, so I'll stick to their fork.

Let's get started then.

The easiest way is, without a doubt, to download the MapBox-ios-example project. It showcases creating a map both online/offline and using UTFGrid for interaction.

So, clone the repository in (or download it directly for that matter).

Open the folder and run the "MapBox Example.xcodeproj" file:

Run the project.

Now, you have basically 3 different map modes:

- Online Layer: Loading tiles from MapBox (which use OpenStreetMap information)

- Offline Layer: Showing a map from an embedded resource on the project, namely a .mbtile file.

- Interactive Layer: Showing how to interact with UTFGrid data on the maps.

What I'll do is very simple.

  • Generate the mbtiles file.
I'll use TileMill for this. I'll use the map that I've created for this example. It's basically a map with hexagons over Europe.

  • Copy the file to the XCode project
Drag the file to the resources folder.

Make sure the "Copy items into destination group's folder (if needed)" is checked

Add the file to the bundled resources of the project.

  • Replace the map loading

In the file: OfflineLayerViewController.m, replace the mbtiles file name from "control-room-0.2.0":

RMMBTilesSource *offlineSource = [[RMMBTilesSource alloc] initWithTileSetURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"control-room-0.2.0" ofType:@"mbtiles"]]];

to "HexagonsEurope":

RMMBTilesSource *offlineSource = [[RMMBTilesSource alloc] initWithTileSetURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"HexagonsEurope" ofType:@"mbtiles"]]];

Now let's run the sucker.

Nice, here's our own custom map, totally offline.

Here's a video showing the map in action, recorded directly from the emulator.

1 comment:

  1. Very useful for my research in that difficult field. Helped me adding my own .mbtiles file for the offline map. My mistake was that i was not checking the "Add to targets" checkbox