Usa esta guía para permitir que tu app escuche y responda a una variedad de eventos que cambian a medida que un usuario navega por una ruta. En esta guía, no se explica cómo definir una ruta, solo cómo responder a eventos a lo largo de una ruta.
Descripción general
El SDK de Navigation para iOS te proporciona objetos de escucha
asociados con la ubicación del usuario y las condiciones a lo largo de la ruta, así como
datos importantes de tiempo y distancia. En el controlador de vista del mapa, tu app debe adoptar los protocolos de estos objetos de escucha: GMSRoadSnappedLocationProviderListener
y GMSNavigatorListener
.
En esta lista, se muestran los métodos de objeto de escucha disponibles para los eventos de navegación:
GMSNavigatorListener.didArriveAtWaypoint
, que se activa cuando se llega a un destino.GMSNavigatorListener.navigatorDidChangeRoute
, que se activa cuando cambia la ruta.GMSNavigatorListener.didUpdateRemainingTime
, al que se llama de forma reiterada a medida que cambia el tiempo hasta el siguiente destino, mientras la guía está activa.GMSNavigatorListener.didUpdateRemainingDistance
, que se llama de forma reiterada a medida que cambia la distancia al siguiente destino mientras la guía está activa.GMSNavigatorListener.didUpdateDelayCategory
, que se llama cuando cambia la categoría de demora al siguiente destino mientras la guía está activa.GMSNavigatorListener.didChangeSuggestedLightingMode
, que se activa cuando se actualizan las condiciones de iluminación estimadas. Por ejemplo, cuando cae la noche en la ubicación actual del usuario, cambia la iluminación.GMSNavigatorListener.didUpdateSpeedingPercentage
, que se activa cuando el conductor supera el límite de velocidad.GMSRoadSnappedLocationProviderListener.didUpdateLocation
, que se llama de forma reiterada a medida que cambia la ubicación del usuario.
Consulta el código
Mostrar/ocultar el código Swift de un objeto de escucha de eventos
/* * Copyright 2020 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import GoogleNavigation import UIKit class ViewController: UIViewController, GMSNavigatorListener, GMSRoadSnappedLocationProviderListener { var mapView: GMSMapView! var locationManager: CLLocationManager! override func loadView() { locationManager = CLLocationManager() let camera = GMSCameraPosition.camera(withLatitude: 47.67, longitude: -122.20, zoom: 14) mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera) // Add listeners for GMSNavigator and GMSRoadSnappedLocationProvider. mapView.navigator?.add(self) mapView.roadSnappedLocationProvider?.add(self) // Set the time update threshold (seconds) and distance update threshold (meters). mapView.navigator?.timeUpdateThreshold = 10 mapView.navigator?.distanceUpdateThreshold = 100 // Show the terms and conditions. let companyName = "Ride Sharing Co." GMSNavigationServices.showTermsAndConditionsDialogIfNeeded( withCompanyName: companyName ) { termsAccepted in if termsAccepted { // Enable navigation if the user accepts the terms. self.mapView.isNavigationEnabled = true // Request authorization to use location services. self.locationManager.requestAlwaysAuthorization() // Request authorization for alert notifications which deliver guidance instructions // in the background. UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) { granted, error in // Handle denied authorization to display notifications. if !granted || error != nil { print("Authorization to deliver notifications was rejected.") } } } else { // Handle the case when the user rejects the terms and conditions. } } view = mapView makeButton() } // Create a route and start guidance. @objc func startNav() { var destinations = [GMSNavigationWaypoint]() destinations.append( GMSNavigationWaypoint.init( placeID: "ChIJnUYTpNASkFQR_gSty5kyoUk", title: "PCC Natural Market")!) destinations.append( GMSNavigationWaypoint.init( placeID: "ChIJJ326ROcSkFQRBfUzOL2DSbo", title: "Marina Park")!) mapView.navigator?.setDestinations(destinations) { routeStatus in guard routeStatus == .OK else { print("Handle route statuses that are not OK.") return } self.mapView.navigator?.isGuidanceActive = true self.mapView.cameraMode = .following self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute() } mapView.roadSnappedLocationProvider?.startUpdatingLocation() } // Listener to handle continuous location updates. func locationProvider( _ locationProvider: GMSRoadSnappedLocationProvider, didUpdate location: CLLocation ) { print("Location: \(location.description)") } // Listener to handle speeding events. func navigator( _ navigator: GMSNavigator, didUpdateSpeedingPercentage percentageAboveLimit: CGFloat ) { print("Speed is \(percentageAboveLimit) above the limit.") } // Listener to handle arrival events. func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) { print("You have arrived at: \(waypoint.title)") mapView.navigator?.continueToNextDestination() mapView.navigator?.isGuidanceActive = true } // Listener for route change events. func navigatorDidChangeRoute(_ navigator: GMSNavigator) { print("The route has changed.") } // Listener for time to next destination. func navigator(_ navigator: GMSNavigator, didUpdateRemainingTime time: TimeInterval) { print("Time to next destination: \(time)") } // Delegate for distance to next destination. func navigator( _ navigator: GMSNavigator, didUpdateRemainingDistance distance: CLLocationDistance ) { let miles = distance * 0.00062137 print("Distance to next destination: \(miles) miles.") } // Delegate for traffic updates to next destination func navigator( _ navigator: GMSNavigator, didUpdate delayCategory: GMSNavigationDelayCategory ) { print("Delay category to next destination: \(String(describing: delayCategory)).") } // Delegate for suggested lighting mode changes. func navigator( _ navigator: GMSNavigator, didChangeSuggestedLightingMode lightingMode: GMSNavigationLightingMode ) { print("Suggested lighting mode has changed: \(String(describing: lightingMode))") // Change to the suggested lighting mode. mapView.lightingMode = lightingMode } // Add a button to the view. func makeButton() { // Start navigation. let navButton = UIButton(frame: CGRect(x: 5, y: 150, width: 200, height: 35)) navButton.backgroundColor = .blue navButton.alpha = 0.5 navButton.setTitle("Start navigation", for: .normal) navButton.addTarget(self, action: #selector(startNav), for: .touchUpInside) self.mapView.addSubview(navButton) } }
Muestra o oculta el código Objective-C de un objeto de escucha de eventos.
/* * Copyright 2020 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "ViewController.h" @import GoogleNavigation; @interface ViewController () <GMSNavigatorListener, GMSRoadSnappedLocationProviderListener> @end @implementation ViewController { GMSMapView *_mapView; CLLocationManager *_locationManager; } - (void)loadView { _locationManager = [[CLLocationManager alloc] init]; GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:47.67 longitude:-122.20 zoom:14]; _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; // Add listeners for GMSNavigator and GMSRoadSnappedLocationProvider. [_mapView.navigator addListener:self]; [_mapView.roadSnappedLocationProvider addListener:self]; // Set the time update threshold (seconds) and distance update threshold (meters). _mapView.navigator.timeUpdateThreshold = 10; _mapView.navigator.distanceUpdateThreshold = 100; // Show the terms and conditions. NSString *companyName = @"Ride Sharing Co."; [GMSNavigationServices showTermsAndConditionsDialogIfNeededWithCompanyName:companyName callback:^(BOOL termsAccepted) { if (termsAccepted) { // Enable navigation if the user accepts the terms. _mapView.navigationEnabled = YES; // Request authorization to use location services. [_locationManager requestAlwaysAuthorization]; } else { // Handle the case when the user rejects the terms and conditions. } }]; self.view = _mapView; [self makeButton]; } // Create a route and initiate navigation. - (void)startNav { NSArray<GMSNavigationWaypoint *> *destinations = @[[[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJnUYTpNASkFQR_gSty5kyoUk" title:@"PCC Natural Market"], [[GMSNavigationWaypoint alloc] initWithPlaceID:@"ChIJJ326ROcSkFQRBfUzOL2DSbo" title:@"Marina Park"]]; [_mapView.navigator setDestinations:destinations callback:^(GMSRouteStatus routeStatus){ _mapView.navigator.guidanceActive = YES; _mapView.navigator.sendsBackgroundNotifications = YES; _mapView.cameraMode = GMSNavigationCameraModeFollowing; [_mapView.locationSimulator simulateLocationsAlongExistingRoute]; }]; [_mapView.roadSnappedLocationProvider startUpdatingLocation]; } #pragma mark - GMSNavigatorListener // Listener for continuous location updates. - (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider didUpdateLocation:(CLLocation *)location { NSLog(@"Location: %@", location.description); } // Listener to handle speeding events. - (void)navigator:(GMSNavigator *)navigator didUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit { NSLog(@"Speed is %f percent above the limit.", percentageAboveLimit); } // Listener to handle arrival events. - (void)navigator:(GMSNavigator *)navigator didArriveAtWaypoint:(GMSNavigationWaypoint *)waypoint { NSLog(@"You have arrived at: %@", waypoint.title); [_mapView.navigator continueToNextDestination]; _mapView.navigator.guidanceActive = YES; } // Listener for route change events. - (void)navigatorDidChangeRoute:(GMSNavigator *)navigator { NSLog(@"The route has changed."); } // Listener for time to next destination. - (void)navigator:(GMSNavigator *)navigator didUpdateRemainingTime:(NSTimeInterval)time { NSLog(@"Time to next destination: %f", time); } // Listener for distance to next destination. - (void)navigator:(GMSNavigator *)navigator didUpdateRemainingDistance:(CLLocationDistance)distance { double miles = distance * 0.00062137; NSLog(@"%@", [NSString stringWithFormat:@"Distance to next destination: %.2f.", miles]); } // Listener for traffic updates for next destination - (void)navigator:(GMSNavigator *)navigator didUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory { NSLog(@"Delay category to next destination: %ld.", delayCategory); } // Listener for suggested lighting mode changes. -(void)navigator:(GMSNavigator *)navigator didChangeSuggestedLightingMode:(GMSNavigationLightingMode)lightingMode { NSLog(@"Suggested lighting mode has changed: %ld", (long)lightingMode); // Change to the suggested lighting mode. _mapView.lightingMode = lightingMode; } #pragma mark - Programmatic UI elements // Add a button to the view. - (void)makeButton { // Start navigation. UIButton *navButton = [UIButton buttonWithType:UIButtonTypeCustom]; [navButton addTarget:self action:@selector(startNav) forControlEvents:UIControlEventTouchUpInside]; [navButton setTitle:@"Navigate" forState:UIControlStateNormal]; [navButton setBackgroundColor:[UIColor blueColor]]; [navButton setAlpha:0.5]; navButton.frame = CGRectMake(5.0, 150.0, 100.0, 35.0); [_mapView addSubview:navButton]; } @end
Declaración de cumplimiento de los protocolos requeridos
Antes de implementar los métodos de navegación, el controlador de vistas debe adoptar los siguientes protocolos:
class ViewController: UIViewController, GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener {
@interface ViewController () <GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener>
@end
Después de adoptar los protocolos de navegación, configura los objetos de escucha en el controlador de vista. Por ejemplo, puedes agregar el siguiente código al método viewDidLoad()
.
mapView.navigator?.add(self) mapView.roadSnappedLocationProvider?.add(self)
[_mapView.navigator addListener:self]; [_mapView.roadSnappedLocationProvider
addListener:self];
Cómo recibir o detener actualizaciones de ubicación
Las actualizaciones de ubicación son necesarias para mostrar el progreso del usuario en el mapa.
La instancia de location
expone las siguientes propiedades:
Propiedad de ubicación | Descripción |
---|---|
Altitud | La altitud actual. |
coordinate.latitude | La coordenada de latitud actual ajustada a la ruta. |
coordinate.longitude | Es la coordenada de longitud actual ajustada a la ruta. |
curso | Es la orientación actual en grados. |
speed | Velocidad actual. |
timestamp | Es la fecha y hora de la lectura actual. |
Para recibir actualizaciones de ubicación continuas, llama a mapView.roadSnappedLocationProvider.startUpdatingLocation
y usa GMSRoadSnappedLocationProviderListener
para controlar el evento didUpdateLocation
.
En el siguiente ejemplo, se muestra cómo llamar a startUpdatingLocation
:
mapView.roadSnappedLocationProvider.startUpdatingLocation()
[_mapView.roadSnappedLocationProvider startUpdatingLocation];
El siguiente código crea un GMSRoadSnappedLocationProviderListener
que controla el evento didUpdateLocation
.
func locationProvider(_ locationProvider: GMSRoadSnappedLocationProvider,
didUpdate location: CLLocation) { print("Location: \(location.description)") }
- (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider
didUpdateLocation:(CLLocation *)location { NSLog(@"Location: %@",
location.description); }
Para recibir actualizaciones de ubicación cuando la app está en segundo plano, establece allowsBackgroundLocationUpdates
como verdadero:
mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = true
_mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = YES;
Cómo detectar eventos de llegada
Tu app usa el evento didArriveAtWaypoint
para detectar cuándo se llega a un destino. Para reanudar la guía y avanzar al siguiente punto de referencia, llama a continueToNextDestination()
y, luego, vuelve a habilitar la guía. Tu app debe volver a habilitar la guía después de llamar a continueToNextDestination()
.
Después de que la app llama a continueToNextDestination
, el navegador ya no tiene datos sobre el destino anterior. Si quieres analizar información sobre un tramo de ruta, debes recuperarla del navegador antes de llamar a continueToNextDestination()
.
En el siguiente ejemplo de código, se muestra un método para controlar el evento didArriveAtWaypoint
:
func navigator(_ navigator: GMSNavigator, didArriveAt waypoint:
GMSNavigationWaypoint) { print("You have arrived at: \(waypoint.title)")
mapView.navigator?.continueToNextDestination()
mapView.navigator?.isGuidanceActive = true }
- (void)navigator:(GMSNavigator *)navigator
didArriveAtWaypoint:(GMSNavigationWaypoint *)waypoint { NSLog(@"You have
arrived at: %@", waypoint.title); [_mapView.navigator
continueToNextDestination]; _mapView.navigator.guidanceActive = YES; }
Cómo recibir actualizaciones de cambios de ruta
Para recibir una notificación cada vez que se cambie la ruta, crea un método para controlar el evento navigatorDidChangeRoute
. Puedes acceder a la ruta nueva con las propiedades routeLegs
y currentRouteLeg
de GMSNavigator
.
func navigatorDidChangeRoute(_ navigator: GMSNavigator) { print("The route has
changed.") }
- (void)navigatorDidChangeRoute:(GMSNavigator *)navigator { NSLog(@"The route
has changed."); }
Cómo recibir actualizaciones del tiempo hasta el destino
Para recibir actualizaciones continuas del tiempo hasta el destino, crea un método para controlar el evento didUpdateRemainingTime
. El parámetro time
proporciona el tiempo estimado, en segundos, hasta que se alcanza el siguiente destino.
func navigator(_ navigator: GMSNavigator, didUpdateRemainingTime time:
TimeInterval) { print("Time to next destination: \(time)") }
- (void)navigator:(GMSNavigator *)navigator
didUpdateRemainingTime:(NSTimeInterval)time { NSLog(@"Time to next
destination: %f", time); }
Para establecer el cambio mínimo en el tiempo estimado hasta el siguiente destino, configura la propiedad timeUpdateThreshold
en GMSNavigator
. El valor se especifica en segundos. Si no se establece esta propiedad, los servicios usan un valor predeterminado de un segundo.
navigator?.timeUpdateThreshold = 10
navigator.timeUpdateThreshold = 10;
Cómo recibir actualizaciones de la distancia al destino
Para recibir actualizaciones continuas de la distancia al destino, crea un método para controlar el evento didUpdateRemainingDistance
. El parámetro distance
proporciona la distancia estimada, en metros, al siguiente destino.
func navigator(_ navigator: GMSNavigator, didUpdateRemainingDistance distance:
CLLocationDistance) { let miles = distance * 0.00062137 print("Distance to next
destination: \(miles) miles.") }
- (void)navigator:(GMSNavigator *)navigator
didUpdateRemainingDistance:(CLLocationDistance)distance { double miles =
distance * 0.00062137; NSLog(@"%@", [NSString stringWithFormat:@"Distance to
next destination: %.2f.", miles]); }
Para establecer el cambio mínimo en la distancia estimada al siguiente destino, establece la propiedad distanceUpdateThreshold
en GMSNavigator
(el valor se especifica en metros). Si no se establece esta propiedad, los servicios usan un valor predeterminado de un medidor.
navigator?.distanceUpdateThreshold = 100
navigator.distanceUpdateThreshold = 100;
Cómo recibir actualizaciones de tráfico
Para recibir actualizaciones continuas del flujo de tráfico de la ruta restante, crea un método para controlar el evento didUpdateDelayCategory
. Una llamada a delayCategoryToNextDestination
muestra GMSNavigationDelayCategory
, que proporciona un valor de 0 a 3. Las actualizaciones de la categoría se basan en la posición actual del usuario de la app. Si los datos de tráfico no están disponibles, GMSNavigationDelayCategory
muestra 0. Los números del 1 al 3 indican un flujo creciente de ligero a intenso.
func navigator(_ navigator: GMSNavigator, didUpdate delayCategory:
GMSNavigationDelayCategory) { print("Traffic flow to next destination:
\(delayCategory)") }
- (void)navigator:(GMSNavigator *)navigator
didUpdateDelayCategory:(GMSNavigationDelayCategory)delayCategory {
NSLog(@"Traffic flow to next destination: %ld", (long)delayCategory); }
La propiedad GMSNavigationDelayCategory
expone los siguientes niveles de demora:
Categoría de retraso | Descripción |
---|---|
GMSNavigationDelayCategoryNoData | 0: No disponible, no hay datos de tráfico o lo siguiente: |
la ruta. | |
GMSNavigationDelayCategoryHeavy | 1: Pesado |
GMSNavigationDelayCategoryMedium | 2 - Medio |
GMSNavigationDelayCategoryLight | 3: Luz. |
Cómo recibir actualizaciones de velocidad
Para recibir actualizaciones cuando un conductor supera el límite de velocidad, crea un método para controlar el evento didUpdateSpeedingPercentage
.
// Listener to handle speeding events. func navigator( _ navigator:
GMSNavigator, didUpdateSpeedingPercentage percentageAboveLimit: CGFloat ) {
print("Speed is \(percentageAboveLimit) above the limit.") }
// Listener to handle speeding events. - (void)navigator:(GMSNavigator
*)navigator didUpdateSpeedingPercentage:(CGFloat)percentageAboveLimit {
NSLog(@"Speed is %f percent above the limit.", percentageAboveLimit); }
Cómo cambiar el modo de iluminación sugerido
Para recibir actualizaciones de los cambios estimados en la iluminación, crea un método para controlar el evento didChangeSuggestedLightingMode
.
// Define a listener for suggested changes to lighting mode. func navigator(_
navigator: GMSNavigator, didChangeSuggestedLightingMode lightingMode:
GMSNavigationLightingMode) { print("Suggested lighting mode has changed:
\(String(describing: lightingMode))")
// Make the suggested change. mapView.lightingMode = lightingMode }
// Define a listener for suggested changes to lighting mode.
-(void)navigator:(GMSNavigator *)navigator didChangeSuggestedLightingMode:
(GMSNavigationLightingMode)lightingMode { NSLog(@"Suggested lighting mode has
changed: %ld", (long)lightingMode);
// Make the suggested change. _mapView.lightingMode = lightingMode; }