【问题标题】:Open an Alert asking to choose App to open map with打开一个警报,要求选择应用程序来打开地图
【发布时间】:2016-11-10 01:30:33
【问题描述】:

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

【问题讨论】:

    标签: ios swift dictionary mapkit


    【解决方案1】:

    基于@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>
    

    【讨论】:

      【解决方案2】:

      基于先前答案的 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】:

        Swift 5+

        基于@Emptyless 答案。

        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>
        

        干杯!

        【讨论】:

          【解决方案4】:

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

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

          下面是我为此编写的 Objective 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];
          }
          

          【讨论】:

            【解决方案5】:

            您可以使用 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
            }
            

            常见的导航应用有:

            • 谷歌地图 - NSURL(string:"comgooglemaps://")
            • 位智 - NSURL(string:"waze://")
            • Navigon - NSURL(string:"navigon://")
            • TomTom - NSURL(string:"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 Maps 和 Google Maps,这将产生如下内容:

            【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-09-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-31
            • 1970-01-01
            • 2017-09-29
            • 1970-01-01
            相关资源
            最近更新 更多