Abra o aplicativo Maps programaticamente no iOS 6

159

Antes do iOS 6, abrir um URL como esse abriria o aplicativo Google Maps:

NSURL *url = [NSURL URLWithString:@"http://maps.google.com/?q=New+York"];
[[UIApplication sharedApplication] openURL:url];

Agora, com a nova implementação do Apple Maps, isso abre o Mobile Safari para o Google Maps. Como posso realizar o mesmo comportamento com o iOS 6? Como faço para abrir programaticamente o aplicativo Maps e apontar para um local / endereço / pesquisa / qualquer coisa específica?

Tom Hamming
fonte

Respostas:

281

Aqui está a maneira oficial da Apple:

// Check for iOS 6
Class mapItemClass = [MKMapItem class];
if (mapItemClass && [mapItemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)]) 
{
    // Create an MKMapItem to pass to the Maps app
    CLLocationCoordinate2D coordinate = 
                CLLocationCoordinate2DMake(16.775, -3.009);
    MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate 
                                            addressDictionary:nil];
    MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
    [mapItem setName:@"My Place"];
    // Pass the map item to the Maps app
    [mapItem openInMapsWithLaunchOptions:nil];
}

Se você deseja obter instruções de direção ou caminhada para o local, pode incluir um mapItemForCurrentLocationcom o MKMapItemna matriz +openMapsWithItems:launchOptions:e definir as opções de inicialização adequadamente.

// Check for iOS 6
Class mapItemClass = [MKMapItem class];
if (mapItemClass && [mapItemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)]) 
{
    // Create an MKMapItem to pass to the Maps app
    CLLocationCoordinate2D coordinate = 
                CLLocationCoordinate2DMake(16.775, -3.009);
    MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate 
                                            addressDictionary:nil];
    MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
    [mapItem setName:@"My Place"];

    // Set the directions mode to "Walking"
    // Can use MKLaunchOptionsDirectionsModeDriving instead
    NSDictionary *launchOptions = @{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeWalking};
    // Get the "Current User Location" MKMapItem
    MKMapItem *currentLocationMapItem = [MKMapItem mapItemForCurrentLocation];
    // Pass the current location and destination map items to the Maps app
    // Set the direction mode in the launchOptions dictionary
    [MKMapItem openMapsWithItems:@[currentLocationMapItem, mapItem] 
                    launchOptions:launchOptions];
}

Você pode preservar o iOS 5 original e o código inferior em uma elsedeclaração depois disso if. Observe que, se você reverter a ordem dos itens na openMapsWithItems:matriz, obterá instruções da coordenada para o seu local atual. Você provavelmente poderia usá-lo para obter direções entre dois locais, passando por um MKMapItemitem de mapa de localização construído em vez do atual. Eu não tentei isso.

Por fim, se você tiver um endereço (como uma sequência) para o qual deseja obter direções, use o geocoder para criar um MKPlacemark, por meio de CLPlacemark.

// Check for iOS 6
Class mapItemClass = [MKMapItem class];
if (mapItemClass && [mapItemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)])
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:@"Piccadilly Circus, London, UK" 
        completionHandler:^(NSArray *placemarks, NSError *error) {

        // Convert the CLPlacemark to an MKPlacemark
        // Note: There's no error checking for a failed geocode
        CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0];
        MKPlacemark *placemark = [[MKPlacemark alloc]
                                  initWithCoordinate:geocodedPlacemark.location.coordinate
                                  addressDictionary:geocodedPlacemark.addressDictionary];

        // Create a map item for the geocoded address to pass to Maps app
        MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
        [mapItem setName:geocodedPlacemark.name];

        // Set the directions mode to "Driving"
        // Can use MKLaunchOptionsDirectionsModeWalking instead
        NSDictionary *launchOptions = @{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};

        // Get the "Current User Location" MKMapItem
        MKMapItem *currentLocationMapItem = [MKMapItem mapItemForCurrentLocation];

        // Pass the current location and destination map items to the Maps app
        // Set the direction mode in the launchOptions dictionary
        [MKMapItem openMapsWithItems:@[currentLocationMapItem, mapItem] launchOptions:launchOptions];

    }];
}
rei nevan
fonte
O código funciona muito bem para o iOS 6. Vale mencionar que, se a rota que queremos é da localização atual do usuário até um destino, não é preciso passar currentLocationMapItem.
Philip007
1
O fato de que você usou coordenadas Tombouctou só faz a resposta ainda melhor :)
sachadso
1 para mencionar que é iOS 6 única e que você precisa de um fallback
Henrik Erlandsson
2
como posso navegar para meu aplicativo atual a partir de aplicativos de mapa?
Apple
1
O que sempre local que seleciono quando abre o aplicativo de mapas da apple mostra o alerta "não foi possível encontrar instruções entre esses locais ios 6" e não está fazendo nada? Qualquer ajuda
NaXir 01/09/13
80

Encontrei a resposta para minha própria pergunta. A Apple documenta seu formato de URL de mapas aqui . Parece que você pode essencialmente substituir maps.google.compor maps.apple.com.

