В iOS был существенно переработан MapKit. Разработчики Apple отказались от Google maps, и создали свой картографический сервис. Карты стали dynamic(© apple), это позволило: красиво переворачивать ярлыки, избежать размытия при масштабировании и пр. API работы с MapKit не изменились, но появились дополнения.

Встречайте MKMapItem (описание здесь).

У MKMapItem есть свойства name, phoneNumber, url дают дополнительную информацию о месте на которое указывает экземпляр класса.


Свойство placemark хранит координаты. Свойство isCurrentLocation указывает на текущее положение девайса (Важно: как только isCurrentLocation устанавливается в YES, placemark устанавливается в nil).

MKPlacemark *myPlacemark = [[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(53.90, 27.56) addressDictionary:nil];
MKMapItem *myPoint = [[MKMapItem alloc] initWithPlacemark:myPlacemark];
Чтобы открыть приложение карты с выбранной точкой, вызываем instance-метод openInMapsWithLaunchOptions:

[myPoint openInMapsWithLaunchOptions:nil];

Если необходимо запустить приложение карты с несколькими «булавками», собираем все MKMapItem в NSArray и вызываем class-метод openInMapsItems: launchOptions:

NSArray *mapItems = @[point1, point2, point3];
[MKMapItem openMapsWithItems:mapItems launchOptions:nil];

В вышеописанные методы передается параметр NSDictionary *launchOptions. В этом параметре можно описать: тип отображаемой карты (схема, спутник, гибрид), центр отображаемого участка карты, отображаемый район, отображать ли траффик.

NSDictionary *options = @{
    MKLaunchOptionsMapTypeKey :[NSNumber numberWithInteger:MKMapTypeHybrid],
    MKLaunchOptionsMapCenterKey :[NSValue valueWithMKCoordinate:CLLocationCoordinate2DMake(53.90, 27.56)],
    MKLaunchOptionsMapSpanKey :[NSValue valueWithMKCoordinateSpan:MKCoordinateSpanMake(1, 1)]};
Еще одна опция которую стоит рассмотреть отдельно – MKLaunchOptionsDirectionsModeKey. Передав этот ключ приложению карты, оно создает маршрут (доступно 2 режима: walking/driving). В качестве начальной точки будет взят первый объект из массива, а конечная – последний объект, вне зависимости от количества объектов в массиве.

MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving

Отобразить текущее положение девайса на карте не сложно:

MKMapItem *currentPoint = [MKMapItem mapItemForCurrentLocation];
[currentPoint openInMapsWithLaunchOptions:nil];
Работать с этим экземпляром так же, как и с обычными MKMapItem, за исключением свойства placemark — оно имеет значение nil, свойство isCurrentLocation будет иметь значение YES.

Самое интересное: теперь приложения можно запускать прямо из стандартного приложения карты.

Нажимаем кнопку «навигации», вводим начальную и конечную точку маршрута.


Выбираем тип транспорта и, по нажатию на кнопку «Route», переходим к выбору приложения.

В верхней части таблицы отображены установленные приложения, ниже – приложения из App Store, которые ассоциированы с выбранным районом и транспортом.
По нажатию на «Route» открываем приложение.

Для создания «routing app» необходимо: задекларировать приложение как routing, указать для какого района ваше приложение, и «ловить» запуск из стандартного приложения карт.

Открываем в xCode (версия 4.5 и выше) файл проекта, выбираем target, настраиваем checkboxes: “accept transit routing request” – разрешаем приложению запускаться из стандартных карт; выбираем те виды транспорта, для которых написано приложение:

Приложение задекларировано как routing app. Займемся определением района для нашего приложения.

Требования к файлу, описывающему район:
• GeoJSON формат (.geojson подробнее);
• Описывайте один мультиполигон (может содержать несколько полигонов как на третьем рисунке);
• Сделайте ваши полигоны максимально простыми (до 20 полигонов по 20 точек на каждый);
• Файл не является частью проекта и загружается отдельно через iTunesConnect.

И последний шаг, перехватываем запуск приложения. Для этого в AppDelegate реализовываем метод application: openURL: sourceApplication: annotation:

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
    if ([MKDirectionsRequest isDirectionsRequestURL:url]) {
        MKDirectionsRequest *request = [[MKDirectionsRequest alloc]
                                        initWithContentsOfURL:url];
        MKMapItem *startItem = [request source];
        MKMapItem *endItem = [request destination];
        // YOUR CODE HERE
}
    return YES;
}
Что делать далее с полученными MKMapItem? Это зависит от вас, но не забывайте проверить свойство isCurrentLocation == YES (placemark в этом случае будет nil).

Ну и на закуску пример.