Вы находитесь на странице: 1из 13

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

iOS Guy
FEEL IT! ENJOY IT!

Tracing routes with MapKit


05/22/2012 23 Comments

i
26 Votes
Presenting a map to the user is a common feature of mobile apps. And very often this feature comes
with an additional requirement: to trace the route from the current user location to some arbitrary
destination. The thing is, most apps accomplish this last requirement by adding a button to the right
navigation item that opens up google maps on the browser. But usually this is not the best user
experience.
Most developers dont know this (and I was one of them not too long ago), but it is possible to use
the
MKMapView
(http://developer.apple.com/library/ios/#documentation/MapKit/Reference
/MKMapView_Class/MKMapView/MKMapView.html) to easily render paths between to locations.
There isnt however (for now) any native APIs that magically handle this kind of drawing.
iOS handles routes using MKOverlayobjects (just like it handles pins using MKAnnotation). There is
a native MKOverlay class called MKPolyline which consists of an array of CLLocationCoordinate2D
structures that MKMapView knows how to draw.
The thing is: We know only two locations (coordinates). The current one (our origin) and the places
location (the destination). AND we need all the coordinates in between these two end locations
describing a smooth path following the roads and streets considering traffic and so on, in order to
properly create the MKPolyline object and add that to the map.
This is where Google Directions API (https://developers.google.com/maps/documentation
/directions/) comes in. Google offers an API (both JSON and XML) that among other options lets
you specify two locations and returns a complex set of information containing all sorts of data, like
routes (with alternatives), waypoints, distance and directions (instructions). At first, you might look
to the documentation and think that you may need to write a parser, iterate through the structure
and grab what you need. That is exactly what you need to do, but not as difficult as it seems. The
information
we are looking for is available as a string named overview_polyline available
under4:02
thePM
1 of
13
21/03/16,

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

route tag. Just grab that.


If you are using JSON (the recommended output), there are a lot of third-party libraries out there that
represents a JSON string as native data structures such as NSArray, NSDictionary and NSString.
Now if you are really lazy (and smart), then you use some sort of library like AFNetworking
(https://github.com/AFNetworking/AFNetworking) to handle requests and get for free JSON
parsing right on the response callback.
Almost every step of the process is a piece of cake until here. The MapKit has a native overlay view
that knows how to display a route. The route is given to you for free and with almost no efforts by
Google and AFNetworking provides you automatic parsing of the response Google sent you.
The only remaining detail is: Google Directions API gives us a string representing the route and we
need an array of CLLocationCoordinate2D structures.
Fortunately the Encoded Polyline Algorithm Format (https://developers.google.com
/maps/documentation/utilities/polylinealgorithm) used by google is fully described in the docs and
an Objective-C implementation was made available byAnkit Srivastava (http://stackoverflow.com
/users/919545/ankit-srivastava) on stackoverflow (http://stackoverflow.com/questions/8426592
/drawing-path-between-two-locations-using-mkpolyline).
For those lazy guys who are in a hurry, good news: There is a code snippet below for every point of
our discussion.
(WordPress sucks when it comes to presenting source code, but there is a View Source button that lets you
copy the code and properly paste it! But just in case you wish to read the code I have alsoattached a file here
(http://iosguy.files.wordpress.com/2012/05/tracing-routes-with-mapkit-snippets.pdf) ;)
Create the Map View
1
2
3
4

_mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];


_mapView.showsUserLocation = YES;
_mapView.delegate = self;
[self.view addSubview:_mapView];

Once you have the current location, define the map region you want to be visible:
1
2

MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(self. location


MKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion]; [_mapVi

Also request Google Directions API to retrieve the route:

2 of 13

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString


[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];

NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];


[parameters setObject:[NSString stringWithFormat:@"%f,%f", location.coordinate.l
[parameters setObject:[NSString stringWithFormat:@"%f,%f", endLocation.coordinat
[parameters setObject:@"true" forKey:@"sensor"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:@"GET" path:
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest


NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:response];
} else {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];

Get what you need:


1
2
3
4
5
6
7
8

- (void)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:@"routes"];
NSDictionary *route = [routes lastObject];
if (route) {
NSString *overviewPolyline = [[route objectForKey: @"overview_polyline"] objectF
_path = [self decodePolyLine:overviewPolyline];
}
}

And use the code provided by Ankit Srivastava:

3 of 13

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {


NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedSt
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:@"\\\\" withString:@"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];

CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue


[array addObject:location];
}
return array;
}

Create the MKPolyline annotation:


1
2
3
4
5
6
7
8
9
10
11
12

NSInteger numberOfSteps = _path.count;


CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}

MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:num


[_mapView addOverlay:polyLine];

And make it visible on the map view:


4 of 13

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

1
2
3
4
5
6
7

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)ov


MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay]
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 1.0;
return polylineView;
}