Atualização: acontece o mesmo no MobileSafari no iOS 6; tocar em um link para http://maps.apple.com/?q=...abrir o aplicativo Maps com essa pesquisa, da mesma forma http://maps.google.com/?q=...que nas versões anteriores. Isso funciona e está documentado na página vinculada acima.

UPDATE: Isso responde à minha pergunta relacionada ao formato do URL. Mas a resposta de nevan king aqui (veja abaixo) é um excelente resumo da API do Google Maps real.

Tom Hamming
fonte
1
Interessante. Se você abrir um navegador para maps.apple.com, ele será redirecionado para maps.google.com. Gostaria de saber quanto tempo isso vai durar?
Pir800 #
@ pir800 - Na verdade, eu estava pensando no que aconteceria se você tocasse em um link para maps.apple.com no Safari no iOS 6. Eu tentei e ele vai para o Google Maps da mesma forma que nas versões anteriores do iOS quando você tocava um link para maps.google.com. Eu acho que é uma boa aposta que eles estejam redirecionando para o Google Maps, para que os autores do site possam apenas apontar os links do mapa para maps.apple.com e fazê-lo funcionar no iOS no Maps, mas normalmente em todos os outros clientes. Mas eu gostaria de verificar isso de alguma forma antes de alterar todos os links do meu mapa para apontar para maps.apple.com!
Tom Hamming
@ pir800 - para mim, abrir maps.apple.com em um navegador me leva a apple.com/ios/maps . Talvez meu comentário anterior seja uma ilusão.
Tom Hamming
Eu quis dizer se você tentar consultar um endereço ou coordenada. Experimente maps.apple.com/?q=los angeles, ca. Você pode abri-lo em sua máquina e encaminhar para maps.google.com
pir800 27/12/12
Existe uma maneira de adicionar o modo de trânsito a essa consulta? (caminhar / dirigir). não foi possível encontrar nenhuma referência a ele na web.
Lirik
41

A melhor maneira de fazer isso é chamar o novo método iOS 6 em MKMapItem openInMapsWithLaunchOptions:launchOptions

Exemplo:

CLLocationCoordinate2D endingCoord = CLLocationCoordinate2DMake(40.446947, -102.047607);
MKPlacemark *endLocation = [[MKPlacemark alloc] initWithCoordinate:endingCoord addressDictionary:nil];
MKMapItem *endingItem = [[MKMapItem alloc] initWithPlacemark:endLocation];

NSMutableDictionary *launchOptions = [[NSMutableDictionary alloc] init];
[launchOptions setObject:MKLaunchOptionsDirectionsModeDriving forKey:MKLaunchOptionsDirectionsModeKey];

[endingItem openInMapsWithLaunchOptions:launchOptions];

Isso iniciará a navegação para dirigir a partir do local atual.

zvonicek
fonte
1
OK, então qual é a maneira mais fácil de obter uma instância de MKMapItemquando tudo o que tenho é um endereço? Essa API parece um pouco complicada para esse caso de uso simples.
Tom Hamming
MKPlacemark * endLocation = [[alocação do MKPlacemark] initWithCoordinate: nulo addressDictionary: yourAdressDictHere]; você pode entregar um endereço Dictonary em
mariusLAN 12/12
7

Vejo que você encontrou o "esquema" do maps.apple.com. É uma boa escolha, pois ele redireciona automaticamente os dispositivos mais antigos para maps.google.com. Mas para o iOS 6, há uma nova classe que você pode aproveitar: MKMapItem .

Dois métodos que são do seu interesse:

  1. -openInMapsWithLaunchOptions: - chame-o em uma instância MKMapItem para abri-lo no Maps.app
  2. + openMapsWithItems: launchOptions: - chame-o na classe MKMapItem para abrir uma matriz de instâncias do MKMapItem.
Filip Radelic
fonte
Isso parece útil. Mas também parece um pouco mais complicado de usar; você precisa de init MKMapItemum MKPlacemark, que você obtém fornecendo um par de latitude / longitude e um dicionário de endereço. Parece mais simples de abrir http://maps.apple.com/?q=1+infinite+loop+cupertino+ca. Existe uma vantagem em usar MKMapItemquando tudo o que você deseja fazer é mostrar um endereço no Google Maps?
22812 Tom Hamming
Você não precisa inicializar um MKMapItemcaso ainda não tenha uma referência a uma que gostaria de usar. Basta usar o método de classe, +openMapsWithItems:launchOptions:em MKMapItemfazer a mesma coisa.
Mark Adams
@MarkAdams esse método de classe usa uma matriz de instâncias de classe, então sim, ele precisa ter pelo menos uma inicializada.
Filip Radelic
Portanto, em uma situação em que tenho coordenadas GPS para abrir, mas nenhum endereço, uso a MKMapItemAPI e ela solta um ponto no mapa chamado "Local desconhecido". Existe uma maneira de fazê-lo exibir um nome para o local? Eu não vejo nenhum chaves para isso nas opções para o dicionário endereço ...
Tom Hamming
5
@ Mr.Jefferson Defina a propriedade name de MKMapItem
matt
5

Aqui está uma classe usando a solução de nevan king concluída em Swift:

