前言
最近開發(fā)的項目使用了一些第三方地圖的功能,主要包括:
- 定位
- POI(附近,模糊)搜索
- 地理編碼和逆編碼
- 地圖展示
- 標(biāo)記點(大頭針)
- 線段,圖形,覆蓋物(折線,直線,圓形,不規(guī)則圖形)
- 導(dǎo)航(內(nèi)部導(dǎo)航,跳轉(zhuǎn)其他地圖 App 導(dǎo)航)
- 地理圍欄
主要包含了高德地圖、谷歌地圖等,其他的地圖如百度地圖,騰訊地圖等參考相關(guān)文檔其實差別也不大。
文章主要記錄一下相關(guān)代碼和一些集成調(diào)試踩過的一些坑,防止忘記,歸個檔。
廢話不多說,先看效果:
<img src="https://image-1254431338.cos.ap-guangzhou.myqcloud.com/2020-11-14-105932.png" alt="image-20201114185932086" style="zoom: 25%;" />

ezgif.com-gif-makereee
<img src="https://image-1254431338.cos.ap-guangzhou.myqcloud.com/2020-11-14-111311.gif" style="zoom: 50%;" />
<img src="https://image-1254431338.cos.ap-guangzhou.myqcloud.com/2020-11-14-110809.png" alt="image-20201114190809301" style="zoom:25%;" />
<img src="https://image-1254431338.cos.ap-guangzhou.myqcloud.com/2020-11-14-114426.png" alt="image-20201114194426235" style="zoom:33%;" />
定位
CoreLocation 框架, CLLocationManager 類。
定位 - 系統(tǒng)原生
// 1. 初始化 CLLocationManager 實例
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
// 持續(xù)定位上報
locationManager.allowsBackgroundLocationUpdates = true
// 是否允許中斷定位功能
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.startUpdatingLocation()
// 權(quán)限判斷
let status = CLLocationManager.authorizationStatus()
if status == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
if status == .denied || status == .restricted {
let alert = UIAlertController(title: "定位權(quán)限未開啟", message: "請前往設(shè)置允許訪問您的定位權(quán)限", preferredStyle: .alert)
let okAction = UIAlertAction(title: "去開啟", style: .default, handler: { _ in
// 打開設(shè)置
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
})
alert.addAction(okAction)
let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.shared.visibleVC().present(alert, animated: true, completion: nil)
return
}
// 3. 代理回調(diào) CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let currentLocation = locations.last
// 得到經(jīng)緯度
let currentCoordinate2D = currentLocation?.coordinate
guard let latitude = currentCoordinate2D?.latitude, let longitude = currentCoordinate2D?.longitude else { return }
// 定位成功后停止定位
locationManager.stopUpdatingLocation()
}
// 發(fā)生錯誤
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
定位 - 高德定位
- 在高德開放平臺注冊賬號
- 新建應(yīng)用
- 拿到 key,在 App 啟動的時候設(shè)置
// 設(shè)置 key
AMapServices.shared()?.apiKey = "\(appKey)"
// 1. 初始化 AMapLocationManager 實例
private lazy var locationManager : AMapLocationManager = {
let managner = AMapLocationManager()
managner.delegate = self
managner.pausesLocationUpdatesAutomatically = false
// 定位精度
managner.desiredAccuracy = kCLLocationAccuracyBest
// 是否允許后臺定位
managner.allowsBackgroundLocationUpdates = false
// 指定單次定位超時時間,默認(rèn)為10s。最小值是2s。注意單次定位請求前設(shè)置。注意: 單次定位超時時間從確定了定位權(quán)限(非kCLAuthorizationStatusNotDetermined狀態(tài))后開始計算。
manager.locationTimeout = 2
// 指定單次定位逆地理超時時間,默認(rèn)為5s。最小值是2s。注意單次定位請求前設(shè)置。
manager.reGeocodeTimeout = 2
return managner
}()
// 2. 開始連續(xù)定位。調(diào)用此方法會cancel掉所有的單次定位請求。
locationManager.startUpdatingLocation()
// 3. 停止連續(xù)定位。調(diào)用此方法會cancel掉所有的單次定位請求,可以用來取消單次定位。
locationManager.stopUpdatingLocation()
// 4. 單次定位。如果當(dāng)前正在連續(xù)定位,調(diào)用此方法將會失敗,返回NO。\n該方法將會根據(jù)設(shè)定的 desiredAccuracy 去獲取定位信息。如果獲取的定位信息精確度低于 desiredAccuracy ,將會持續(xù)的等待定位信息,直到超時后通過completionBlock返回精度最高的定位信息。\n可以通過 stopUpdatingLocation 方法去取消正在進行的單次定位請求。
// withReGeocode: 是否帶有逆地理信息(獲取逆地理信息需要聯(lián)網(wǎng))
locationManager.requestLocation(withReGeocode: true) { (location, regeocode, error) in
guard error == nil else { return }
guard let regeocode = regeocode else { return }
print(regeocode)
}
// 5. 代理回調(diào) AMapLocationManagerDelegate
// 定位成功
func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode!) {
}
// 定位失敗
func amapLocationManager(_ manager: AMapLocationManager!, didFailWithError error: Error!) {
}
// 請求定位授權(quán)
func amapLocationManager(_ manager: AMapLocationManager!, doRequireLocationAuth locationManager: CLLocationManager!) {
locationManager.requestAlwaysAuthorization()
}
定位 - Google 定位
- 在 https://cloud.google.com/maps-platform/ 平臺注冊開發(fā)者賬號
- 申請 API key
image-20201114173121575
// 設(shè)置 API key
GMSServices.provideAPIKey("\(Google API key)")
POI(Point of Interest,興趣點)&& 地理編碼、逆編碼 && 路徑規(guī)劃
POI(Point of Interest,興趣點)&& 地理編碼、逆編碼 && 路徑規(guī)劃 - 高德地圖
高德地圖 SDK 封裝了 AMapSearchObject 基類對象,具體的搜搜請求對象和響應(yīng)對象都由子類去繼承實現(xiàn)。
// 1、初始化搜索對象,設(shè)置代理
private lazy var search: AMapSearchAPI = {
let object = AMapSearchAPI()!
object.delegate = self
return object
}()
//--------- 附近 :構(gòu)造請求對象 -----------
let request = AMapPOIAroundSearchRequest()
// 當(dāng)?shù)囟ㄎ唤?jīng)緯度
request.location = AMapGeoPoint.location(withLatitude: currentCoordinate!.latitude.cgFloat, longitude: currentCoordinate!.longitude.cgFloat)
request.sortrule = 0
// 類型,多個類型用“|”分割 可選值:文本分類、分類代碼
// 高德地圖的POI類別共20個大類,分別為:汽車服務(wù)、汽車銷售、汽車維修、摩托車服務(wù)、餐飲服務(wù)、購物服務(wù)、生活服務(wù)、體育休閑服務(wù)、醫(yī)療保健服務(wù)、住宿服務(wù)、風(fēng)景名勝、商務(wù)住宅、政府機構(gòu)及社會團體、科教文化服務(wù)、交通設(shè)施服務(wù)、金融保險服務(wù)、公司企業(yè)、道路附屬設(shè)施、地名地址信息、公共設(shè)施,同時,每個大類別都還有二級以及三級的細(xì)小劃。
request.types = "風(fēng)景名勝|(zhì)商務(wù)住宅|政府機構(gòu)及社會團體|交通設(shè)施服務(wù)|公司企業(yè)|道路附屬設(shè)施|地名地址信息"
request.requireExtension = true
// 當(dāng)前頁數(shù)
request.page = page
request.requireSubPOIs = true
// 發(fā)起搜索
search.aMapPOIAroundSearch(request)
// ----------------- 關(guān)鍵詞搜索 構(gòu)造請求對象 ------------------------------
let request = AMapPOIKeywordsSearchRequest()
request.keywords = keywords
// 指定城市
request.city = city
request.sortrule = 0
request.requireExtension = true
request.page = page
request.cityLimit = false
request.requireSubPOIs = true
request.types = "風(fēng)景名勝|(zhì)商務(wù)住宅|政府機構(gòu)及社會團體|交通設(shè)施服務(wù)|公司企業(yè)|道路附屬設(shè)施|地名地址信息"
// 關(guān)鍵詞搜索 - 高德: 發(fā)起關(guān)鍵詞搜索
search.aMapPOIKeywordsSearch(request)
// ----------- 地理編碼:地理編碼,又稱為地址匹配,是從已知的地址描述到對應(yīng)的經(jīng)緯度坐標(biāo)的轉(zhuǎn)換過程。該功能適用于根據(jù)用戶輸入的地址確認(rèn)用戶具體位置的場景,常用于配送人員根據(jù)用戶輸入的具體地址找地點。-----------
let request = AMapGeocodeSearchRequest()
// 位置信息:地理編碼是依據(jù)當(dāng)前輸入,根據(jù)標(biāo)準(zhǔn)化的地址結(jié)構(gòu)(省/市/區(qū)或縣/鄉(xiāng)/村或社區(qū)/商圈/街道/門牌號/POI)進行各個地址級別的匹配,以確認(rèn)輸入地址對應(yīng)的地理坐標(biāo),只有返回的地理坐標(biāo)匹配的級別為POI,才會對應(yīng)一個具體的地物(POI)。
request.address = address
// 發(fā)起地理編碼搜索請求
search.aMapGeocodeSearch(request)
// -------------------------------- AMapSearchDelegate --------------------------------------
// POI 搜索回調(diào)
func onPOISearchDone(_ request: AMapPOISearchBaseRequest!, response: AMapPOISearchResponse!) {
if response.count == 0 {
return
}
//解析response獲取POI信息
}
// 地理編碼(地址轉(zhuǎn)坐標(biāo))回調(diào)
func onGeocodeSearchDone(_ request: AMapGeocodeSearchRequest!, response: AMapGeocodeSearchResponse!) {
// 解析response獲取地理信息,
}
// 路線規(guī)劃
func onRouteSearchDone(_ request: AMapRouteSearchBaseRequest!, response: AMapRouteSearchResponse!) {
if response.count > 0 {
//解析response獲取路徑信息
}
}
// 搜索出現(xiàn)錯誤
func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
}
POI(Point of Interest,興趣點)&& 地理編碼、逆編碼 && 路徑規(guī)劃 - Google 地圖
Google 地圖這些 POI 搜索,導(dǎo)航數(shù)據(jù)這些,提供的是 HTTP API 請求調(diào)用的方式。
// 谷歌地圖 POI 關(guān)鍵詞模糊搜索
// https://maps.googleapis.com/maps/api/place/textsearch/json
var params: [String: Any] = [:]
params["key"] = "\(Google API key)"
// 語言 :
params["language"] = "en"
params["query"] = "\(關(guān)鍵詞文本)"
params["inputType"] = "textQuery"
// params["region"] =
// 谷歌地圖 POI 附近搜索
// https://maps.googleapis.com/maps/api/place/nearbysearch/json
var params: [String: Any] = [:]
params["key"] = "\(Google API key)"
// 語言 :
params["language"] = "en"
// 當(dāng)前位置 字符串: "緯度,經(jīng)度"
params["location"] = "\(latitude,longitude)"
// 搜索半徑 (單位:米)
params["radius"] = "\(1500)"
// 谷歌地理編碼
// https://maps.googleapis.com/maps/api/geocode/json
var params: [String: Any] = [:]
params["key"] = "\(Google API key)"
// 地址文本
params["address"] = address
// 谷歌地址逆編碼
// https://maps.googleapis.com/maps/api/geocode/json
var params: [String: Any] = [:]
params["key"] = "\(Google API key)"
params["latlng"] = location.googleDisplay
return .requestParameters(parameters: params,
encoding: URLEncoding.default)
// 谷歌路線導(dǎo)航,默認(rèn)駕車
// https://maps.googleapis.com/maps/api/directions/json
var params: [String: Any] = [:]
params["key"] = "\(Google API key)"
// 出發(fā)點坐標(biāo)位置
params["origin"] = "\(latitude,longitude)"
// 目的地坐標(biāo)位置
params["destination"] = "\(latitude,longitude)"
// 解析相應(yīng)數(shù)據(jù),模型轉(zhuǎn)換框架使用的是 ObjectMapper
/// 列表容器模型
struct ListContainerModel<T: Mappable>: Mappable {
var list: [T]?
var numberOfElements: Int?
var total: Int?
var pageNumber: Int?
var size: Int?
var hasNextPage: Bool?
var hasPreviousPage: Bool?
init?(map: Map) {
}
mutating func mapping(map: Map) {
list <- map["list"]
numberOfElements <- map["numberOfElements"]
total <- map["total"]
pageNumber <- map["pageNumber"]
size <- map["size"]
hasNextPage <- map["hasNextPage"]
hasPreviousPage <- map["hasPreviousPage"]
}
}
/// google POI 附近和關(guān)鍵詞地址搜索
struct GoogleSearchAddressContainerModel: Mappable {
var html_attributions: [Any]?
/// POI 列表
var results: [SearchAddressModel]?
/// 返回結(jié)果狀態(tài)
var status: String?
init?(map: Map) {
}
mutating func mapping(map: Map) {
html_attributions <- map["html_attributions"]
results <- map["results"]
status <- map["status"]
}
}
/// leg Model
struct GoogleDirectionLegModel: Mappable {
var distance: Any?
var duration: Any?
var end_address: String?
var end_location: GeometryLocation?
var start_address: String?
var start_location: GeometryLocation?
var steps: [GoogleDirectionAddressModel]?
init?(map: Map) {
}
mutating func mapping(map: Map) {
steps <- map["steps"]
}
}
/// 谷歌地圖返回結(jié)果模型
struct GoogleDirectionResultModel: Mappable {
var steps: [GoogleDirectionAddressModel]? {
get {
var result = [GoogleDirectionAddressModel]()
legs?.forEach({ (leg) in
result.append(contentsOf: leg.steps ?? [])
})
return result
}
}
var legs: [GoogleDirectionLegModel]?
var points: String?
init?(map: Map) {
}
mutating func mapping(map: Map) {
legs <- map["routes.0.legs"]
points <- map["routes.0.overview_polyline.points"]
}
}
標(biāo)記點(大頭針 annotation || Marker)
標(biāo)記點(大頭針 annotation || Marker)- 高德
// 1. 創(chuàng)建地圖對象
let gaodeMap = MAMapView()
gaodeMap.delegate = self
// 縮放級別
zoomLevel = 17
// 是否顯示用戶位置
isShowsUserLocation = true
// 自定義地圖樣式(1. 在高德地圖開發(fā)者應(yīng)用后臺新建地圖樣式,下載樣式的資源包拖到工程里面去)
guard let url = R.file.styleData(),
let data = try? Data(contentsOf: url) else { return }
let options = MAMapCustomStyleOptions()
options.styleData = data
setCustomMapStyleOptions(options)
customMapStyleEnabled = true
// 設(shè)定當(dāng)前地圖的經(jīng)緯度范圍,該范圍可能會被調(diào)整為適合地圖窗口顯示的范圍
setRegion(MACoordinateRegion(center: centerCoordinate, span: MACoordinateSpan(latitudeDelta: 0.03, longitudeDelta: 0.03)), animated: false)
// 2. 新建標(biāo)注
let pointAnnotation = MAPointAnnotation()
// 標(biāo)注中心點經(jīng)緯度坐標(biāo)
pointAnnotation.coordinate = center
// 標(biāo)注標(biāo)題
pointAnnotation.title = title
// 標(biāo)注副標(biāo)題
pointAnnotation.subtitle = subTitle
// 添加標(biāo)注
gaodeMap.addAnnotation(pointAnnotation
// 選中標(biāo)注數(shù)據(jù)對應(yīng)的view。注意:如果annotation對應(yīng)的annotationView因不在屏幕范圍內(nèi)而被移入復(fù)用池,為了完成選中操作,會將對應(yīng)的annotationView添加到地圖上,并將地圖中心點移至annotation.coordinate的位置。
gaodeMap.selectAnnotation(pointAnnotation, animated: false)
// 設(shè)置標(biāo)注 的外觀樣式
// MAMapViewDelegate
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
if annotation.isKind(of: MAPointAnnotation.self) {
let pointReuseIndetifier = "pointReuseIndetifier"
var annotationView: MAPinAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as! MAPinAnnotationView?
if annotationView == nil {
annotationView = MAPinAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
}
// 是否可以點擊標(biāo)注view
annotationView!.canShowCallout = true
// 是否有標(biāo)注添加到地圖上的動畫效果(從上而下)
annotationView!.animatesDrop = true
// 是否可以拖拽
annotationView!.isDraggable = true
// 是否有右邊的視圖
annotationView!.rightCalloutAccessoryView = nil
return annotationView!
}
return nil
}
// 移除標(biāo)注
gaodeMap.removeAnnotation(pointAnnotation)
標(biāo)記點(大頭針 annotation || Marker)- Google
// 創(chuàng)建 Google map
let googleMap = GMSMapView()
// 添加標(biāo)注 Marker
// 創(chuàng)建 GMSMarker 對象
let marker = GMSMarker()
// 標(biāo)注位置
marker.position = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
// 標(biāo)注標(biāo)題
marker.title = title
// 標(biāo)注副標(biāo)題
marker.snippet = subTitle
// 設(shè)置標(biāo)注的圖片
marker.icon = UIImage()
// 設(shè)置
let camera = GMSCameraPosition.camera(withLatitude: marker.position.latitude, longitude: marker.position.longitude, zoom: 16.0)
marker.map = googleMap
// 自動顯示標(biāo)題內(nèi)容
selectedMarker = marker
// 移除標(biāo)注
marker.map = nil
Overlay && Polyline
Overlay && Polyline - 高德
// 多線段的坐標(biāo)點數(shù)組
var lineCoordinates = [CLLocationCoordinate2D]()
// 多邊形
let pol = MAPolygon(coordinates: &lineCoordinates, count: UInt(lineCoordinates.count))
gaodeMap.add(pol)
// 不是多邊形
let polyline: MAPolyline = MAPolyline(coordinates: &lineCoordinates, count: UInt(lineCoordinates.count))
gaodeMap.addOverlays([polyline])
// 展示路線
showOverlays([polyline], animated: false)
// 移除
removeOverlays(polyline)
Overlay && Polyline - Google
// 多線段的坐標(biāo)點數(shù)組
var lineCoordinates = [CLLocationCoordinate2D]()
// 多邊形路徑
let gmsPath = GMSMutablePath()
lineCoordinates.forEach { (location) in
if let latitude = location.latitude, let longitude = location.longitude {
gmsPath.addLatitude(latitude, longitude: longitude)
}
}
let polyline = GMSPolyline(path: gmsPath)
// 設(shè)置線段顏色
polyline.strokeColor = UIColor._themeColor()
// 設(shè)置線段寬度
polyline.strokeWidth = 8.0
// 顯示出來
polyline.map = googleMap
// 移除
polyline.map = nil
地理圍欄
POI 圍欄
行政區(qū)劃 圍欄
自定義圓形圍欄
自定義多邊圍欄
// 創(chuàng)建圍欄對象
lazy var geoFenceManager: AMapGeoFenceManager = {
let manager = AMapGeoFenceManager()
//進入,離開,停留都要進行通知
manager.activeAction = [AMapGeoFenceActiveAction.inside , AMapGeoFenceActiveAction.outside , AMapGeoFenceActiveAction.stayed]
manager.allowsBackgroundLocationUpdates = false // 允許后臺定位
manager.delegate = self
return manager
}()
// 創(chuàng)建行政區(qū)域地理圍欄
geoFenceManager.addDistrictRegionForMonitoring(withDistrictName: "深圳市", customID: "city")
// 添加圓形圍欄
// withCenter: 圍欄中心點
// radius: 圍欄半徑
geoFenceManager.addCircleRegionForMonitoring(withCenter: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), radius: 500, customID: "123456")
// 移除圍欄
// 設(shè)置圓形圍欄樣式
// 渲染多邊型 --- MAMapViewDelegate
func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
if overlay.isKind(of: MACircle.self) {
let renderer: MACircleRenderer = MACircleRenderer(overlay: overlay)
renderer.lineWidth = 1.0
renderer.strokeColor = UIColor.gxd_themeColor()
renderer.fillColor = UIColor.gxd_themeColor().withAlphaComponent(0.4)
return renderer
}
return nil
}
// MARK: - AMapGeoFenceManagerDelegate
// 圍欄創(chuàng)建完成
func amapGeoFenceManager(_ manager: AMapGeoFenceManager!, didAddRegionForMonitoringFinished regions: [AMapGeoFenceRegion]!, customID: String!, error: Error!) {
if let error = error {
let error = error as NSError
NSLog("創(chuàng)建失敗 %@",error);
}
else {
NSLog("創(chuàng)建成功")
let circleRegion = regions.first as? AMapGeoFenceCircleRegion
// 在地圖上畫一個區(qū)域
guard let center = circleRegion?.center,
let radius = circleRegion?.radius else { return }
let circle: MACircle = MACircle(center: CLLocationCoordinate2D(latitude: center.latitude, longitude: center.longitude), radius: CLLocationDistance(radius))
gaodeMap.add(circle)
}
}
// 圍欄狀態(tài)改變時 用戶未知、進入圍欄、退出圍欄、在圍欄內(nèi)停留
func amapGeoFenceManager(_ manager: AMapGeoFenceManager!, didGeoFencesStatusChangedFor region: AMapGeoFenceRegion!, customID: String!, error: Error!) {
if error == nil {
print("status changed \(region.description)")
} else {
print("status changed error \(error)")
}
}
導(dǎo)航
跳轉(zhuǎn)到第三方地圖 App 發(fā)起導(dǎo)航,先要在 InfoPlist 文件里面配置 QueriesSchemes 字段
<key>LSApplicationQueriesSchemes</key>
<array>
<string>comgooglemaps</string>
<string>iosamap</string>
<string>baidumap</string>
</array>
發(fā)起導(dǎo)航:
/// 地圖導(dǎo)航模式
enum MapDirectionMode {
// 駕車
case driving
// 步行
case walking
// 騎行
case bicycling
// 公共交通
case transit
}
struct DirectionParams {
/// 源 App 名稱
var sourceApplication: String = U""
/// 源 App scheme url
var backScheme: String = "\(appUrlScheme)"
/// 起始地點
var origin: Location?
/// 目的地點
var destination: Location
/// 導(dǎo)航模式
var mode: MapDirectionMode = .driving
}
/// 打開蘋果地圖導(dǎo)航
/// - Parameter params: 參數(shù)
static func openAppleMapDirection(withParams params: DirectionParams) {
guard let latitude = params.destination.latitude,
let longitude = params.destination.longitude else { return }
let currentLocation = MKMapItem.forCurrentLocation()
let toPlacemark = MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
let toLocation = MKMapItem(placemark: toPlacemark)
toLocation.name = params.destination.name
MKMapItem.openMaps(with: [currentLocation, toLocation], launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
}
/// 打開 google 地圖導(dǎo)航
/// - Parameter params: 參數(shù)
static func openGoogleMapDirection(withParams params: DirectionParams) {
if !Keys.MapSchemeUrl.google.isInstalled { return }
guard var daddr = params.destination.name else {
return
}
daddr = daddr.replacingOccurrences(of: " ", with: "+", options: .literal, range: nil)
let urlString = Keys.MapSchemeUrl.google.rawValue + "?" + "x-source=\(params.sourceApplication)&x-success=\(params.backScheme)&saddr=&daddr=\(daddr)&directionsmode=driving"
guard let url = URL(string: urlString) else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
/// 打開 百度 地圖導(dǎo)航
/// - Parameter params: 參數(shù)
static func openBaiduMapDirection(withParams params: DirectionParams) {
if !Keys.MapSchemeUrl.baidu.isInstalled { return }
guard let destinationLatitude = params.destination.latitude,
let destinationLongitude = params.destination.longitude else { return }
let destinationName = params.destination.name ?? ""
let urlString = Keys.MapSchemeUrl.baidu.rawValue + "map/direction?origin=name:{{我的位置}}&destination=name:\(destinationName)|latlng:\(destinationLatitude),\(destinationLongitude)&mode=driving&coord_type=bd09ll&src=ios.Express.\(params.sourceApplication)"
guard let url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
/// 打開 高德 地圖導(dǎo)航
/// - Parameter params: 參數(shù)
static func openGaodeMapDirection(withParams params: DirectionParams) {
if !Keys.MapSchemeUrl.gaode.isInstalled { return }
guard let latitude = params.destination.latitude,
let longitude = params.destination.longitude else { return }
let destinationName = params.destination.name ?? ""
let urlString = Keys.MapSchemeUrl.gaode.rawValue + "path?sourceApplication=\(params.sourceApplication)&backScheme=\(params.backScheme)&dlat=\(latitude)&dlon=\(longitude)&dname=\(destinationName)&dev=0&t=0"
guard let url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "") else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
