jsdw_ios/QuickLocation/Section/Map/Navigation/NavigationVC.swift

323 lines
12 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// NavigationVC.swift
// QuickLocation
//
// Created by on 2026/6/16.
//
import UIKit
import RxSwift
import RxCocoa
import CoreLocation
#if !targetEnvironment(simulator)
import AMapNaviKit
import MapKit
#endif
class NavigationVC: BaseViewController {
override var isNavigationBarHidden: Bool { true }
fileprivate var rootView: NavigationView!
private let member: CircleMember
private let currentUserCoord: CLLocationCoordinate2D?
private let groupName: String
private let groupIconIndex: String
#if !targetEnvironment(simulator)
private var routeOverlay: MAPolyline?
#endif
init(member: CircleMember, currentUserCoord: CLLocationCoordinate2D?, groupName: String = "", groupIcon: String = "") {
self.member = member
self.currentUserCoord = currentUserCoord
self.groupName = groupName
self.groupIconIndex = groupIcon
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
rootView = NavigationView(frame: UIScreen.main.bounds)
view = rootView
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// pop/dismiss
if isMovingFromParent || isBeingDismissed {
#if !targetEnvironment(simulator)
rootView.cleanupMap()
#endif
}
}
override func viewDidLoad() {
super.viewDidLoad()
rootView.configure(member: member, groupName: groupName, groupIcon: groupIconIndex)
reactiveAction()
setupMap()
calculateDistance()
requestRoute()
}
// MARK: - Actions
private func reactiveAction() {
rootView.navigationBtn.rx.tap.subscribe(onNext: { _ in
self.touchGoMap()
}).disposed(by: disposeBag)
}
private func setupMap() {
#if !targetEnvironment(simulator)
rootView.mapView.delegate = self
//
if let from = currentUserCoord, CLLocationCoordinate2DIsValid(from) {
let startAnn = MAPointAnnotation()
startAnn.coordinate = from
startAnn.title = "起点"
rootView.mapView.addAnnotation(startAnn)
}
#endif
}
private func requestRoute() {
#if !targetEnvironment(simulator)
guard let from = currentUserCoord,
CLLocationCoordinate2DIsValid(from),
CLLocationCoordinate2DIsValid(member.coordinate) else { return }
let naviManager = AMapNaviDriveManager.sharedInstance()
naviManager.delegate = self
guard let startPoint = AMapNaviPoint.location(withLatitude: CGFloat(from.latitude), longitude: CGFloat(from.longitude)),
let endPoint = AMapNaviPoint.location(withLatitude: CGFloat(member.coordinate.latitude), longitude: CGFloat(member.coordinate.longitude)) else { return }
naviManager.calculateDriveRoute(withStart: [startPoint], end: [endPoint], wayPoints: nil, drivingStrategy: .drivingStrategySingleDefault)
#endif
}
private func calculateDistance() {
guard CLLocationCoordinate2DIsValid(member.coordinate) else { return }
let memberLoc = CLLocation(latitude: member.coordinate.latitude, longitude: member.coordinate.longitude)
guard let userLoc = currentUserCoord.map({ CLLocation(latitude: $0.latitude, longitude: $0.longitude) }) else {
rootView.distanceLab.text = ""
return
}
let dist = memberLoc.distance(from: userLoc)
if dist < 1000 {
rootView.distanceLab.text = "距离 \(Int(dist))"
} else {
rootView.distanceLab.text = "距离 \(String(format: "%.1f", dist / 1000)) 公里"
}
}
func touchGoMap() {
let coortitle = "目的地"
let latitute = member.coordinate.latitude
let longitute = member.coordinate.longitude
// ""
let alert = UIAlertController(title: "请选择导航应用程序", message: nil, preferredStyle: .actionSheet)
if canOpenUrl("iosamap://") {//
alert.addAction(UIAlertAction(title: "高德地图", style: .default, handler: { _ in
self.amap(dlat: latitute, dlon: longitute, dname: coortitle, way: 0)
}))
}
if canOpenUrl("baidumap://") {//
alert.addAction(UIAlertAction(title: "百度地图", style: .default, handler: { _ in
self.baidumap(endAddress: coortitle, way: "driving", lat: latitute,lng: longitute)
}))
}
if canOpenUrl("qqmap://") {//
alert.addAction(UIAlertAction(title: "腾讯地图", style: .default, handler: { _ in
self.qqmap(endAddress: coortitle, way: "driving", lat: latitute,lng: longitute)
}))
}
alert.addAction(UIAlertAction(title: "Apple 地图", style: .default, handler: { _ in
self.appleMap(lat:latitute , lng:longitute, destination: coortitle)
}))
alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
#if !targetEnvironment(simulator)
// MARK: - AMapNaviDriveManagerDelegate
extension NavigationVC: AMapNaviDriveManagerDelegate {
func driveManager(onCalculateRouteSuccess driveManager: AMapNaviDriveManager) {
guard let route = driveManager.naviRoute else { return }
if let overlay = routeOverlay {
rootView.mapView.remove(overlay)
}
let coords = route.routeCoordinates.compactMap { point -> CLLocationCoordinate2D in
return CLLocationCoordinate2D(latitude: Double(point.latitude), longitude: Double(point.longitude))
}.filter { CLLocationCoordinate2DIsValid($0) }
guard coords.count > 1 else { return }
var mutableCoords = coords
if let polyline = MAPolyline(coordinates: &mutableCoords, count: UInt(coords.count)) {
rootView.mapView.add(polyline)
routeOverlay = polyline
rootView.mapView.setVisibleMapRect(polyline.boundingMapRect, edgePadding: UIEdgeInsets(top: 80, left: 50, bottom: 260, right: 50), animated: true)
}
let distM = Int(route.routeLength)
if distM < 1000 {
rootView.distanceLab.text = "距离 \(distM)"
} else {
rootView.distanceLab.text = "距离 \(String(format: "%.1f", Double(distM) / 1000)) 公里"
}
let endAnn = MAPointAnnotation()
endAnn.coordinate = member.coordinate
endAnn.title = member.name
rootView.mapView.addAnnotation(endAnn)
}
func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error) {
print("Navi route failed: \(error.localizedDescription)")
}
}
// MARK: - MAMapViewDelegate
extension NavigationVC: MAMapViewDelegate {
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
if annotation is MAUserLocation { return nil }
let identifier = "NavEnd"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if view == nil {
view = MAAnnotationView(annotation: annotation, reuseIdentifier: identifier)
} else {
view?.annotation = annotation
}
let isEnd = annotation.title == member.name
view?.image = UIImage(named: isEnd ? "Map/end" : "Map/current")
view?.centerOffset = CGPoint(x: 0, y: -22)
return view
}
func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
if let polyline = overlay as? MAPolyline {
let renderer = MAPolylineRenderer(polyline: polyline)
renderer?.strokeColor = UIColor(hexStr: "34B824")
renderer?.lineWidth = 6
return renderer
}
return nil
}
}
#endif
// MARK: -
extension NavigationVC {
//
func appleMap(lat: Double, lng: Double, destination: String) {
let loc = CLLocationCoordinate2DMake(lat, lng)
let currentLocation = MKMapItem.forCurrentLocation()
let toLocation = MKMapItem(placemark:MKPlacemark(coordinate:loc,addressDictionary:nil))
toLocation.name = destination
let boo = MKMapItem.openMaps(with: [currentLocation,toLocation], launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving,MKLaunchOptionsShowsTrafficKey: NSNumber(value: true)])
print(boo)
}
//
func amap(dlat: Double, dlon: Double, dname: String, way: Int) {
let appName = "极速定位"
let urlString = "iosamap://path?sourceApplication=\(appName)&dname=\(dname)&dlat=\(dlat)&dlon=\(dlon)&t=\(way)" as String
if self.openMap(urlString) == false {
print("您还没有安装高德地图")
let urlString = "itms-apps://itunes.apple.com/app/id452186370"
self.openURL(urlString: urlString)
}
}
//
func qqmap(endAddress: String, way: String, lat: Double, lng: Double) {
let urlString = "qqmap://map/routeplan?type=\(way)&from=&fromcoord=CurrentLocation&to=\(endAddress)&tocoord=\(lat),\(lng)&referer=腾讯需要申请APPkey"
let str = urlString as String
if self.openMap(str) == false {
print("您还没有安装腾讯地图")
let urlString = "itms-apps://itunes.apple.com/app/id481623196"
self.openURL(urlString: urlString)
}
}
//
func baidumap(endAddress: String, way: String, lat: Double, lng: Double) {
let coordinate = CLLocationCoordinate2DMake(lat, lng)
//
let baiduCoordinate = getBaiDuCoordinateByGaoDeCoordinate(coordinate: coordinate)
let destination = "\(baiduCoordinate.latitude),\(baiduCoordinate.longitude)"
let urlString = "baidumap://map/direction?" + "&destination=" + endAddress + "&mode=" + way + "&destination=" + destination
let str = urlString as String
if self.openMap(str) == false {
print("您还没有安装百度地图")
let urlString = "itms-apps://itunes.apple.com/app/id452186370" as String
self.openURL(urlString: urlString)
}
}
//
private func openMap(_ urlString: String) -> Bool {
let urlstr = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? ""
guard let url = URL(string: urlstr) else {
return false
}
if UIApplication.shared.canOpenURL(url) == true {
self.openURL(urlString: urlString as String)
return true
} else {
return false
}
}
func openURL(urlString:String) {
let urlstr = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) ?? ""
guard let url = URL(string:urlstr) else {
return
}
//iOS
if #available(iOS 10, *) {
UIApplication.shared.open(url , options: [:],
completionHandler: { (success) in
})
} else {
UIApplication.shared.openURL(url )
}
}
//
//
func getBaiDuCoordinateByGaoDeCoordinate(coordinate:CLLocationCoordinate2D) -> CLLocationCoordinate2D {
return CLLocationCoordinate2DMake(coordinate.latitude + 0.006, coordinate.longitude + 0.0065)
}
func canOpenUrl(_ urlString: String) -> Bool {
guard let url = URL(string: urlString) else { return false }
print("\(url) \(UIApplication.shared.canOpenURL(url))")
return UIApplication.shared.canOpenURL(url)
}
}