11 Set, 2013 13:15
Utilizando o Google Maps no seu Aplicativo iOS - Parte 3
Baixando a rota da API do Google Maps
Infelizmente, até o momento, o Google Maps SDK do iOS não possui a função de calcular rotas embutida. Para realizar essa tarefa, precisamos recorrer ao Serviços da Web da API do Google Maps que contem, entre outras, a função desejada.
Para simplificar, assumirei que você já possui dois pontos entre os quais você deseja traçar a rota. Esse pontos podem ser obtidos de qualquer modo: pegando a posição do usuário, tocando no mapa, etc.
- (void)tracarRotaDe:(CLLocationCoordinate2D)origem para:(CLLocationCoordinate2D)destino {
NSString* origemString = [NSString stringWithFormat:@"%f,%f", origem.latitude, origem.longitude];
NSString* destinoString = [NSString stringWithFormat:@"%f,%f", destino.latitude, destino.longitude];
// 1
NSString* apiUrlStr = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&sensor=true", origemString, destinoString];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
// 2
[self performSelectorInBackground:@selector(baixarRota:) withObject:apiUrl];
}
O método acima, monta uma url de acordo com as especificações do serviço de rotas (1). Você pode customizar a url para traçar rotas de carro (padrão), a pé, ou com várias outras opções.
Como é necessário conectar ao serviço (2), a conexão não pode ser feita na Main Thread para não bloquear a interface e então chamamos assincronamente o método a seguir.
- (void)baixarRota:(NSURL *)apiUrl {
NSData *apiResponse = [NSData dataWithContentsOfURL:apiUrl];
// 1
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:apiResponse options:0 error:nil];
NSString *encodedPoints = nil;
if ([json[@"routes"] count] > 0) {
// 2
encodedPoints = json[@"routes"][0][@"overview_polyline"][@"points"];
}
if ([encodedPoints length] > 0) {
@try {
// 3
GMSPath *path = [GMSPath pathFromEncodedPath:encodedPoints];
// 4
[self performSelectorOnMainThread:@selector(atualizarRota:) withObject:path waitUntilDone:YES];
return;
}
@catch (NSException *exception) {
NSLog(@"Error calculating path from encoded points: %@", exception);
}
}
rota = nil;
[self performSelectorOnMainThread:@selector(rotaNaoEncontrada) withObject:nil waitUntilDone:YES];
}
A chamada ao serviço retorna um JSON (1) com vários detalhes sobre a rota que você pode usar caso deseje mostrar um passo-a-passo para o usuário.
No nosso caso, vamos mostrar apenas a rota completa traçada no mapa. Para isso, o JSON contem a rota codificada sob o atributo overview_polyline ->points (2). O SDK possui uma classe, GMSPath, que sabe como decodificar essa string com o método pathFromEncodedPath: (3).
Como desenhar a rota é uma operação de interface, deve ser executada na Main Thread (4). Então, chamamos finalmente o método abaixo.
- (void)atualizarRota:(GMSPath *)path {
// *
[self eliminarRota];
// 1
rota = [GMSPolyline polylineWithPath:path];
// 2
rota.strokeWidth = 8;
rota.strokeColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.7];
if (rota) {
// 3
rota.map = self.mapView;
// 4
GMSCameraUpdate *update = [GMSCameraUpdate fitBounds:[[GMSCoordinateBounds alloc] initWithPath:rota.path]
withPadding:50.0f];
[self.mapView animateWithCameraUpdate:update];
}
}
Com o GMSPath, podemos montar uma GMSPolyline (1) que é a classe que representa um caminho a ser desenhado no mapa. Você pode customizar, entre outros atributos, a espessura e a cor da linha conforme a sua necessidade (2). Depois, basta adicionar a rota no mapa (3) e, caso queira, realizar um GMSCameraUpdate para enquadrar a rota na tela (4).
A menos que sua intenção seja sobrepor várias rotas, é saudável remover a rota atual antes de adicionar uma nova (*). Felizmente, é muito fácil fazer isso:
- (void)eliminarRota {
rota.map = nil;
rota = nil;
}
Basta "desconectar" a rota do mapa e depois eliminá-la (Neste exemplo eu usei o ARC, por isso não há nenhum release nos código acima).
Ainda existem outros recursos bem legais do SDK, fiquem ligados nos próximos posts.