import Foundation import AMapNaviKit import AVFoundation public class AmapService: NSObject, AMapNaviDriveManagerDelegate { public static let shared = AmapService() private var driveManager: AMapNaviDriveManager? private var startPoint: AMapNaviPoint? private var endPoint: AMapNaviPoint? private var isNavigating = false private override init() { super.init() setupDriveManager() } private func setupDriveManager() { // 使用单例模式初始化 driveManager = AMapNaviDriveManager.sharedInstance() driveManager?.delegate = self driveManager?.isUseInternalTTS = true // 设置高德地图服务 // 1. 设置隐私合规 AMapServices.shared()?.enableHTTPS = true AMapServices.shared()?.apiKey = "0b704e172b7ade5a7a18728e8f517a05" } public func startNavigation(from start: String, to end: String) { guard !isNavigating else { print("导航已在进行中") return } print("开始导航") // 解析坐标 let startCoords = start.split(separator: ",").compactMap { Double($0.trimmingCharacters(in: .whitespaces)) } let endCoords = end.split(separator: ",").compactMap { Double($0.trimmingCharacters(in: .whitespaces)) } guard startCoords.count == 2, endCoords.count == 2 else { print("坐标格式错误,应为'经度,纬度'") return } // 创建导航点(注意:高德地图使用经纬度顺序) startPoint = AMapNaviPoint.location(withLatitude: CGFloat(startCoords[1]), longitude: CGFloat(startCoords[0])) endPoint = AMapNaviPoint.location(withLatitude: CGFloat(endCoords[1]), longitude: CGFloat(endCoords[0])) if let start = startPoint, let end = endPoint { isNavigating = true // 使用推荐的默认策略(避让拥堵+速度优先+避免收费) let strategy: AMapNaviDrivingStrategy = .drivingStrategySingleDefault // 调用最新API(注意参数是数组) let success = driveManager?.calculateDriveRoute(withStart: [start], end: [end], wayPoints: nil, drivingStrategy: strategy) ?? false if !success { isNavigating = false print("路径规划参数校验失败") } } } public func stopNavigation() { driveManager?.stopNavi() isNavigating = false } // MARK: - AMapNaviDriveManagerDelegate public func driveManager(onCalculateRouteSuccess driveManager: AMapNaviDriveManager) { print("Route calculation succeeded") driveManager.startEmulatorNavi() // 使用模拟导航(测试用) // 实际使用时改为: // driveManager.startGPSNavi() } public func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error) { isNavigating = false print("Route calculation failed: \(error.localizedDescription)") } public func driveManager(_ driveManager: AMapNaviDriveManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) { // 过滤空内容和不需要处理的播报类型 guard !soundString.isEmpty else { return } switch soundStringType { case .default: // 默认导航提示(如"前方500米右转"等) playSystemTTS(soundString) case .navigationStart: // 开始导航提示("开始导航"等) playSystemTTS("准备出发," + soundString) case .navigationEnd: // 到达目的地提示 playSystemTTS(soundString + ",导航结束") case .yaw: // 偏航提示("您已偏航,正在重新规划路线"等) playSystemTTS("注意:" + soundString) case .interrupt: // 重要打断播报(如急转弯警告等) interruptCurrentSpeech() playSystemTTS(soundString) default: // 其他未明确处理的类型使用默认播报 playSystemTTS(soundString) } } public func playSystemTTS(_ text: String) { let utterance = AVSpeechUtterance(string: text) utterance.voice = AVSpeechSynthesisVoice(language: "zh-CN") utterance.rate = 0.5 // 适当放慢语速 let synthesizer = AVSpeechSynthesizer() synthesizer.speak(utterance) } public func interruptCurrentSpeech() { AVSpeechSynthesizer().stopSpeaking(at: .immediate) } public func driveManager(_ driveManager: AMapNaviDriveManager, update naviInfo: AMapNaviInfo?) { guard let naviInfo = naviInfo else { return } let currentRoad = naviInfo.currentRoadName ?? "未知道路" let nextRoad = naviInfo.nextRoadName ?? "未知道路" let distance = naviInfo.routeRemainDistance let time = naviInfo.routeRemainTime print(""" 当前道路: \(currentRoad) 下条道路: \(nextRoad) 剩余距离: \(distance)米 剩余时间: \(time)秒 """) } public func driveManager(_ driveManager: AMapNaviDriveManager, error: Error) { isNavigating = false print("Navigation error occurred: \(error.localizedDescription)") } public func driveManagerDidEndEmulatorNavi(_ driveManager: AMapNaviDriveManager) { isNavigating = false print("Emulator navigation ended") } deinit { driveManager?.stopNavi() driveManager?.delegate = nil AMapNaviDriveManager.destroyInstance() } }