【发布时间】:2016-11-10 01:30:33
【问题描述】:
我有一个集成了地图工具包的视图控制器。我需要在打开该地图之前发出警报,要求从所有类似的地图应用程序中进行选择以打开它。例如,如果我的 iPhone 中安装了 google maps 应用程序,则应该有一个选项,以及默认的 mapkit 视图。是否有可能实现此功能,即从 iphone 扫描每个类似的应用程序并将结果作为打开地图的选项返回。
【问题讨论】:
标签: ios swift dictionary mapkit
我有一个集成了地图工具包的视图控制器。我需要在打开该地图之前发出警报,要求从所有类似的地图应用程序中进行选择以打开它。例如,如果我的 iPhone 中安装了 google maps 应用程序,则应该有一个选项,以及默认的 mapkit 视图。是否有可能实现此功能,即从 iphone 扫描每个类似的应用程序并将结果作为打开地图的选项返回。
【问题讨论】:
标签: ios swift dictionary mapkit
基于@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>
【讨论】:
基于先前答案的 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>
【讨论】:
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>
干杯!
【讨论】:
对于寻找类似东西的其他人 您现在可以使用 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];
}
【讨论】:
您可以使用 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
}
常见的导航应用有:
更多内容请访问: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,这将产生如下内容:
【讨论】: