Auf einer Karte den aktuellen Ort auswählen und Details einblenden

In dieser Anleitung erfahren Sie, wie Sie eine iOS-App für folgende Zwecke erstellen:

  • Aktuellen Gerätestandort abrufen
  • Rufen Sie eine Liste von Orten ab, an denen sich das Gerät wahrscheinlich befindet.
  • Nutzer nach der besten Übereinstimmung für den Ort fragen
  • Markierung auf der Karte anzeigen

In dieser Anleitung erfahren Sie, wie Sie eine iOS-App mit dem Places SDK for iOS, dem Maps SDK for iOS und dem Apple Core Location Framework erstellen.

Code abrufen

Klonen Sie das Google Maps SDK for iOS oder laden Sie es von GitHub herunter.

Entwicklungsprojekt einrichten

So installieren Sie das Places SDK for iOS und das Maps SDK for iOS:

  1. Laden Sie Xcode Version 14.0 oder höher herunter und installieren Sie sie.
  2. Wenn Sie CocoaPods noch nicht haben, installieren Sie es unter macOS, indem Sie den folgenden Befehl über das Terminal ausführen:
    sudo gem install cocoapods
  3. Wechseln Sie in dem Verzeichnis, in dem Sie das Beispiel-Repository gespeichert haben (Code abrufen), zum Verzeichnis tutorials/current-place-on-map.
  4. Führe den Befehl pod install aus. Dadurch werden die in Podfile angegebenen APIs und ggf. zugehörige Abhängigkeiten installiert.
  5. Führen Sie pod outdated aus, um die installierte Pod-Version mit allen neuen Updates zu vergleichen. Wenn eine neue Version erkannt wird, führen Sie pod update aus, um Podfile zu aktualisieren und das neueste SDK zu installieren. Weitere Informationen findest du im CocoaPods-Leitfaden.
  6. Öffnen Sie current-place-on-map.xcworkspace des Projekts (doppelklicken), um es in Xcode zu öffnen. Sie müssen die Datei .xcworkspace verwenden, um das Projekt zu öffnen.

Eine ausführliche Installationsanleitung finden Sie unter Erste Schritte (Maps) und Erste Schritte (Places).

Erforderliche APIs aktivieren und API-Schlüssel abrufen

Als letzten Schritt benötigen Sie einen Google API-Schlüssel, der zur Verwendung des Maps SDK for iOS und der Places API berechtigt ist.

  1. Folgen Sie der Anleitung unter Erste Schritte mit der Google Maps Platform, um ein Rechnungskonto und ein Projekt für beide dieser Produkte einzurichten.
  2. Folgen Sie der Anleitung unter API-Schlüssel anfordern, um einen API-Schlüssel für das zuvor eingerichtete Entwicklungsprojekt zu erstellen.

API-Schlüssel zur Anwendung hinzufügen

Füge deinen API-Schlüssel folgendermaßen in AppDelegate.swift ein:

  1. Die folgende Importanweisung wurde der Datei hinzugefügt:
    import GooglePlaces
    import GoogleMaps
  2. Bearbeiten Sie die folgende Zeile in der Methode application(_:didFinishLaunchingWithOptions:) und ersetzen Sie YOUR_API_KEY durch Ihren API-Schlüssel:
    GMSPlacesClient.provideAPIKey("YOUR_API_KEY")
    GMSServices.provideAPIKey("YOUR_API_KEY")

App erstellen und ausführen

  1. Verbinden Sie ein iOS-Gerät mit Ihrem Computer oder wählen Sie im Pop-up-Menü für das Xcode-Schema einen Simulator aus.
  2. Wenn Sie ein Gerät verwenden, vergewissern Sie sich, dass die Ortungsdienste aktiviert sind. Wenn Sie einen Simulator verwenden, wählen Sie im Menü Features einen Standort aus.
  3. Klicken Sie in Xcode auf die Menüoption Product/Run (Produkt/Ausführen) oder auf das Wiedergabesymbol.
    • Xcode erstellt die App und führt sie dann auf dem Gerät oder im Simulator aus.
    • Nun sollte eine Karte mit einer Reihe von Markierungen zu sehen sein, die um Ihren aktuellen Standort herum angeordnet sind.

