Программно открытое приложение Карты в iOS 6


159

В предыдущих версиях iOS 6 при открытии URL-адреса открывалось приложение Google Maps:

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

Теперь с новой реализацией Apple Maps, это просто открывает Mobile Safari для Google Maps. Как я могу добиться того же поведения с iOS 6? Как программно открыть приложение «Карты», чтобы оно указывало на определенное местоположение / адрес / поиск / что-нибудь еще?

Ответы:


281

Вот официальный способ 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];
}

Если вы хотите получить вождение или ходьбу инструкции к месту, вы можете включить mapItemForCurrentLocationс MKMapItemмассивом в +openMapsWithItems:launchOptions:, и установить параметры запуска правильно.

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

elseПосле этого вы можете сохранить исходный код iOS 5 и более низкий код в выписке if. Обратите внимание, что если вы измените порядок элементов в openMapsWithItems:массиве, вы получите направление от координаты к вашему текущему местоположению. Вы, вероятно, могли бы использовать его, чтобы получить направление между любыми двумя местоположениями, передавая построенный MKMapItemвместо текущего элемента карты местоположения. Я не пробовал это.

Наконец, если у вас есть адрес (в виде строки), на который вы хотите направить маршрут, используйте геокодер для создания MKPlacemark, посредством 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];

    }];
}

Код прекрасно работает для iOS 6. Стоит отметить, что если мы хотим получить маршрут от текущего местоположения пользователя до пункта назначения, то нет необходимости проходить через него currentLocationMapItem.
Philip007

1
Тот факт, что вы использовали координаты Томбукту, делает ответ еще лучше :)
sachadso

+1 за упоминание о том, что это только iOS 6 и что вам нужен запасной вариант
Хенрик Эрландссон

2
Как я могу перейти к моему текущему приложению из приложений карты?
Apple,

1
Какое же местоположение, которое я выбираю, когда оно открывает приложение «Apple Maps», оно показывает «Не удалось найти маршруты между этими местоположениями IOS 6», а затем ничего не делает? Любая помощь
NaXir

80

Нашел ответ на свой вопрос. Apple документирует формат URL своих карт здесь . Похоже , вы можете существенно заменить maps.google.comс maps.apple.com.

Обновление: Оказывается, то же самое верно для MobileSafari на iOS 6; При нажатии на ссылку http://maps.apple.com/?q=...открывается приложение «Карты» с этим поиском, как http://maps.google.com/?q=...и в предыдущих версиях. Это работает и задокументировано на странице, указанной выше.

ОБНОВЛЕНИЕ: Это отвечает на мой вопрос, касающийся формата URL. Но здесь ответ Невана Кинга (см. Ниже) - это отличная сводка фактического API Карт.


1
Интересный. Если вы откроете браузер для maps.apple.com, он будет перенаправлен на maps.google.com. Интересно, как долго это продлится?
pir800

@ pir800 - Мне просто было интересно, что произойдет, если вы нажмете ссылку на maps.apple.com в Safari на iOS 6. Я попробовал это, и он переходит к Maps так же, как и в предыдущих версиях iOS, когда вы нажимали ссылка на maps.google.com. Я думаю, стоит поспорить, что они перенаправляют на карты Google, чтобы авторы веб-сайтов могли просто указывать ссылки на карты на maps.apple.com и работать с iOS на Картах, но нормально работать на всех других клиентах. Но я бы хотел как-то это проверить, прежде чем менять все ссылки на моей карте, чтобы они указывали на maps.apple.com!
Том Хэмминг,

@ pir800 - для меня открытие maps.apple.com в браузере приводит меня к apple.com/ios/maps . Возможно мой предыдущий комментарий - желаемое за действительное.
Том Хэмминг,

Я имел в виду, если вы пытаетесь запросить адрес или координату. Попробуйте maps.apple.com/?q=los angeles, ca. Вы можете открыть его на своем настольном компьютере, и он будет перенаправлен на maps.google.com
pir800

Есть ли способ добавить режим транзита к этому запросу? (ходьба / вождение). не могу найти ссылку на него в Интернете.
Лирик

41

Лучший способ сделать это - вызвать новый метод iOS 6 на MKMapItem openInMapsWithLaunchOptions:launchOptions

Пример:

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

Это запустит навигацию для вождения из текущего местоположения.


