打开警报,要求选择应用程序以打开地图

时间:2016-07-07 16:10:14

标签: ios swift dictionary mapkit

我有一个集成了地图套件的视图控制器。我需要在打开地图之前拍摄警报,要求从地图的所有类似应用中进行选择以打开它。例如,如果谷歌地图应用程序安装在我的iPhone中,则应该有一个选项,以及默认的mapkit视图。是否有可能实现此功能,从iphone扫描每个类似的应用程序并返回结果作为打开地图的选项。

5 个答案:

答案 0 :(得分:25)

您可以使用sumesh的回答[1]创建一系列检查以映射已安装的应用:

var installedNavigationApps : [String] = ["Apple Maps"] // Apple Maps is always installed

您可以想到的每个导航应用程序:

if (UIApplication.sharedApplication().canOpenURL(url: NSURL)) {
        self.installedNavigationApps.append(url)
} else {
        // do nothing
}

常见的导航应用是:

  • Google地图 - NSURL(字符串:“comgooglemaps://”)
  • Waze - NSURL(字符串:“waze://”)
  • Navigon - NSURL(字符串:“navigon://”)
  • TomTom - NSURL(字符串:“tomtomhome://”)

可以在http://wiki.akosma.com/IPhone_URL_Schemes

找到更多内容

创建已安装的导航应用程序列表后,您可以呈现UIAlertController:

let alert = UIAlertController(title: "Selection", message: "Select Navigation App", preferredStyle: .ActionSheet)
for app in self.installNavigationApps {
    let button = UIAlertAction(title: app, style: .Default, handler: nil)
    alert.addAction(button)
}
self.presentViewController(alert, animated: true, completion: nil)

当然,您需要使用指定的urlscheme在处理程序中添加按钮单击的行为。例如,如果单击Google地图,请使用以下内容:

UIApplication.sharedApplication().openURL(NSURL(string:
            "comgooglemaps://?saddr=&daddr=\(place.latitude),\(place.longitude)&directionsmode=driving")!) // Also from sumesh's answer

只安装了Apple地图和Google地图,这将产生如下内容:

enter image description here

答案 1 :(得分:10)

快速5 +

基于@Emptyless答案。

to

import MapKit

func openMapButtonAction() {
        let latitude = 45.5088
        let longitude = -73.554

        let appleURL = "http://maps.apple.com/?daddr=\(latitude),\(longitude)"
        let googleURL = "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving"
        let wazeURL = "waze://?ll=\(latitude),\(longitude)&navigate=false"

        let googleItem = ("Google Map", URL(string:googleURL)!)
        let wazeItem = ("Waze", URL(string:wazeURL)!)
        var installedNavigationApps = [("Apple Maps", URL(string:appleURL)!)]

        if UIApplication.shared.canOpenURL(googleItem.1) {
            installedNavigationApps.append(googleItem)
        }

        if UIApplication.shared.canOpenURL(wazeItem.1) {
            installedNavigationApps.append(wazeItem)
        }

        let alert = UIAlertController(title: "Selection", message: "Select Navigation App", preferredStyle: .actionSheet)
        for app in installedNavigationApps {
            let button = UIAlertAction(title: app.0, style: .default, handler: { _ in
                UIApplication.shared.open(app.1, options: [:], completionHandler: nil)
            })
            alert.addAction(button)
        }
        let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        alert.addAction(cancel)
        present(alert, animated: true)
    }

也将它们放在您的info.plist中:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlechromes</string>
    <string>comgooglemaps</string>
    <string>waze</string>
</array>

干杯!

答案 2 :(得分:6)

基于先前答案的Swift 5+解决方案,该解决方案显示了 Apple Maps,Google Maps,Waze和City Mapper 之间的选择器。它还允许使用可选位置标题(对于支持该功能的应用程序),并且仅在选项多于1个时显示警报(如果只有1个选项,它将自动打开或不执行任何操作)。

func openMaps(latitude: Double, longitude: Double, title: String?) {
    let application = UIApplication.shared
    let coordinate = "\(latitude),\(longitude)"
    let encodedTitle = title?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
    let handlers = [
        ("Apple Maps", "http://maps.apple.com/?q=\(encodedTitle)&ll=\(coordinate)"),
        ("Google Maps", "comgooglemaps://?q=\(coordinate)"),
        ("Waze", "waze://?ll=\(coordinate)"),
        ("Citymapper", "citymapper://directions?endcoord=\(coordinate)&endname=\(encodedTitle)")
    ]
        .compactMap { (name, address) in URL(string: address).map { (name, $0) } }
        .filter { (_, url) in application.canOpenURL(url) }

    guard handlers.count > 1 else {
        if let (_, url) = handlers.first {
            application.open(url, options: [:])
        }
        return
    }
    let alert = UIAlertController(title: R.string.localizable.select_map_app(), message: nil, preferredStyle: .actionSheet)
    handlers.forEach { (name, url) in
        alert.addAction(UIAlertAction(title: name, style: .default) { _ in
            application.open(url, options: [:])
        })
    }
    alert.addAction(UIAlertAction(title: R.string.localizable.cancel(), style: .cancel, handler: nil))
    contextProvider.currentViewController.present(alert, animated: true, completion: nil)
}

请注意,此解决方案使用R.swift进行字符串本地化,但是您可以正常地将其替换为NSLocalizedString,并使用contextProvider.currentViewController来获得显示的UIViewController,但是您可以如果您已经在视图控制器中调用它,则将其替换为self

与往常一样,您还需要将以下内容添加到您的应用程序Info.plist:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>citymapper</string>
    <string>comgooglemaps</string>
    <string>waze</string>
</array>

答案 3 :(得分:3)

基于@Angel G. Olloqui 的 SwiftUI 方法回答:

<块引用>
struct YourView: View {
    @State private var showingSheet = false

    var body: some View {
        VStack {
            Button(action: {
                showingSheet = true
            }) {
                Text("Navigate")
            }

        }
        .actionSheet(isPresented: $showingSheet) {
            let latitude = 45.5088
            let longitude = -73.554

            let appleURL = "http://maps.apple.com/?daddr=\(latitude),\(longitude)"
            let googleURL = "comgooglemaps://?daddr=\(latitude),\(longitude)&directionsmode=driving"
            let wazeURL = "waze://?ll=\(latitude),\(longitude)&navigate=false"

            let googleItem = ("Google Map", URL(string:googleURL)!)
            let wazeItem = ("Waze", URL(string:wazeURL)!)
            var installedNavigationApps = [("Apple Maps", URL(string:appleURL)!)]

            if UIApplication.shared.canOpenURL(googleItem.1) {
                installedNavigationApps.append(googleItem)
            }

            if UIApplication.shared.canOpenURL(wazeItem.1) {
                installedNavigationApps.append(wazeItem)
            }
            
            var buttons: [ActionSheet.Button] = []
            for app in installedNavigationApps {
                let button: ActionSheet.Button = .default(Text(app.0)) {
                    UIApplication.shared.open(app.1, options: [:], completionHandler: nil)
                }
                buttons.append(button)
            }
            let cancel: ActionSheet.Button = .cancel()
            buttons.append(cancel)
            
            return ActionSheet(title: Text("Navigate"), message: Text("Select an app..."), buttons: buttons)
        }
    }
}

另外,将以下内容添加到您的 Info.plist

<块引用>
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>googlechromes</string>
    <string>comgooglemaps</string>
    <string>waze</string>
</array>

答案 4 :(得分:0)

对于任何寻求类似东西的人 现在,您可以使用UIActivityViewController,与单击共享按钮时使用的UIControl Photos或Safari相同。

对于苹果地图和谷歌地图,您可以添加自定义应用程序活动以与其他项目一起显示。您需要子类化UIActivity并覆盖title和image方法。然后perform()函数可以处理自定义项目上的点击

下面是我为此编写的目标C代码。 对于Swift代码,您可以参考UIActivityViewController swift

    NSMutableArray *activityArray = [[NSMutableArray alloc] init];
// Check if google maps is installed and accordingly add it in menu
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"comgooglemaps://"]]) {
  GoogleMapsActivityView *googleMapsActivity = [[GoogleMapsActivityView alloc] init];
  [activityArray addObject:googleMapsActivity];
}
// Check if apple maps is installed and accordingly add it in menu
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"maps://"]]) {
  AppleMapsActivityView *appleMapsActivity = [[AppleMapsActivityView alloc] init];
  [activityArray addObject:appleMapsActivity];
}
NSArray *currentPlaces = [NSArray arrayWithObject:place];
UIActivityViewController *activityViewController =
    [[UIActivityViewController alloc] initWithActivityItems:currentPlaces
                                      applicationActivities:activityArray];