Fehlerbehebung:

  • Wenn Sie keine Karte sehen, prüfen Sie, ob Sie einen API-Schlüssel erhalten und ihn wie oben beschrieben in die App eingefügt haben. Suchen Sie in der Debugging-Konsole von Xcode nach Fehlermeldungen zum API-Schlüssel.
  • Wenn Sie den API-Schlüssel durch den iOS-Bundle-Identifikator eingeschränkt haben, bearbeiten Sie den Schlüssel und fügen Sie den Bundle Identifier für die App hinzu: com.google.examples.current-place-on-map.
  • Die Karte wird nicht richtig angezeigt, wenn die Berechtigungsanfrage für Standortdienste abgelehnt wird.
    • Wenn Sie ein Gerät verwenden, rufen Sie Einstellungen/Allgemein/Datenschutz/Standortdienste auf und aktivieren Sie die Standortdienste erneut.
    • Wenn Sie einen Simulator verwenden, gehen Sie zu Simulator/Reset Content and Settings... (Simulator/Inhalte und Einstellungen zurücksetzen...).
    Wenn Sie die App das nächste Mal ausführen, müssen Sie die Eingabeaufforderung für Standortdienste akzeptieren.
  • Sie benötigen eine gute WLAN- oder GPS-Verbindung.
  • Wird die App gestartet, aber keine Karte angezeigt, prüfen Sie, ob Sie die Info.plist-Datei für Ihr Projekt mit den entsprechenden Berechtigungen zur Standortermittlung aktualisiert haben. Weitere Informationen zum Umgang mit Berechtigungen finden Sie unten in der Anleitung Berechtigung zur Standortermittlung in der App anfordern.
  • Verwenden Sie die Xcode-Debugging-Tools, um Logs aufzurufen und Fehler in der Anwendung zu beheben.

Den Code verstehen

In diesem Teil der Anleitung werden die wesentlichsten Teile der App current-place-on-map erläutert, damit Sie besser verstehen, wie Sie eine ähnliche App erstellen.

Die App current-place-on-map hat zwei Ansichts-Controller: einen zur Anzeige einer Karte, auf dem der aktuell ausgewählte Ort des Nutzers zu sehen ist, und einen, mit dem Nutzer eine Liste mit möglichen Orten zur Auswahl haben. Jeder Ansichts-Controller hat dieselben Variablen zum Verfolgen der Liste der wahrscheinlichen Orte (likelyPlaces) und zum Angeben der Auswahl des Nutzers (selectedPlace). Die Navigation zwischen Ansichten erfolgt mithilfe von Sequenzen.

Berechtigung zur Standortermittlung wird angefordert

Ihre App muss den Nutzer um seine Einwilligung zur Verwendung der Standortdienste bitten. Füge dazu den Schlüssel NSLocationAlwaysUsageDescription in die Datei Info.plist für die Anwendung ein und setze den Wert jedes Schlüssels auf einen String, der beschreibt, wie die App Standortdaten verwenden möchte.

Standortmanager einrichten