1
Хорошо, так какой самый простой способ получить экземпляр, MKMapItemкогда у меня есть только адрес? Этот API кажется немного сложным для этого простого варианта использования.
Том Хэмминг

MKPlacemark * endLocation = [[MKPlacemark alloc] initWithCoordinate: nil addressDictionary: yourAdressDictHere]; Вы можете передать адрес Dictonary в
mariusLAN

7

Я вижу, вы нашли "схему" URL-адреса maps.apple.com. Это хороший выбор, поскольку он автоматически перенаправляет старые устройства на maps.google.com. Но для iOS 6 есть новый класс, которым вы можете воспользоваться: MKMapItem .

Два метода, которые вас интересуют:

  1. -openInMapsWithLaunchOptions: - вызвать его в экземпляре MKMapItem, чтобы открыть его в Maps.app
  2. + openMapsWithItems: launchOptions: - вызвать его в классе MKMapItem, чтобы открыть массив экземпляров MKMapItem.

Это выглядит полезным. Но это также кажется немного более сложным в использовании; Вы должны сделать это init MKMapItemс помощью MKPlacemarkпары широта / долгота и словаря адресов. Кажется проще просто открыть http://maps.apple.com/?q=1+infinite+loop+cupertino+ca. Есть ли преимущество в использовании, MKMapItemкогда все, что вы хотите сделать, это показать адрес в Картах?
Том Хэмминг,

Вам не нужно инициализировать, MKMapItemесли у вас еще нет ссылки на тот, который вы хотели бы использовать. Просто используйте метод класса, +openMapsWithItems:launchOptions:на , MKMapItemчтобы сделать то же самое.
Марк Адамс

@MarkAdams этот метод класса принимает массив экземпляров класса, так что да, он должен иметь хотя бы один инициализированный.
Филипп Раделич

Таким образом, в ситуации, когда у меня есть координаты GPS для открытия, но нет адреса, я использую MKMapItemAPI, и он отбрасывает точку на карте с надписью «Неизвестное местоположение». Есть ли способ заставить его отображать название места? Я не вижу ключей для этого в параметрах словаря адресов ...
Том Хэмминг,

5
@ Mr.Jefferson Установите свойство name для MKMapItem
matt

5

Вот класс, использующий решение Невана Кинга, выполненное в 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)
}

4

Меня раздражает, что использование ссылки http://maps.apple.com?q= ... открывает браузер Safari первым на старых устройствах.

Так что для устройства iOS 5, открывающего ваше приложение со ссылкой на maps.apple.com, шаги выглядят следующим образом:

  1. вы нажимаете что-то в приложении, и это относится к URL-адресу maps.apple.com
  2. сафари открывает ссылку
  3. сервер maps.apple.com перенаправляет на URL-адрес maps.google.com
  4. URL-адрес maps.google.com интерпретируется и открывается приложение Google Maps.

Я думаю, что (очень очевидные и запутанные) шаги 2 и 3 раздражают пользователей. Поэтому я проверяю версию os и запускаю maps.google.com или maps.apple.com на устройстве (соответственно для версий ios 5 или ios 6).


Это то, что я тоже делаю. Похоже, лучший подход.
Том Хэмминг

3

Мои исследования по этому вопросу привели меня к следующим выводам:

  1. Если вы используете maps.google.com, он откроет карту в сафари для каждого ios.
  2. Если вы используете maps.apple.com, то он откроет карту в приложении карты ios 6, а также будет работать с ios 5, а в ios 5 он откроет карту как обычно в сафари.

3

Если вы хотите открыть Google Карты вместо этого (или предложить в качестве дополнительного варианта), вы можете использовать схемы URL comgooglemaps://и comgooglemaps-x-callback://URL, описанные здесь .


3

Перед запуском url удалите любой специальный символ из url и замените пробелы на +. Это избавит вас от головной боли:

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

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


2

Обновлен до Swift 4, основываясь на ответе @ 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)
}

1

Не используя карты, просто программно используя действие UiButton, это отлично сработало для меня.

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

                }

Вы могли бы немного распространить этот код. Например, я поместил переменную как переменную уровня класса, заполнил ее другой функцией, а затем, когда нажал кнопку, просто взял то, что было в переменной, и очистил ее для использования в URL.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.