Programowo otwórz aplikację Mapy w iOS 6

159

W wersjach wcześniejszych niż iOS 6 otwarcie takiego adresu URL powodowało otwarcie aplikacji Mapy (Google):

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

Teraz, dzięki nowej implementacji Apple Maps, powoduje to po prostu otwarcie Mobile Safari w Mapach Google. Jak mogę osiągnąć to samo zachowanie w iOS 6? Jak programowo otworzyć aplikację Mapy i wskazać konkretną lokalizację / adres / wyszukiwanie / cokolwiek?

Tom Hamming
źródło

Odpowiedzi:

281

Oto oficjalny sposób 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];
}

Jeśli chcesz uzyskać instrukcje dotyczące jazdy lub chodzenia do lokalizacji, możesz dołączyć do tablicy znak mapItemForCurrentLocationz MKMapItemsymbolem w +openMapsWithItems:launchOptions:i odpowiednio ustawić opcje uruchamiania.

// 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];
}

Możesz zachować swój oryginalny kod iOS 5 i niższy w elseinstrukcji if. Zwróć uwagę, że jeśli odwrócisz kolejność elementów w openMapsWithItems:tablicy, otrzymasz wskazówki od współrzędnych do bieżącej lokalizacji. Prawdopodobnie możesz go użyć, aby uzyskać wskazówki między dowolnymi dwoma lokalizacjami, mijając skonstruowany MKMapItemzamiast bieżącego elementu mapy. Ja tego nie próbowałem.

Wreszcie, jeśli masz adres (jako ciąg znaków), które chcesz kierować się, aby skorzystać z geocoder utworzyć MKPlacemarkdrodze 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];

    }];
}
Nevan King
źródło
Kod działa świetnie na iOS 6. Warto jednak wspomnieć, że jeśli trasa, którą chcemy osiągnąć, prowadzi z aktualnej lokalizacji użytkownika do celu, nie ma potrzeby przechodzenia currentLocationMapItem.
Philip007
1
Fakt, że użyłeś współrzędnych Tombouctou tylko sprawia, że ​​odpowiedź jest jeszcze lepsza :)
sachadso
+1 za wzmiankę, że to tylko iOS 6 i że potrzebujesz rozwiązania zastępczego
Henrik Erlandsson,
2
jak mogę przejść do mojej bieżącej aplikacji z aplikacji map?
Apple
1
Jaką lokalizację wybieram, gdy otwiera aplikację Apple Maps, pokazuje ostrzeżenie „Nie można znaleźć wskazówek między tymi lokalizacjami ios 6”, a następnie nic nie robi? Jakakolwiek pomoc
NaXir
80

Znalazłem odpowiedź na moje własne pytanie. Apple dokumentuje tutaj format adresu URL map . Wygląda na to, można w zasadzie wymienić maps.google.comz maps.apple.com.

Aktualizacja: Okazuje się, że to samo dotyczy MobileSafari na iOS 6; stuknięcie łącza, aby http://maps.apple.com/?q=...otworzyć aplikację Mapy z tym wyszukiwaniem w ten sam sposóbhttp://maps.google.com/?q=... jak w poprzednich wersjach. To działa i jest udokumentowane na stronie, do której link znajduje się powyżej.

UPDATE: To odpowiada na moje pytanie dotyczące formatu adresu URL. Ale odpowiedź Nevana Kinga tutaj (patrz poniżej) to doskonałe podsumowanie rzeczywistego interfejsu API Map.

Tom Hamming
źródło
1
Ciekawy. Jeśli otworzysz przeglądarkę na maps.apple.com, przekierowuje ona do maps.google.com. Zastanawiam się, jak długo to potrwa?
pir800
@ pir800 - Właściwie zastanawiałem się, co by się stało, gdybyś stuknął w link do maps.apple.com w Safari na iOS 6. Wypróbowałem, a po dotknięciu przechodzi do Map w taki sam sposób, jak w poprzednich wersjach iOS link do maps.google.com. Myślę, że to dobry zakład, że przekierowują do map Google, aby autorzy witryn mogli po prostu wskazywać linki map do maps.apple.com i uruchamiać je na iOS w Mapach, ale działają normalnie na wszystkich innych klientach. Ale chciałbym to jakoś zweryfikować, zanim zmienię wszystkie moje linki mapy, aby wskazywały na maps.apple.com!
Tom Hamming,
@ pir800 - dla mnie otwarcie maps.apple.com w przeglądarce przenosi mnie na apple.com/ios/maps . Może mój poprzedni komentarz to myślenie życzeniowe.
Tom Hamming,
Miałem na myśli, jeśli spróbujesz zapytać o adres lub współrzędne. Wypróbuj maps.apple.com/?q=los angeles, ca. Możesz go otworzyć na komputerze stacjonarnym i przekieruje do maps.google.com
pir800
Czy istnieje sposób na dodanie trybu tranzytu do tego zapytania? (chodzenie / jazda samochodem). nie mógł znaleźć żadnego odniesienia do niego w sieci.
Lirik
41

Najlepszym sposobem na to jest wywołanie nowej metody iOS 6 MKMapItem openInMapsWithLaunchOptions:launchOptions

Przykład:

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];

Spowoduje to rozpoczęcie nawigacji do jazdy z bieżącej lokalizacji.

