You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
6.0 KiB

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 = "6144a636c24dc9f2e1e57f7597849cf7"
}
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()
}
}