Please note the code snippets provided on this post doesnt have any error handling neither are optimized.
Remember to fix these issues before copying them to your application.

Tagged: CLLocation, CLLocationCoordinate2D, Directions API, iOs, iPad, iPhone, MapKit,


MKMapView, MKOverlayView, MKPolylineView, route

23 Responses to Tracing routes with MapKit


david says:
07/06/2012 at 04:40 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-212)

i
Rate This
Hi,
Ive tried the code and Im getting an exception.
The problem is in the method parseResponse
(void)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:@routes];
NSDictionary *route = [routes lastObject];
if (route) {
NSString *overviewPolyline = [[route objectForKey: @overview_polyline]
objectForKey:@points];
5 of 13_path = [self decodePolyLine:overviewPolyline];

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

}
}
sending the message objectForKey to the response object causes an unrecognized selector sent to
instance
Ive tried to copy and paste the URL called by the application into a browser and seems to receive
a correct answer. Here is a link FYI.
http://maps.googleapis.com/maps/api/directions/json?sensor=true&
destination=41.380000%2C2.180000&origin=41.380000%2C2.120000 (http://maps.googleapis.com
/maps/api/directions/json?sensor=true&destination=41.380000%2C2.180000&
origin=41.380000%2C2.120000)
Any help will be much appreciated.
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=212#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
07/06/2012 at 04:47 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-213)

i
Rate This
Hi David,
in this tutorial I was using AFNetworking and JSONKit.
AFNetworking automatically locates and uses JSONKit (and some other known JSON parsers)
when a request is made (through the AFNetworking API).
If you did that, the response object should be an NSDictionary. Otherwise it can be a string or
a HTTPResponse object of some kind.
Greetings,
Cezar
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=213#respond)
david says:
07/06/2012 at 07:03 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-214)

i
Rate This
Thanks for the quick response. I did not do it before. I have placed the JSONKit files into
my project, but the error keeps happening :(
6 of 13

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

david says:
07/09/2012 at 00:44 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-216)

i
Rate This
Just to let you know, it worked after I added:
[_httpClient setDefaultHeader:@Accept value:@application/json];
right after the line:
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
JaiParivesh JaiNepal (http://www.facebook.com/jaiparivesh) says:
07/31/2012 at 23:25 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-239)

i
Rate This
is this example stored some where? It will be easy for the new babies for learning thanks.
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=239#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
08/01/2012 at 05:19 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-240)

i
Rate This
Nope :/
Feel free to contribute!
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=240#respond)
Jesus says:
08/02/2012 at 11:50 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-243)

7 of 13
i

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

Rate This
Please help me, the code runs without errors or warnings but it dont display route. Where do i
put function map view?
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=243#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
08/02/2012 at 11:52 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-244)

i
Rate This
the mapView is not a function, but an object. You should add it as a subview of your controller
(generally).
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=244#respond)
Jesus says:
08/02/2012 at 12:08 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-245)

i
Rate This
Ok, the map and coordinates are displayed fine, but the route is not displayed and I dont
know why could you help me?
Im trying to learn about IOS doing some working code.
Miquel says:
10/24/2012 at 09:18 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-267)

i
Rate This
Just writing to thank you (and Ankit Srivastava)!
It helped me a lot and it just worked. As a side note, I used MKNetworkKit instead of
AFNetworking, but both look pretty similar (at least the code related to requesting data to the
Google API).
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=267#respond)
nebiros (http://vesifront.org) says:
8 of 13
21/03/16, 4:02 PM
11/14/2012 at 21:20 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-276)

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

i
Rate This
Can you share the code?, please, :)
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=276#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
11/16/2012 at 13:41 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-278)

