2

I have an app that takes a street address and has to open an action sheet with actions corresponding to navigation apps installed on the iPhone. Tapping on the action opens the navigation app with the destination as the provided street address. I did not find a tutorial that does that so I need some guidance.

Similar to what the Facebook iOS app does when one taps on "Get Directions".

Nishant Bhindi
  • 2,242
  • 8
  • 21
user3017495
  • 123
  • 5

2 Answers2

3

I've implemented it in Swift 4

Define an enum for all the navigation apps you want to open.

enum NavigationApps: String {
    case appleMaps = "Maps"
    case googleMaps = "Google Maps"
    case hereWeGo = "HERE WeGo"
}

Following method takes latitude and longitude parameters in location tuple and opens action sheet with options of all the maps present in enum above and installed on user device. installedNavigationApps is an array of dictionary (key/value pairs) where keys are from NavigationApps enum and values are their respective URL schemes.

All you need to do is to mention all navigation apps in NavigationApps enum, URL schemes in installedNavigationApps array of dictionary, and handle app launch for each navigation app in UIAlertAction handler.

import MapKit

extension UIViewController {

    // MARK: - Map Navigation

    func openMapForLocation(location: (latitude: CLLocationDegrees, longitude: CLLocationDegrees)) {

        let installedNavigationApps : [[String:String]] = [[NavigationApps.appleMaps.rawValue:""], [NavigationApps.googleMaps.rawValue:"comgooglemaps://"], [NavigationApps.hereWeGo.rawValue:"here-route://"]]

        var alertAction: UIAlertAction?

        let alert = UIAlertController(title: "Select Navigation App", message: "Open in", preferredStyle: .actionSheet)

        for app in installedNavigationApps {
            let appName = app.keys.first
            if (appName == NavigationApps.appleMaps.rawValue ||
                appName == NavigationApps.googleMaps.rawValue || UIApplication.shared.canOpenURL(URL(string:app[appName!]!)!))
            {

                alertAction = UIAlertAction(title: appName, style: .default, handler: { (action) in
                    switch appName {
                    case NavigationApps.appleMaps.rawValue?:
                        let regionDistance:CLLocationDistance = 10000
                        let coordinates = CLLocationCoordinate2DMake(location.latitude, location.longitude)
                        let regionSpan = MKCoordinateRegionMakeWithDistance(coordinates, regionDistance, regionDistance)
                        let options = [
                            MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
                            MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span)
                        ]
                        let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
                        let mapItem = MKMapItem(placemark: placemark)
                        mapItem.name = "KIZAD"
                        mapItem.openInMaps(launchOptions: options)
                        break

                    case NavigationApps.googleMaps.rawValue?:
                        if UIApplication.shared.canOpenURL(URL(string:app[appName!]!)!) {
                            //open in Google Maps application
                            UIApplication.shared.open(URL(string:
                                "comgooglemaps://?saddr=&daddr=\(location.latitude),\(location.longitude)&directionsmode=driving")! as URL, options: [:], completionHandler: nil)
                        } else {
                            //open in Browser
                            let string = "https://maps.google.com/?q=@\(location.latitude),\(location.longitude)"
                            UIApplication.shared.open(URL(string: string)!)
                        }
                        break

                    case NavigationApps.hereWeGo.rawValue?:
                        UIApplication.shared.open(URL(string:
                            "here-route://mylocation/\(location.latitude),\(location.longitude)?ref=KIZAD&m=d")! as URL, options: [:], completionHandler: nil)
                        break

                    default:
                        break
                    }
                })
                alert.addAction(alertAction!)
            }
            else
            {
                print("Can't open URL scheme")
            }
        }

        alertAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        alert.addAction(alertAction!)

        self.present(alert, animated: true, completion: nil)
    }
}

IMPORTANT: Do NOT forget to add URL scheme of all third party navigation apps in info.plist. For instance:

<key>LSApplicationQueriesSchemes</key>
<array>
 <string>comgooglemaps</string>
 <string>here-route</string>
</array>
Maverick
  • 3,209
  • 1
  • 34
  • 40
2

There is an existing library that can do this for you. You will need to add the LSApplicationQueriesSchemes keys to the info plist as per the instructions.

https://github.com/kiliankoe/Karte

As of writing, it supports:

  • Apple Maps
  • Google Maps
  • Citymapper
  • Transit App
  • Lyft
  • Uber
  • Navigon
  • Waze
  • DB Navigator
  • Yandex.Navi
  • Moovit
Ric Santos
  • 15,419
  • 6
  • 50
  • 75