Mit CLLocationManager kannst du den aktuellen Standort des Geräts ermitteln und regelmäßige Updates anfordern, wenn das Gerät an einen neuen Standort verlegt wird. Diese Anleitung enthält den Code, den Sie zum Abrufen des Gerätestandorts benötigen. Weitere Informationen finden Sie in der Anleitung zum Abrufen des Nutzerstandorts in der Apple Developer-Dokumentation.

  1. Geben Sie den Standortmanager, den aktuellen Standort, die Kartenansicht, den Places-Client und die Standard-Zoomstufe auf Klassenebene an.
  2. Swift

    var locationManager: CLLocationManager!
    var currentLocation: CLLocation?
    var mapView: GMSMapView!
    var placesClient: GMSPlacesClient!
    var preciseLocationZoomLevel: Float = 15.0
    var approximateLocationZoomLevel: Float = 10.0
          

    Objective-C

    CLLocationManager *locationManager;
    CLLocation * _Nullable currentLocation;
    GMSMapView *mapView;
    GMSPlacesClient *placesClient;
    float preciseLocationZoomLevel;
    float approximateLocationZoomLevel;
          
  3. Initialisiere den Standortmanager und GMSPlacesClient in viewDidLoad().
  4. Swift

    // Initialize the location manager.
    locationManager = CLLocationManager()
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.distanceFilter = 50
    locationManager.startUpdatingLocation()
    locationManager.delegate = self
    
    placesClient = GMSPlacesClient.shared()
          

    Objective-C

    // Initialize the location manager.
    locationManager = [[CLLocationManager alloc] init];
    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    [locationManager requestWhenInUseAuthorization];
    locationManager.distanceFilter = 50;
    [locationManager startUpdatingLocation];
    locationManager.delegate = self;
    
    placesClient = [GMSPlacesClient sharedClient];
          
  5. Deklarieren Sie Variablen, die die Liste der möglichen Orte und den vom Nutzer ausgewählten Ort enthalten.
  6. Swift

    // An array to hold the list of likely places.
    var likelyPlaces: [GMSPlace] = []
    
    // The currently selected place.
    var selectedPlace: GMSPlace?
          

    Objective-C

    // An array to hold the list of likely places.
    NSMutableArray<GMSPlace *> *likelyPlaces;
    
    // The currently selected place.
    GMSPlace * _Nullable selectedPlace;
          
  7. Fügen Sie mithilfe einer Erweiterungsklausel Bevollmächtigte hinzu, die Ereignisse für den Standortmanager verarbeiten.
  8. Swift

    // Delegates to handle events for the location manager.
    extension MapViewController: CLLocationManagerDelegate {
    
      // Handle incoming location events.
      func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location: CLLocation = locations.last!
        print("Location: \(location)")
    
        let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
        let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
                                              longitude: location.coordinate.longitude,
                                              zoom: zoomLevel)
    
        if mapView.isHidden {
          mapView.isHidden = false
          mapView.camera = camera
        } else {
          mapView.animate(to: camera)
        }
    
        listLikelyPlaces()
      }
    
      // Handle authorization for the location manager.
      func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        // Check accuracy authorization
        let accuracy = manager.accuracyAuthorization
        switch accuracy {
        case .fullAccuracy:
            print("Location accuracy is precise.")
        case .reducedAccuracy:
            print("Location accuracy is not precise.")
        @unknown default:
          fatalError()
        }
    
        // Handle authorization status
        switch status {
        case .restricted:
          print("Location access was restricted.")
        case .denied:
          print("User denied access to location.")
          // Display the map using the default location.
          mapView.isHidden = false
        case .notDetermined:
          print("Location status not determined.")
        case .authorizedAlways: fallthrough
        case .authorizedWhenInUse:
          print("Location status is OK.")
        @unknown default:
          fatalError()
        }
      }
    
      // Handle location manager errors.
      func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        locationManager.stopUpdatingLocation()
        print("Error: \(error)")
      }
    }
          

    Objective-C

    // Delegates to handle events for the location manager.
    #pragma mark - CLLocationManagerDelegate
    
    // Handle incoming location events.
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
    {
      CLLocation *location = locations.lastObject;
      NSLog(@"Location: %@", location);
    
      float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;
      GMSCameraPosition * camera = [GMSCameraPosition cameraWithLatitude:location.coordinate.latitude
                                                               longitude:location.coordinate.longitude
                                                                    zoom:zoomLevel];
    
      if (mapView.isHidden) {
        mapView.hidden = NO;
        mapView.camera = camera;
      } else {
        [mapView animateToCameraPosition:camera];
      }
    
      [self listLikelyPlaces];
    }
    
    // Handle authorization for the location manager.
    - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
    {
      // Check accuracy authorization
      CLAccuracyAuthorization accuracy = manager.accuracyAuthorization;
      switch (accuracy) {
        case CLAccuracyAuthorizationFullAccuracy:
          NSLog(@"Location accuracy is precise.");
          break;
        case CLAccuracyAuthorizationReducedAccuracy:
          NSLog(@"Location accuracy is not precise.");
          break;
      }
    
      // Handle authorization status
      switch (status) {
        case kCLAuthorizationStatusRestricted:
          NSLog(@"Location access was restricted.");
          break;
        case kCLAuthorizationStatusDenied:
          NSLog(@"User denied access to location.");
          // Display the map using the default location.
          mapView.hidden = NO;
        case kCLAuthorizationStatusNotDetermined:
          NSLog(@"Location status not determined.");
        case kCLAuthorizationStatusAuthorizedAlways:
        case kCLAuthorizationStatusAuthorizedWhenInUse:
          NSLog(@"Location status is OK.");
      }
    }
    
    // Handle location manager errors.
    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
      [manager stopUpdatingLocation];
      NSLog(@"Error: %@", error.localizedDescription);
    }
          

Karte hinzufügen

