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
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)")
|
|
}
|
|
}
|
|
|