Navigationsereignisse im Blick behalten

In diesem Leitfaden erfahren Sie, wie Sie Ihre App so konfigurieren, dass sie auf eine Vielzahl von Ereignissen reagiert, die sich ändern, während sich ein Nutzer auf einer Route bewegt. In diesem Leitfaden wird nicht beschrieben, wie eine Route definiert wird, sondern nur, wie auf Ereignisse entlang einer Route reagiert wird.

Übersicht

Das Navigation SDK for iOS bietet Ihnen Listener, die mit dem Standort des Nutzers und den Bedingungen entlang der Route sowie wichtigen Zeit- und Entfernungsdaten verknüpft sind. Im View Controller der Karte muss Ihre App die Protokolle für diese Listener übernehmen: GMSRoadSnappedLocationProviderListener und GMSNavigatorListener.

In dieser Liste sind die Listenermethoden aufgeführt, die für Navigationsereignisse verfügbar sind:

Code

/*
 * 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)
  }

}
/*
 * 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

Konformität mit den erforderlichen Protokollen erklären

Bevor die Navigationsmethoden implementiert werden, muss der View Controller die folgenden Protokolle übernehmen:

class ViewController: UIViewController, GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener {

@interface ViewController () <GMSNavigatorListener,
GMSRoadSnappedLocationProviderListener>

@end

Nachdem Sie die Navigationsprotokolle übernommen haben, legen Sie die Listener auf den Ansichtscontroller fest. Sie können der Methode viewDidLoad() beispielsweise den folgenden Code hinzufügen.

mapView.navigator?.add(self) mapView.roadSnappedLocationProvider?.add(self)

[_mapView.navigator addListener:self]; [_mapView.roadSnappedLocationProvider
addListener:self];

Standortaktualisierungen erhalten oder beenden

Standortaktualisierungen sind erforderlich, um den Fortschritt des Nutzers auf der Karte anzuzeigen.

Die location-Instanz stellt die folgenden Eigenschaften bereit:

Standort-Property Beschreibung
Höhe Aktuelle Höhe.
coordinate.latitude Aktuelle Breitengradkoordinate, die an Straßen ausgerichtet ist.
coordinate.longitude Aktuelle Längengradkoordinate, die an einer Straße angehängt ist.
Kurs Aktueller Kurs in Grad.
speed Aktuelle Geschwindigkeit.
timestamp Datum und Uhrzeit der aktuellen Messung.

Wenn Sie kontinuierliche Standortaktualisierungen erhalten möchten, rufen Sie mapView.roadSnappedLocationProvider.startUpdatingLocation auf und verwenden Sie GMSRoadSnappedLocationProviderListener , um das Ereignis didUpdateLocation zu verarbeiten.

Hier sehen Sie, wie startUpdatingLocation aufgerufen wird:

mapView.roadSnappedLocationProvider.startUpdatingLocation()

[_mapView.roadSnappedLocationProvider startUpdatingLocation];

Im folgenden Code wird eine GMSRoadSnappedLocationProviderListener erstellt, die das didUpdateLocation-Ereignis verarbeitet.

func locationProvider(_ locationProvider: GMSRoadSnappedLocationProvider,
didUpdate location: CLLocation) { print("Location: \(location.description)") }

-   (void)locationProvider:(GMSRoadSnappedLocationProvider *)locationProvider
    didUpdateLocation:(CLLocation *)location { NSLog(@"Location: %@",
    location.description); }

Wenn Sie Standortaktualisierungen erhalten möchten, während die App im Hintergrund ausgeführt wird, setzen Sie allowsBackgroundLocationUpdates auf „true“:

mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = true

 _mapView.roadSnappedLocationProvider.allowsBackgroundLocationUpdates = YES;

Ankunftsereignisse erkennen

Ihre App verwendet das Ereignis didArriveAtWaypoint, um zu erkennen, wenn ein Ziel erreicht wurde. Sie können die Navigation fortsetzen und zum nächsten Wegpunkt wechseln, indem Sie continueToNextDestination() drücken und dann die Navigation wieder aktivieren. Ihre App muss die Navigation nach dem Aufruf von continueToNextDestination() wieder aktivieren.

Nachdem die App continueToNextDestination aufgerufen hat, hat der Navigationsgerät keine Daten mehr zum vorherigen Ziel. Wenn Sie Informationen zu einem Streckenabschnitt analysieren möchten, müssen Sie diese vom Navigationssystem abrufen, bevor Sie continueToNextDestination() aufrufen.

Das folgende Codebeispiel zeigt eine Methode zum Bearbeiten des didArriveAtWaypoint-Ereignisses:

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; }

Updates zu Routenänderungen erhalten

Wenn Sie jedes Mal eine Benachrichtigung erhalten möchten, wenn sich die Route ändert, erstellen Sie eine Methode zum Bearbeiten des Ereignisses navigatorDidChangeRoute. Sie können über die Attribute routeLegs und currentRouteLeg von GMSNavigator auf die neue Route zugreifen.

func navigatorDidChangeRoute(_ navigator: GMSNavigator) { print("The route has
changed.") }

-   (void)navigatorDidChangeRoute:(GMSNavigator *)navigator { NSLog(@"The route
    has changed."); }

Aktualisierungen zur voraussichtlichen Ankunftszeit erhalten

Wenn Sie kontinuierliche Updates zur Zeit bis zum Ziel erhalten möchten, erstellen Sie eine Methode zum Bearbeiten des Ereignisses didUpdateRemainingTime. Der Parameter time gibt die geschätzte Zeit in Sekunden bis zum Erreichen des nächsten Ziels an.

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

Wenn Sie die minimale Änderung der geschätzten Zeit bis zum nächsten Ziel festlegen möchten, legen Sie die Eigenschaft timeUpdateThreshold auf GMSNavigator fest. Der Wert wird in Sekunden angegeben. Wenn diese Property nicht festgelegt ist, verwenden die Dienste den Standardwert „1 Sekunde“.

navigator?.timeUpdateThreshold = 10

navigator.timeUpdateThreshold = 10;

Aktualisierungen der Entfernung zum Ziel erhalten

Wenn Sie kontinuierliche Aktualisierungen der Entfernung zum Ziel erhalten möchten, erstellen Sie eine Methode zum Bearbeiten des Ereignisses didUpdateRemainingDistance. Der Parameter distance gibt die geschätzte Entfernung in Metern zum nächsten Ziel an.

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]); }

Wenn Sie die minimale Änderung der geschätzten Entfernung zum nächsten Ziel festlegen möchten, legen Sie die Property distanceUpdateThreshold auf GMSNavigator fest. Der Wert wird in Metern angegeben. Wenn diese Eigenschaft nicht festgelegt ist, verwenden die Dienste den Standardwert „1 Meter“.

navigator?.distanceUpdateThreshold = 100

navigator.distanceUpdateThreshold = 100;

Verkehrsinformationen erhalten

Wenn Sie kontinuierliche Updates des Verkehrsflusses für die verbleibende Route erhalten möchten, erstellen Sie eine Methode zum Bearbeiten des didUpdateDelayCategory-Ereignisses. Ein Aufruf von delayCategoryToNextDestination gibt GMSNavigationDelayCategory zurück, der einen Wert von 0 bis 3 liefert. Aktualisierungen der Kategorie basieren auf der aktuellen Position des App-Nutzers. Wenn keine Zugriffsdaten verfügbar sind, wird für GMSNavigationDelayCategory der Wert 0 zurückgegeben. Die Zahlen 1–3 geben den zunehmenden Fluss von leicht nach stark an.

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

Die GMSNavigationDelayCategory-Eigenschaft gibt die folgenden Verzögerungsstufen an:

Verzögerungskategorie Beschreibung
GMSNavigationDelayCategoryNoData 0 – Nicht verfügbar, keine Daten für den Traffic oder :
der Route.
GMSNavigationDelayCategoryHeavy 1 – Schwer.
GMSNavigationDelayCategoryMedium 2 – Mittel.
GMSNavigationDelayCategoryLight 3 – Leuchtend

Geschwindigkeitswarnungen erhalten

Wenn Sie Updates erhalten möchten, wenn ein Fahrer das Tempolimit überschreitet, erstellen Sie eine Methode zum Verarbeiten des didUpdateSpeedingPercentage-Ereignisses.

// 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); }

Vorgeschlagenen Beleuchtungsmodus ändern

Wenn Sie Updates zu den geschätzten Änderungen der Beleuchtung erhalten möchten, erstellen Sie eine Methode zum Bearbeiten des Ereignisses 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; }