activityViewController.excludedActivityTypes = @[UIActivityTypePrint,
                                                 UIActivityTypeCopyToPasteboard,
                                                 UIActivityTypeAssignToContact,
                                                 UIActivityTypeSaveToCameraRoll,
                                                 UIActivityTypePostToWeibo,
                                                 UIActivityTypeAddToReadingList,
                                                 UIActivityTypePostToVimeo,
                                                 UIActivityTypeAirDrop];
[self presentViewController:activityViewController animated:YES completion:nil];

并继承GoogleMapsActivity

@interface GoogleMapsActivityView: UIActivity

@end

@implementation GoogleMapsActivityView

- (NSString *)activityType {
  return @"yourApp.openplace.googlemaps";
}

- (NSString *)activityTitle {
  return NSLocalizedString(@"Open with Google Maps", @"Activity view title");
}

- (UIImage *)activityImage {
  return [UIImage imageNamed:@"ic_google_maps_logo"];
}

- (UIActivityCategory)activityCategory {
  return UIActivityCategoryAction;
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
  return YES;
}

- (void)performActivity {

  CLLocationDegrees lat = 99999;
  CLLocationDegrees lng = 99999;
  NSString *latlong = [NSString stringWithFormat:@"%.7f,%@%.7f", lat, @"", lng];
  NSString *urlString = [NSString stringWithFormat:@"comgooglemaps://?q=%@", latlong];

  if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlString]]) {
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]
                                       options:@{}
                             completionHandler:nil];
  }
  [self activityDidFinish:YES];
}