In today’s programming tutorial, I’ll show you how easy it is to use OpenStreetMap maps in your app instead of default Apple maps. There are many reasons why you might want to do this: for example, the OpenStreetMap project is being built by a huge community of contributors and therefore the maps are really detailed; or, you might just want to give your users the option to use whatever maps they prefer.
Prior to iOS 7, it was also possible to use different map tiles than those that MapKit provides, but it required fairly large amount of code and work. Luckily, the map kit team introduced a really simple way to do this in iOS 7: new classes MKTileOverlay and MKTileOverlayRenderer. If you are a registered iOS developer, I highly suggest you watch the session 304 of WWDC ’13 here (requires ADC login). The introduction of it starts at 22:09.
You probably came here to see the code, so I’ll skip the explanation for now.
And… here it is!
The code
// Place this into your -viewDidLoad method
NSString *template = @"http://tile.openstreetmap.org/{z}/{x}/{y}.png"; // (1)
MKTileOverlay *overlay = [[MKTileOverlay alloc] initWithURLTemplate:template]; // (2)
overlay.canReplaceMapContent = YES; // (3)
[self.mapView addOverlay:overlay level:MKOverlayLevelAboveLabels]; // (4)
// And this somewhere in your class that’s mapView’s delegate (most likely a view controller).
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKTileOverlay class]]) {
return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
}
return nil;
}
The code is pretty self-explanatory, but just in case, I’ll briefly explain what it does.
Line 1: Here is where you specify what map tiles url you want to use. The {x}, {y} and {z} are placeholders that will be substituted by integers based on what part of the planet and at what zoom needs to be loaded (x is horizontal position, y is vertical and z is zoom, starting at 0 for the most zoomed-out map).
Line 2: Creating new MKTileOverlay, which will do all the magic of loading the tiles as needed.
Line 3: Will keep map view from loading default Apple map tiles.
Line 4: Adding the overlay above labels (streets, cities etc.), because OpenStreetMap has its own.
Line 7-11: The delegate method: simply checks what class the overlay is, and creates and returns new MKTileOverlayRenderer in case it’s MKTileOverlay.
Allowing non-https connections in your app
(Update: December 2016) In iOS 9, Apple introduced App Transport Security, which means that by default apps are required to use secure network connections over HTTPS. If you try to run the example code with the basic OpneStreetMap, you will get this error:
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
Fortunately, it’s still possible to allow non-https connections. All you need to do is add a special key to your Info.plist file:
The full code for beginners
If you are new to iOS development, here are a few more instructions: First, you need to drag a Map Kit View in Storyboard to your main view controller. Then, you need to create an IBOutlet to a variable in your view controller called mapView. Finally, you can use the code from above. The finished view controller looks like this:
(Get actual text at Pastebin.)
The MKTileOverlay coordinate system
MKTileOverlay uses Spherical Mercator projection (EPSG:3857). I don’t know much about projections (or map stuff in general), but the good news is that this seems to be the most common type of projection, popularized by Google and now used by OpenStreetMap, among others, so you’ll likely be able to use it with the maps of your choice. You can learn more about it on Wikipedia – Mercator projection.
A note for using OpenStreetMap tile servers
OpenStreetMap tile servers are run solely on donated resources, so if you have a very popular app that would create heavy load on those servers, you should go with a commercial solution. For more info, take a look at Tile usage policy – OpenStreetMap wiki.
Other OpenStreetMap-based maps
There are several other maps based on the OpenStreetMap data, most notably OpenCycleMap and MapQuest. You can use them by changing the template url when creating the MKTileOverlay
• OpenCycleMap: http://b.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png
• MapQuest: http://otile3.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg
Take a look at the official OSM wiki page Slippy map filenames – Tile servers to learn more.
Update – September 2017
MapQuest has since then disabled access to their tiles, so it’s no longer an option. OpenCycleMap now requires API key when requesting tiles. You can register at thunderforest.com to get the API key, and the quota for the free (Hobby) plan is 150.000 tiles per month. They have various other map themes as well, I highly recommend checking them out.
Comparison of maps
Where to go from here
Give it a spin, and let me know in the comments if you have any questions. In case you are wondering what UI to build to let users switch between the maps, I have good news: I figured out and implemented a very nice solution. And it even includes a user-tracking button, so it can be used as a drop-in replacement of MKMapView to instantly improve your app’s map experience. I am planning to release the code on GitHub very soon, but if you are curious, you can get Routie and try it out there. For now, here is a screenshot to whet your appetite: