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.

315 lines
13 KiB

import UIKit
import AVFAudio
import AMapNaviKit
class AmapViewController: UIViewController {
// MARK: - 必须声明为强引用
private var driveManager: AMapNaviDriveManager!
private var driveView: AMapNaviDriveView!
private let speechSynthesizer = AVSpeechSynthesizer()
private var startPoint: AMapNaviPoint!
private var endPoint: AMapNaviPoint!
// 自定义初始化方法
init(startpos: String, endpos: String) {
super.init(nibName: nil, bundle: nil)
self.startPoint = AmapViewController.parseCoord(from: startpos)
self.endPoint = AmapViewController.parseCoord(from: endpos)
print("导航---------------------: \(startPoint) \(endPoint)")
}
// 解析 "lat,lng" -> AMapNaviPoint
private static func parseCoord(from string: String) -> AMapNaviPoint? {
let components = string.split(separator: ",")
guard components.count == 2,
let lng = Double(components[0]),
let lat = Double(components[1]) else {
print("❌ 无效坐标格式: \(string)")
return nil
}
return AMapNaviPoint.location(withLatitude: lat, longitude: lng)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupAMapComponents()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 页面即将消失时停止导航
if driveManager != nil {
driveManager.stopNavi()
driveManager.allowsBackgroundLocationUpdates = false
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// 页面完全消失后清理资源
cleanupResources()
}
private func cleanupResources() {
print("开始清理导航资源")
// 停止语音合成
speechSynthesizer.stopSpeaking(at: .immediate)
// 如果导航管理器存在,进行清理
if let manager = driveManager {
// 停止导航
manager.stopNavi()
// 禁用后台定位
manager.allowsBackgroundLocationUpdates = false
// 清理代理
manager.delegate = nil
// 如果视图存在,移除数据代表
if let view = driveView {
manager.removeDataRepresentative(view)
view.delegate = nil
view.removeFromSuperview()
}
}
// 销毁单例实例(关键步骤)
AMapNaviDriveManager.destroyInstance()
// 清空引用
driveManager = nil
driveView = nil
print("导航资源清理完成")
}
private func setupAMapComponents() {
self.addNSNotification();
// 1. 初始化 DriveView(必须在主线程)
// print("导航------------------ setupAMapComponents_1")
DispatchQueue.main.async {
// print("导航------------------ setupAMapComponents_2")
self.driveView = AMapNaviDriveView(frame: self.view.bounds)
// print("导航------------------ setupAMapComponents_3")
self.driveView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// print("导航------------------ setupAMapComponents_4")
self.driveView.delegate = self
// print("导航------------------ setupAMapComponents_5")
self.view.addSubview(self.driveView)
// print("导航------------------ setupAMapComponents_6")
// 2. 初始化 DriveManager
self.driveManager = AMapNaviDriveManager.sharedInstance()
// print("导航------------------ setupAMapComponents_7")
self.driveManager.delegate = self
// print("导航------------------ setupAMapComponents_8")
self.driveManager.allowsBackgroundLocationUpdates = true
// print("导航------------------ setupAMapComponents_9")
// 3. 确保对象非空再关联
if let manager = self.driveManager, let view = self.driveView {
// print("导航------------------ setupAMapComponents_10")
manager.addDataRepresentative(view)
// print("导航------------------ setupAMapComponents_11")
self.startNavigation()
// print("导航------------------ setupAMapComponents_12")
} else {
print("Error: driveManager or driveView is nil")
}
// print("导航------------------ setupAMapComponents_13")
}
}
private func startNavigation() {
// print("导航------------------ startNavigation_1")
// let startPoint = AMapNaviPoint.location(withLatitude: 39.989614, longitude: 116.481763)!
// print("导航------------------ startNavigation_2")
// let endPoint = AMapNaviPoint.location(withLatitude: 39.983456, longitude: 116.315495)!
// print("导航------------------ startNavigation_3")
driveManager.calculateDriveRoute(
withStart: [startPoint],
end: [endPoint],
wayPoints: nil,
drivingStrategy: .drivingStrategySingleDefault
)
print("导航------------------ startNavigation_4")
}
@objc private func exitNavigation() {
print("导航------------------ 退出导航,清理资源")
// 停止导航
driveManager.stopNavi()
driveManager.removeDataRepresentative(driveView)
driveManager.delegate = nil
// 移除导航视图
driveView.delegate = nil
driveView.removeFromSuperview()
driveView = nil
// 销毁导航管理器
driveManager = nil
// 关闭当前页面 - 修复:使用正确的退出方式
if let navigationController = navigationController {
// 如果是在导航控制器中,使用 pop
navigationController.popViewController(animated: true)
} else {
// 如果是 present 出来的,使用 dismiss
dismiss(animated: true, completion: nil)
}
}
private func addNSNotification(){
NotificationCenter.default.addObserver(
forName: NSNotification.Name("ExitNavigation"),
object: nil,
queue: .main
) { _ in
self.exitNavigation()
}
}
}
// MARK: - 代理方法
extension AmapViewController: AMapNaviDriveViewDelegate, AMapNaviDriveManagerDelegate {
//View回调
func driveViewCloseButtonClicked(_ driveView: AMapNaviDriveView) {
print("导航界面关闭按钮被点击")
// 1. 立即停止所有导航相关服务
driveManager?.stopNavi()
driveManager?.allowsBackgroundLocationUpdates = false
// 2. 清理视图和代理关系
driveManager?.removeDataRepresentative(driveView)
driveManager?.delegate = nil
driveView.delegate = nil
// 3. 从视图层次结构中移除
driveView.removeFromSuperview()
// 4. 停止语音合成
speechSynthesizer.stopSpeaking(at: .immediate)
// 5. 销毁导航管理器实例
AMapNaviDriveManager.destroyInstance()
// 6. 清空引用
driveManager = nil
// 7. 立即退出,不使用延迟
if let navigationController = navigationController {
navigationController.popViewController(animated: true)
} else {
dismiss(animated: true, completion: nil)
}
}
func driveView(_ driveView: AMapNaviDriveView, didChange showMode: AMapNaviDriveViewShowMode) {
print("导航界面显示模式改变:\(showMode.rawValue)")
}
func driveView(_ driveView: AMapNaviDriveView, didChange trackMode: AMapNaviViewTrackingMode) {
print("导航界面跟随模式改变:\(trackMode.rawValue)")
}
func driveView(_ driveView: AMapNaviDriveView, didChangeOrientation isLandscape: Bool) {
print("导航界面横竖屏切换:isLandscape = \(isLandscape)")
}
func driveView(_ driveView: AMapNaviDriveView, didChangeDayNightType showStandardNightType: Bool) {
print("导航界面白天/黑夜模式切换:isNight = \(showStandardNightType)")
}
func driveViewEdgePadding(_ driveView: AMapNaviDriveView) -> UIEdgeInsets {
// 你可以根据自己 UI 布局返回合适的内边距,防止遮挡
let padding = UIEdgeInsets(top: 100, left: 50, bottom: 80, right: 60)
print("请求导航界面可视区域边距:\(padding)")
return padding
}
//导航回调
func driveManager(_ driveManager: AMapNaviDriveManager, error: Error) {
print("导航------------------ ❌ 发生错误: \(error.localizedDescription)")
}
func driveManager(onCalculateRouteSuccess driveManager: AMapNaviDriveManager){
print("导航------------------ ✅ 路线规划成功(旧方法)")
driveManager.startGPSNavi()
}
func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteSuccessWith type: AMapNaviRoutePlanType) {
print("导航------------------ 路径规划成功,类型: \(type.rawValue)")
driveManager.startGPSNavi()
}
func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error) {
print("导航------------------ ❌ 路线规划失败: \(error.localizedDescription)")
}
func driveManager(_ driveManager: AMapNaviDriveManager, onCalculateRouteFailure error: Error, routePlanType type: AMapNaviRoutePlanType) {
print("导航------------------ ❌ 路线规划失败(新方法): \(error.localizedDescription),类型: \(type.rawValue)")
}
func driveManager(_ driveManager: AMapNaviDriveManager, didStartNavi naviMode: AMapNaviMode) {
print("导航------------------ 🚗 已开始导航,模式: \(naviMode.rawValue)")
}
func driveManagerNeedRecalculateRoute(forYaw driveManager: AMapNaviDriveManager) {
print("导航------------------ 出现偏航,需要重新计算路径")
}
func driveManagerNeedRecalculateRoute(forTrafficJam driveManager: AMapNaviDriveManager) {
print("导航------------------ 遇到拥堵,重新规划路线")
}
func driveManager(_ driveManager: AMapNaviDriveManager, onArrivedWayPoint wayPointIndex: Int) {
print("导航------------------ 到达途经点索引:\(wayPointIndex)")
}
func driveManagerIsNaviSoundPlaying(_ driveManager: AMapNaviDriveManager) -> Bool {
print("导航------------------ 🔊 正在判断是否在播报语音")
return false // 如果你有 TTS 系统播报时需返回 true
}
func driveManager(_ driveManager: AMapNaviDriveManager, playNaviSound soundString: String, soundStringType: AMapNaviSoundType) {
print("导航------------------ 📢 导航播报: \(soundString),类型: \(soundStringType.rawValue)")
// 示例:使用 AVSpeechSynthesizer 播放语音
let utterance = AVSpeechUtterance(string: soundString)
utterance.voice = AVSpeechSynthesisVoice(language: "zh-CN")
speechSynthesizer.speak(utterance)
}
func driveManagerDidEndEmulatorNavi(_ driveManager: AMapNaviDriveManager) {
print("导航------------------ 🛑 模拟导航结束")
}
func driveManager(onArrivedDestination driveManager: AMapNaviDriveManager) {
print("导航------------------ 🎯 到达目的地")
}
func driveManager(_ driveManager: AMapNaviDriveManager, onNaviPlay ringType: AMapNaviRingType) {
print("导航------------------ 🔔 播放提示音,类型: \(ringType.rawValue)")
}
func driveManager(_ driveManager: AMapNaviDriveManager, update gpsSignalStrength: AMapNaviGPSSignalStrength) {
print("导航------------------ 📡 GPS信号强度: \(gpsSignalStrength.rawValue)")
}
func driveManager(_ driveManager: AMapNaviDriveManager, postRouteNotification notifyData: AMapNaviRouteNotifyData) {
print("导航------------------ 📌 路线通知信息: \(notifyData)")
}
func driveManager(_ driveManager: AMapNaviDriveManager, onSuggestChangeMainNaviRoute suggestChangeMainNaviRouteInfo: AMapNaviSuggestChangeMainNaviRouteInfo) {
print("导航------------------ 🔄 建议切换主导航路线: \(suggestChangeMainNaviRouteInfo)")
}
}