iOS端Mapbox导航语音重复问题排查求助
Mapbox iOS逐向导航语音重复叠加问题
在iOS端使用Mapbox逐向导航时,需在导航激活状态下添加途经点。通过addSpots方法为地图添加点图层后,点显示正常,但出现以下问题:
- 关闭导航后重新打开,语音播报会重复叠加,关闭再打开的次数越多,语音重复层数越多
- 移除
addSpots方法后,语音重复问题消失
已做排查与尝试
- 推测控制器关闭时导航未正确终止,新会话与旧会话发生重叠
- 尝试在导航控制器dismiss时调用
navigationServices.stop(),但无效果
相关代码
import Foundation import UIKit import XamoomSDK import MBProgressHUD import FirebaseAuth import NotificationCenter import MapboxDirections import MapboxCoreNavigation import MapboxNavigation import MapboxMaps import CoreLocation import MBProgressHUD class BasicViewController: UIViewController { var wayPoint: [Waypoint] = [] var spots: [XMMSpot] = [] var customImageMarker: UIImage? var layer: [String] = [] convenience init(waypoints: [Waypoint], spots: [XMMSpot], customImageMarker: UIImage, layer: [String]) { self.init(nibName: nil, bundle: nil) self.wayPoint = waypoints self.spots = spots self.customImageMarker = customImageMarker self.layer = layer } override func viewDidLoad() { super.viewDidLoad() requestRoute() } func requestRoute() { let navigationRoutOptions = NavigationRouteOptions(waypoints: wayPoint) Directions.shared.calculate(navigationRoutOptions) { [weak self] (_, result) in switch result { case .failure(let error): print(error.localizedDescription) case .success(let response): guard let strongSelf = self else { return } let navigationService = MapboxNavigationService(routeResponse: response, routeIndex: 0, routeOptions: navigationRoutOptions, credentials: NavigationSettings.shared.directions.credentials, simulating: .none) let navigationOptions = NavigationOptions(navigationService: navigationService) let navigationViewController = NavigationViewController(for: response, routeIndex: 0, routeOptions: navigationRoutOptions, navigationOptions: navigationOptions) navigationViewController.delegate = strongSelf self?.addSpots(navViewController: (navigationViewController)) navigationViewController.modalPresentationStyle = .fullScreen navigationViewController.routeLineTracksTraversal = true strongSelf.present(navigationViewController, animated: true, completion: nil) } } } func addSpots(navViewController: NavigationViewController) { navViewController.navigationMapView?.mapView.mapboxMap.onEvery(event: .styleLoaded) { _ in for spot in self.spots { let style = navViewController.navigationMapView?.mapView.mapboxMap.style try? style?.addImage((self.customImageMarker!), id: "markerimage", stretchX: [], stretchY: []) let someCoordinate = CLLocationCoordinate2DMake(spot.latitude, spot.longitude) let point = Point(someCoordinate) var feature = Feature(geometry: Geometry.point(point)) feature.identifier = .string(spot.name) var source = GeoJSONSource() source.data = .feature(feature) try? navViewController.navigationMapView?.mapView.mapboxMap.style.addSource(source, id: spot.name) self.layer.append(spot.name) var layer = SymbolLayer(id: spot.name) layer.source = spot.name layer.iconImage = .constant(.name("markerimage")) layer.iconAnchor = .constant(.bottom) layer.textField = .constant(spot.name) layer.iconAllowOverlap = .constant(true) try? navViewController.navigationMapView?.mapView.mapboxMap.style.addLayer(layer) } } } } extension BasicViewController: NavigationViewControllerDelegate { func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { dismiss(animated: true, completion: nil) } }
下一步排查方案
清理重复的事件监听
addSpots中使用onEvery(event: .styleLoaded)会重复注册事件监听,即使旧导航关闭,监听仍可能绑定在地图实例上。需保存监听token并在导航关闭时移除:// 新增属性保存监听token var styleLoadedToken: Cancelable? func addSpots(navViewController: NavigationViewController) { styleLoadedToken = navViewController.navigationMapView?.mapView.mapboxMap.onEvery(event: .styleLoaded) { [weak self] _ in // 原有图层添加逻辑 } } // 在导航关闭时移除监听 func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { styleLoadedToken?.cancel() dismiss(animated: true, completion: nil) }导航关闭时彻底清理图层资源
每次导航关闭时,移除之前添加的所有source、layer和图片资源,避免旧资源残留:func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { guard let style = navigationViewController.navigationMapView?.mapView.mapboxMap.style else { dismiss(animated: true, completion: nil) return } // 移除所有自定义图层和数据源 for layerId in self.layer { style.removeLayer(withId: layerId) style.removeSource(withId: layerId) } self.layer.removeAll() // 移除自定义图片 style.removeImage(withId: "markerimage") // 停止并销毁导航服务 navigationViewController.navigationService.shutdown() dismiss(animated: true, completion: nil) }修正导航服务的生命周期管理
将navigationService声明为类属性,确保在关闭时能准确终止并释放:class BasicViewController: UIViewController { var navigationService: MapboxNavigationService? // ...其他属性 func requestRoute() { // ...原有逻辑 self.navigationService = MapboxNavigationService(routeResponse: response, routeIndex: 0, routeOptions: navigationRoutOptions, credentials: NavigationSettings.shared.directions.credentials, simulating: .none) let navigationOptions = NavigationOptions(navigationService: self.navigationService!) // ...后续逻辑 } func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) { navigationService?.shutdown() navigationService = nil dismiss(animated: true, completion: nil) } }避免重复添加图片资源
addSpots中每次循环都调用addImage会重复添加同名图片,改为仅添加一次:func addSpots(navViewController: NavigationViewController) { navViewController.navigationMapView?.mapView.mapboxMap.onEvery(event: .styleLoaded) { [weak self] _ in guard let self = self, let style = navViewController.navigationMapView?.mapView.mapboxMap.style else { return } // 检查图片是否已存在,不存在再添加 if style.image(withId: "markerimage") == nil { try? style.addImage(self.customImageMarker!, id: "markerimage", stretchX: [], stretchY: []) } // 原有添加source和layer的逻辑 } }
内容的提问来源于stack exchange,提问作者Ivan Magda
相关产品推荐
相关产品推荐