zvonicek
źródło
1
OK, więc jaki jest najłatwiejszy sposób, aby uzyskać przykład, MKMapItemgdy wszystko, co mam, to adres? Ten interfejs API wydaje się nieco skomplikowany w tym prostym przypadku użycia.
Tom Hamming,
MKPlacemark * endLocation = [[MKPlacemark assign] initWithCoordinate: nil addressDictionary: yourAdressDictHere]; możesz podać adres Dictonary
mariusLAN
7

Widzę, że znalazłeś „schemat” adresu URL maps.apple.com. To dobry wybór, ponieważ automatycznie przekierowuje starsze urządzenia na maps.google.com. Ale dla iOS 6 jest nowa klasa, z której możesz chcieć skorzystać: MKMapItem .

Dwie interesujące Cię metody:

  1. -openInMapsWithLaunchOptions: - wywołaj go w instancji MKMapItem, aby otworzyć ją w Maps.app
  2. + openMapsWithItems: launchOptions: - wywołaj go w klasie MKMapItem, aby otworzyć tablicę instancji MKMapItem.
Filip Radelic
źródło
To wygląda na przydatne. Ale wydaje się też trochę bardziej skomplikowany w użyciu; musisz to zrobić init MKMapItemza pomocą MKPlacemark, który otrzymujesz, dostarczając parę szerokość / długość geograficzna i słownik adresów. Wydaje się prostsze, aby po prostu otworzyć http://maps.apple.com/?q=1+infinite+loop+cupertino+ca. Czy warto używać, MKMapItemgdy wszystko, co chcesz zrobić, to pokazać adres w Mapach?
Tom Hamming,
Nie musisz inicjować pliku, MKMapItemjeśli nie masz jeszcze odniesienia do tego, którego chcesz użyć. Wystarczy skorzystać z metody klasy, +openMapsWithItems:launchOptions:na MKMapItemaby zrobić to samo.
Mark Adams,
@MarkAdams ta metoda klasy przyjmuje tablicę instancji klasy, więc tak, musi mieć zainicjowaną przynajmniej jedną.
Filip Radelic,
Czyli w sytuacji, gdy mam do otwarcia współrzędne GPS, ale brak adresu, korzystam z MKMapItemAPI i upuszcza punkt na mapie oznaczony jako „Nieznana lokalizacja”. Czy istnieje sposób, aby wyświetlić nazwę lokalizacji? Nie widzę żadnych kluczy do tego w opcjach słownika adresów ...
Tom Hamming,
5
@ Mr.Jefferson Ustaw właściwość name dla MKMapItem
Matt
5

Oto klasa wykorzystująca rozwiązanie Nevana Kinga ukończone w 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
źródło
4

Denerwowało mnie, że korzystanie z http://maps.apple.com?q= ... konfiguracji linku otwiera najpierw przeglądarkę safari na starszych urządzeniach.

W przypadku urządzenia iOS 5 otwierającego aplikację z odniesieniem do maps.apple.com kroki wyglądają następująco:

  1. klikniesz coś w aplikacji, a to odsyła do adresu URL maps.apple.com
  2. safari otwiera łącze
  3. serwer maps.apple.com przekierowuje na adres URL maps.google.com
  4. adres URL maps.google.com jest interpretowany i otwiera aplikację Mapy Google.

Myślę, że (bardzo oczywiste i mylące) kroki 2 i 3 są denerwujące dla użytkowników. Dlatego sprawdzam wersję systemu operacyjnego i uruchamiam na urządzeniu maps.google.com lub maps.apple.com (odpowiednio dla wersji systemu operacyjnego ios 5 lub ios 6).

EeKay
źródło
To też robię. Wydaje się, że jest to najlepsze podejście.
Tom Hamming
3

Moje badania na ten temat prowadzą mnie do następujących wniosków:

  1. Jeśli korzystasz z maps.google.com, otworzy się mapa w Safari dla każdego systemu iOS.
  2. Jeśli korzystasz z maps.apple.com, otworzy się mapa w aplikacji map w systemie iOS 6, a także będzie działać dobrze z ios 5, aw iOS 5 otworzy mapę jak zwykle w safari.
Honey Jain
źródło
3

Jeśli zamiast tego chcesz otworzyć Mapy Google (lub zaoferować jako opcję dodatkową), możesz skorzystać z udokumentowanych tutaj schematów adresów URL comgooglemaps://i .comgooglemaps-x-callback://

Johan Kool
źródło
3

Przed uruchomieniem url usuń wszelkie znaki specjalne z adresu URL i zamień spacje na +. Pozwoli to zaoszczędzić trochę bólu głowy:

    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
źródło
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
źródło
2

Zaktualizowano do Swift 4 na podstawie odpowiedzi @ 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
źródło
1

Nie używając map, tylko programowo używając akcji UiButton, to zadziałało świetnie.

// 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!)

                }

Możesz trochę rozpowszechnić ten kod. Na przykład umieściłem zmienną jako zmienną na poziomie klasy, kazałem innej funkcji ją wypełnić, a następnie po naciśnięciu przycisku po prostu wziąłem to, co było w zmiennej i wyszorowałem, aby użyć go w adresie URL.

Christopher Wade Cantley
źródło