Программно открытое приложение Карты в 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];

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

zvonicek
источник
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)
}
PJeremyMalouf
источник
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).

EeKay
источник
Это то, что я тоже делаю. Похоже, лучший подход.
Том Хэмминг
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.

Кристофер Уэйд Кэнтли
источник