Programmatically open Maps app in iOS 6

IosObjective CIos6Mapkit

Ios Problem Overview


Previous to iOS 6, opening a URL like this would open the (Google) Maps app:

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

Now with the new Apple Maps implementation, this just opens Mobile Safari to Google Maps. How can I accomplish the same behavior with iOS 6? How do I programmatically open the Maps app and have it point to a specific location/address/search/whatever?

Ios Solutions


Solution 1 - Ios

Here's the official Apple way:

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

If you want to get driving or walking instructions to the location, you can include a mapItemForCurrentLocation with the MKMapItem in the array in +openMapsWithItems:launchOptions:, and set the launch options appropriately.

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

You can preserve your original iOS 5 and lower code in an else statement after that if. Note that if you reverse the order of items in the openMapsWithItems: array, you'll get directions from the coordinate to your current location. You could probably use it to get directions between any two locations by passing a constructed MKMapItem instead of the current location map item. I haven't tried that.

Finally, if you have an address (as a string) that you want directions to, use the geocoder to create an MKPlacemark, by way of 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];
		
	}];
}

Solution 2 - Ios

Found the answer to my own question. Apple documents its maps URL format here. It looks like you can essentially replace maps.google.com with maps.apple.com.

Update: It turns out that the same is true in MobileSafari on iOS 6; tapping a link to http://maps.apple.com/?q=... opens the Maps app with that search, the same way http://maps.google.com/?q=... did on previous versions. This works and is documented in the page linked above.

UPDATE: This answers my question relating to the URL format. But nevan king's answer here (see below) is an excellent summary of the actual Maps API.

Solution 3 - Ios

The best way to do it is to call new iOS 6 method on MKMapItem openInMapsWithLaunchOptions:launchOptions

Example:

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

This will start the navigation for driving from the current location.

Solution 4 - Ios

I see you found the maps.apple.com url "scheme". It's a good choice because it will automatically redirect older devices to maps.google.com. But for iOS 6 there is a new class you might want to take advantage of: MKMapItem.

Two methods that are of interest to you:

  1. -openInMapsWithLaunchOptions: - call it on an MKMapItem instance to open it in Maps.app
  2. +openMapsWithItems:launchOptions: - call it on MKMapItem class to open an array of MKMapItem instances.

Solution 5 - Ios

Here is a class using nevan king's solution completed in 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)
}

Solution 6 - Ios

I found it annoying that using the http://maps.apple.com?q=... link setup opens the safari browser first at older devices.

So for an iOS 5 device opening up your app with a reference to maps.apple.com the steps look like:

  1. you click something in the app and it refers to the maps.apple.com url
  2. safari opens up the link
  3. the maps.apple.com server redirects to the maps.google.com url
  4. the maps.google.com url gets interpreted and opens the google Maps app.

I think that the (very obvious and confusing) steps 2 and 3 are annoying to users. Therefore i check the os version and either run maps.google.com or maps.apple.com on the device (for resp. ios 5 or ios 6 OS versions).

Solution 7 - Ios

My research on this issue lead me to the following conclusions:

  1. If you use maps.google.com then it will open the map in safari for every ios.
  2. If you use maps.apple.com then it will open the map in map application of ios 6 and also work greate with ios 5 and in ios 5 it open the map as normal in safari.

Solution 8 - Ios

If you want to open Google Maps instead (or offer as a secondary option), you can use the comgooglemaps:// and comgooglemaps-x-callback:// URL schemes documented here.

Solution 9 - Ios

Before launching url, remove any special character from the url and replace spaces by +. This will save you some headaches:

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

Solution 10 - Ios

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

Solution 11 - Ios

Not using maps, just programmatically using a UiButton action, this worked great for me.

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

You could spread some of this code out a bit. For example, I put the variable as a class level variable, had another function fill it, and then when pressed the button simply took what was in the variable and scrubbed it to be used in a URL.

Solution 12 - Ios

Updated to Swift 4 based on @PJeremyMalouf's answer:

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)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTom HammingView Question on Stackoverflow
Solution 1 - Iosnevan kingView Answer on Stackoverflow
Solution 2 - IosTom HammingView Answer on Stackoverflow
Solution 3 - IoszvonicekView Answer on Stackoverflow
Solution 4 - IosFilip RadelicView Answer on Stackoverflow
Solution 5 - IosPJeremyMaloufView Answer on Stackoverflow
Solution 6 - IosEeKayView Answer on Stackoverflow
Solution 7 - IosHoney JainView Answer on Stackoverflow
Solution 8 - IosJohan KoolView Answer on Stackoverflow
Solution 9 - IosJavier Calatrava LlaveríaView Answer on Stackoverflow
Solution 10 - IosVinod JoshiView Answer on Stackoverflow
Solution 11 - IosChristopher Wade CantleyView Answer on Stackoverflow
Solution 12 - IosChris PrinceView Answer on Stackoverflow