class func openMapWithCoordinates(theLon:String, theLat:String){

            var coordinate = CLLocationCoordinate2DMake(CLLocationDegrees(theLon), CLLocationDegrees(theLat))

            var placemark:MKPlacemark = MKPlacemark(coordinate: coordinate, addressDictionary:nil)

            var mapItem:MKMapItem = MKMapItem(placemark: placemark)

            mapItem.name = "Target location"

            let launchOptions:NSDictionary = NSDictionary(object: MKLaunchOptionsDirectionsModeDriving, forKey: MKLaunchOptionsDirectionsModeKey)

            var currentLocationMapItem:MKMapItem = MKMapItem.mapItemForCurrentLocation()

            MKMapItem.openMapsWithItems([currentLocationMapItem, mapItem], launchOptions: launchOptions)
}
PJeremyMalouf
fonte
4

Achei irritante que o uso da configuração do link http://maps.apple.com?q= ... abra o navegador safari primeiro em dispositivos mais antigos.

Portanto, para um dispositivo iOS 5 que abre seu aplicativo com uma referência a maps.apple.com, as etapas são:

  1. você clica em algo no aplicativo e se refere ao URL maps.apple.com
  2. safari abre o link
  3. o servidor maps.apple.com redireciona para o URL maps.google.com
  4. o URL maps.google.com é interpretado e abre o aplicativo do Google Maps.

Eu acho que as etapas 2 e 3 (muito óbvias e confusas) são irritantes para os usuários. Portanto, verifico a versão do sistema operacional e executo maps.google.com ou maps.apple.com no dispositivo (para as versões do SO iOS 5 ou iOS 6).

EeKay
fonte
É o que estou fazendo também. Parece a melhor abordagem.
Tom Hamming
3

Minha pesquisa sobre esse assunto me levou às seguintes conclusões:

  1. Se você usar o maps.google.com, ele abrirá o mapa no safari para todos os ios.
  2. Se você usar maps.apple.com, ele abrirá o mapa no aplicativo de mapa do ios 6 e também funcionará greate com o ios 5 e, no ios 5, abrirá o mapa normalmente no safari.
Honey Jain
fonte
3

Se você deseja abrir o Google Maps (ou oferecer como opção secundária), use os esquemas comgooglemaps://e comgooglemaps-x-callback://URL documentados aqui .

Johan Kool
fonte
3

Antes de iniciar o URL, remova qualquer caractere especial do URL e substitua os espaços por +. Isso poupará algumas dores de cabeça:

    NSString *mapURLStr = [NSString stringWithFormat: @"http://maps.apple.com/?q=%@",@"Limmattalstrasse 170, 8049 Zürich"];

    mapURLStr = [mapURLStr stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    NSURL *url = [NSURL URLWithString:[mapURLStr stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
    if ([[UIApplication sharedApplication] canOpenURL:url]){
            [[UIApplication sharedApplication] openURL:url];
        }
Javier Calatrava Llavería
fonte
2
NSString *address = [NSString stringWithFormat:@"%@ %@ %@ %@"
                             ,[dataDictionary objectForKey:@"practice_address"]
                             ,[dataDictionary objectForKey:@"practice_city"]
                             ,[dataDictionary objectForKey:@"practice_state"]
                             ,[dataDictionary objectForKey:@"practice_zipcode"]];


        NSString *mapAddress = [@"http://maps.apple.com/?q=" stringByAppendingString:[address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

        NSLog(@"Map Address %@",mapAddress);

        [objSpineCustomProtocol setUserDefaults:mapAddress :@"webSiteToLoad"];

        [self performSegueWithIdentifier: @"provider_to_web_loader_segue" sender: self];

// VKJ

Vinod Joshi
fonte
2

Atualizado para o Swift 4 com base na resposta de @ PJeremyMalouf:

private func navigateUsingAppleMaps(to coords:CLLocation, locationName: String? = nil) {
    let placemark = MKPlacemark(coordinate: coords.coordinate, addressDictionary:nil)
    let mapItem = MKMapItem(placemark: placemark)
    mapItem.name = locationName
    let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
    let currentLocationMapItem = MKMapItem.forCurrentLocation()

    MKMapItem.openMaps(with: [currentLocationMapItem, mapItem], launchOptions: launchOptions)
}
Chris Prince
fonte
1

Não usando mapas, apenas programaticamente usando uma ação UiButton, isso funcionou muito bem para mim.

// Button triggers the map to be presented.

@IBAction func toMapButton(sender: AnyObject) {

//Empty container for the value

var addressToLinkTo = ""

//Fill the container with an address

self.addressToLinkTo = "http://maps.apple.com/?q=111 Some place drive, Oak Ridge TN 37830"

self.addressToLinkTo = self.addressToLinkTo.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!

let url = NSURL(string: self.addressToLinkTo)
UIApplication.sharedApplication().openURL(url!)

                }

Você pode espalhar um pouco desse código. Por exemplo, eu coloquei a variável como variável de nível de classe, tive outra função para preenchê-la e, quando pressionada, o botão simplesmente pegava o que estava na variável e esfregava para ser usado em um URL.

Christopher Wade Cantley
fonte