Erstellen Sie eine Karte und fügen Sie sie der Ansicht in viewDidLoad() im Hauptansichts-Controller hinzu. Die Karte bleibt ausgeblendet, bis ein Standortupdate empfangen wird. Standortaktualisierungen werden in der Erweiterung CLLocationManagerDelegate verarbeitet.

Swift

// A default location to use when location permission is not granted.
let defaultLocation = CLLocation(latitude: -33.869405, longitude: 151.199)

// Create a map.
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
                                      longitude: defaultLocation.coordinate.longitude,
                                      zoom: zoomLevel)
mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
mapView.settings.myLocationButton = true
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.isMyLocationEnabled = true

// Add the map to the view, hide it until we've got a location update.
view.addSubview(mapView)
mapView.isHidden = true
      

Objective-C

// A default location to use when location permission is not granted.
CLLocationCoordinate2D defaultLocation = CLLocationCoordinate2DMake(-33.869405, 151.199);

// Create a map.
float zoomLevel = locationManager.accuracyAuthorization == CLAccuracyAuthorizationFullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel;
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:defaultLocation.latitude
                                                        longitude:defaultLocation.longitude
                                                             zoom:zoomLevel];
mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera];
mapView.settings.myLocationButton = YES;
mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
mapView.myLocationEnabled = YES;

// Add the map to the view, hide it until we've got a location update.
[self.view addSubview:mapView];
mapView.hidden = YES;
      

Nutzer auffordern, ihren aktuellen Ort auszuwählen

Verwenden Sie das Places SDK for iOS, um die fünf häufigsten Ortswahrscheinlichkeiten basierend auf dem aktuellen Standort des Nutzers zu ermitteln und die Liste in einem UITableView darzustellen. Wenn der Nutzer einen Ort auswählt, wird der Karte eine Markierung hinzugefügt.

  1. Rufen Sie eine Liste mit Orten ab, die wahrscheinlich für ein UITableView ausgefüllt werden sollen. In dieser Liste kann der Nutzer den Ort auswählen, an dem er sich aktuell befindet.
  2. Swift

    // Populate the array with the list of likely places.
    func listLikelyPlaces() {
      // Clean up from previous sessions.
      likelyPlaces.removeAll()
    
      let placeFields: GMSPlaceField = [.name, .coordinate]
      placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: placeFields) { (placeLikelihoods, error) in
        guard error == nil else {
          // TODO: Handle the error.
          print("Current Place error: \(error!.localizedDescription)")
          return
        }
    
        guard let placeLikelihoods = placeLikelihoods else {
          print("No places found.")
          return
        }
    
        // Get likely places and add to the list.
        for likelihood in placeLikelihoods {
          let place = likelihood.place
          self.likelyPlaces.append(place)
        }
      }
    }
          

    Objective-C

    // Populate the array with the list of likely places.
    - (void) listLikelyPlaces
    {
      // Clean up from previous sessions.
      likelyPlaces = [NSMutableArray array];
    
      GMSPlaceField placeFields = GMSPlaceFieldName | GMSPlaceFieldCoordinate;
      [placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:placeFields callback:^(NSArray<GMSPlaceLikelihood *> * _Nullable likelihoods, NSError * _Nullable error) {
        if (error != nil) {
          // TODO: Handle the error.
          NSLog(@"Current Place error: %@", error.localizedDescription);
          return;
        }
    
        if (likelihoods == nil) {
          NSLog(@"No places found.");
          return;
        }
    
        for (GMSPlaceLikelihood *likelihood in likelihoods) {
          GMSPlace *place = likelihood.place;
          [likelyPlaces addObject:place];
        }
      }];
    }
          
  3. Öffnen Sie eine neue Ansicht, um dem Nutzer Orte zu zeigen, die wahrscheinlich für ihn geeignet sind. Wenn der Nutzer auf „Get Place“ tippt, wird eine neue Ansicht angezeigt und er sieht eine Liste möglicher Orte, aus denen er auswählen kann. Die Funktion prepare aktualisiert PlacesViewController mit der Liste der aktuell wahrscheinlichen Orte und wird bei einem Segue automatisch aufgerufen.
  4. Swift

    // Prepare the segue.
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
      if segue.identifier == "segueToSelect" {
        if let nextViewController = segue.destination as? PlacesViewController {
          nextViewController.likelyPlaces = likelyPlaces
        }
      }
    }
          

    Objective-C

    // Prepare the segue.
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
      if ([segue.identifier isEqualToString:@"segueToSelect"]) {
        if ([segue.destinationViewController isKindOfClass:[PlacesViewController class]]) {
          PlacesViewController *placesViewController = (PlacesViewController *)segue.destinationViewController;
          placesViewController.likelyPlaces = likelyPlaces;
        }
      }
    }
          
  5. Füllen Sie in PlacesViewController die Tabelle mit der Liste der wahrscheinlichsten Orte aus. Verwenden Sie dazu die Delegaterweiterung UITableViewDataSource.
  6. Swift

    // Populate the table with the list of most likely places.
    extension PlacesViewController: UITableViewDataSource {
      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return likelyPlaces.count
      }
    
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
        let collectionItem = likelyPlaces[indexPath.row]
    
        cell.textLabel?.text = collectionItem.name
    
        return cell
      }
    }
          

    Objective-C

    #pragma mark - UITableViewDataSource
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
      return self.likelyPlaces.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
      return [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier forIndexPath:indexPath];
    }
    @end
          
  7. Verarbeitet die Auswahl des Nutzers mit der Delegierungserweiterung UITableViewDelegate.
  8. Swift

    class PlacesViewController: UIViewController {
    
      // ...
    
      // Pass the selected place to the new view controller.
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "unwindToMain" {
          if let nextViewController = segue.destination as? MapViewController {
            nextViewController.selectedPlace = selectedPlace
          }
        }
      }
    }
    
    // Respond when a user selects a place.
    extension PlacesViewController: UITableViewDelegate {
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedPlace = likelyPlaces[indexPath.row]
        performSegue(withIdentifier: "unwindToMain", sender: self)
      }
    
      // Adjust cell height to only show the first five items in the table
      // (scrolling is disabled in IB).
      func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return self.tableView.frame.size.height/5
      }
    
      // Make table rows display at proper height if there are less than 5 items.
      func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if (section == tableView.numberOfSections - 1) {
          return 1
        }
        return 0
      }
    }
          

    Objective-C

    @interface PlacesViewController () <UITableViewDataSource, UITableViewDelegate>
    // ...
    
    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    
    }
    
    #pragma mark - UITableViewDelegate
    
    // Respond when a user selects a place.
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
      self.selectedPlace = [self.likelyPlaces objectAtIndex:indexPath.row];
      [self performSegueWithIdentifier:@"unwindToMain" sender:self];
    }
    
    // Adjust cell height to only show the first five items in the table
    // (scrolling is disabled in IB).
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
      return self.tableView.frame.size.height/5;
    }
    
    // Make table rows display at proper height if there are less than 5 items.
    -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
    {
      if (section == tableView.numberOfSections - 1) {
        return 1;
      }
      return 0;
    }
          