i
Rate This
I shared the code on the post (http://iosguy.files.wordpress.com/2012/05/tracing-routeswith-mapkit-snippets.pdf (http://iosguy.files.wordpress.com/2012/05/tracing-routeswith-mapkit-snippets.pdf))..
Juan Felipe Alvarez Saldarriaga (http://juan.im) says:
11/13/2012 at 20:11 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-275)

i
Rate This
Thank you!, but, what about the Usage Limits (https://developers.google.com
/maps/documentation/directions/#Limits (https://developers.google.com/maps/documentation
/directions/#Limits))?, when Google says: Note: the Directions API may only be used in
conjunction with displaying results on a Google map; using Directions data without displaying a
map for which directions data was requested is prohibited., so, what up with iOS6 and Apple
Maps?
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=275#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
11/16/2012 at 13:39 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-277)

i
9 of 13
21/03/16, 4:02 PM
Rate This

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

Hi Juan,
You are unfortunately right. According to the Directions APIs usage limits, you shouldnt
use it with iOS 6.
(I wrote this post before iOS 6 was released =)
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=277#respond)
kineticgravatar says:
01/26/2013 at 12:33 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-286)

i
Rate This
I know this post is old, but I wanted to mention that before anyone out there gets discouraged
when they read that the data has to be used with Google Maps, there is now the Google Maps
SDK for iOS, which has polylines too!
https://developers.google.com/maps/documentation/ios/lines (https://developers.google.com
/maps/documentation/ios/lines)
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=286#respond)
manish nath (@manishnath) (http://twitter.com/manishnath) says:
09/16/2013 at 12:36 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-312)

i
Rate This
The Terms of service do not allow you to draw lines to present routes or turn by turn
navigation :
https://developers.google.com/maps/terms (https://developers.google.com/maps/terms)
(e) No Modification of Links. You must not modify, replace, obscure, or otherwise hinder
the functioning of links to Google or third party websites provided in the Content. For the
avoidance of doubt, titles for place results must link to the applicable URL provided in the
result, unless the title is intended to be selected only for purposes of navigation by an end
user accessing your Maps API Implementation from a device with appropriately spaceconstraining user interface options. In these cases, the title linking to the Google-provided
URL must be displayed as the top and primary link on the subsequent landing page or
user interface component.

10 of 13

Cezar Augustus Signori (http://iosguy.com/) says:


09/16/2013 at 13:13 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit
/#comment-314)

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

i
Rate This
I am not sure I quite followed your thoughts. What those Link restrictions have to do with
drawing routes?
Codec Major says:
02/20/2013 at 14:04 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-291)

i
Rate This
Thank you so much!!
Very useful :D
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=291#respond)
shengjia says:
06/06/2013 at 12:43 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-300)

i
Rate This
Hi,
I have to mention that there is an error from method decodePolyline by Ankit Srivastava.
We should not do the code following:
[encoded replaceOccurrencesOfString:@\\\\ withString:@\\
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=300#respond)
prag says:
07/10/2013 at 08:22 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-302)

i
11 of 13
21/03/16, 4:02 PM
Rate This

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

Very informative article..


Does the JSON response contains traffic information.If yes, Please tell me the Key to extract it.
Thanks
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=302#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
08/24/2013 at 10:22 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-310)

i
Rate This
Cant quite recall. Just log the JSON response or take a quick look on the API documentation.
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=310#respond)
manish nath (@manishnath) (http://twitter.com/manishnath) says:
09/16/2013 at 12:33 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-311)

i
Rate This
is this even legal to draw directions on maps in iOS apps using googles api ?
(c) No Navigation, Autonomous Vehicle Control, or Enterprise Applications. You must not use
the Service or Content with any products, systems, or applications for or in connection with any
of the following:
(i) real time navigation or route guidance, including but not limited to turn-by-turn route
guidance that is synchronized to the position of a users sensor-enabled device.
From TOS Googles Map API
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=311#respond)
Cezar Augustus Signori (http://iosguy.com/) says:
09/16/2013 at 13:11 (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/#comment-313)

i
Rate This
I am no lawyer but I think so given section 9, specifically 9.1 and 9.2. In the end it depends on
how you do that.
Reply (http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/?replytocom=313#respond)
12 of 13

21/03/16, 4:02 PM

Tracing routes with MapKit | iOS Guy

http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/

Create a free website or blog at WordPress.com.


The Oulipo Theme.

13 of 13

21/03/16, 4:02 PM

Вам также может понравиться