Markierung zur Karte hinzufügen

Wenn der Nutzer eine Auswahl trifft, verwenden Sie einen Abschnitt zum Entspannen, um zur vorherigen Ansicht zurückzukehren, und fügen Sie die Markierung auf der Karte hinzu. Die IBAction unwindToMain wird automatisch aufgerufen, wenn Sie zum Hauptansichts-Controller zurückkehren.

Swift

// Update the map once the user has made their selection.
@IBAction func unwindToMain(segue: UIStoryboardSegue) {
  // Clear the map.
  mapView.clear()

  // Add a marker to the map.
  if let place = selectedPlace {
    let marker = GMSMarker(position: place.coordinate)
    marker.title = selectedPlace?.name
    marker.snippet = selectedPlace?.formattedAddress
    marker.map = mapView
  }

  listLikelyPlaces()
}
      

Objective-C

// Update the map once the user has made their selection.
- (void) unwindToMain:(UIStoryboardSegue *)segue
{
  // Clear the map.
  [mapView clear];

  // Add a marker to the map.
  if (selectedPlace != nil) {
    GMSMarker *marker = [GMSMarker markerWithPosition:selectedPlace.coordinate];
    marker.title = selectedPlace.name;
    marker.snippet = selectedPlace.formattedAddress;
    marker.map = mapView;
  }

  [self listLikelyPlaces];
}
      

Glückwunsch! Sie haben eine iOS-App erstellt, in der Nutzer ihren aktuellen Ort auswählen können. Das Ergebnis wird auf einer Google-Karte angezeigt. Sie haben dabei gelernt, wie Sie das Places SDK for iOS, das Maps SDK for iOS und das Apple Core Location Framework verwenden.