Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Sélectionner le lieu actuel et afficher les détails sur une carte

Ce tutoriel explique comment créer une application iOS pour:

  • Obtenir la position actuelle de l'appareil
  • Obtenez la liste des endroits où l'appareil est susceptible de se trouver.
  • Demander à l'utilisateur la meilleure correspondance de lieu
  • Affichez un repère sur la carte.

Suivez ce tutoriel pour créer une application iOS à l'aide du SDK Places pour iOS, du SDK Maps pour iOS et du framework d'Apple Core.

Récupérer le code

Clonez ou téléchargez le SDK Google Maps pour iOS à partir de GitHub.

Configurer votre projet de développement

Pour installer le SDK Places pour iOS et le SDK Maps pour iOS, procédez comme suit:

  1. Téléchargez et installez Xcode version 13.0 ou ultérieure.
  2. Si vous ne disposez pas encore de CocoaPods, installez-le sur macOS en exécutant la commande suivante à partir du terminal :
    sudo gem install cocoapods
  3. Dans le répertoire où vous avez enregistré l'exemple de dépôt (Get the code), accédez au répertoire tutorials/current-place-on-map.
  4. Exécutez la commande pod install. Cette action installe les API spécifiées dans Podfile, ainsi que toutes les dépendances éventuelles.
  5. Ouvrez (double-cliquez) la valeur current-place-on-map.xcworkspace du projet pour l'ouvrir dans Xcode. Vous devez utiliser le fichier .xcworkspace pour ouvrir le projet.

Pour obtenir des instructions d'installation détaillées, consultez les pages Premiers pas (Maps) et Premiers pas (Places).

Activer les API nécessaires et obtenir une clé API

Pour suivre ce tutoriel, vous avez besoin d'une clé API Google autorisée à utiliser le SDK Maps pour iOS et l'API Places.

  1. Suivez les instructions de la section Premiers pas avec Google Maps Platform pour configurer un compte de facturation et un projet avec ces deux produits.
  2. Suivez les instructions de la page Obtenir une clé API afin de créer une clé API pour le projet de développement que vous avez configuré précédemment.

Ajouter la clé API à votre application

Swift

Ajoutez votre clé API à votre fichier AppDelegate.swift comme suit :

  1. Notez que l'instruction d'importation suivante a été ajoutée au fichier :
    import GooglePlaces
    import GoogleMaps
  2. Modifiez la ligne suivante dans votre méthode application(_:didFinishLaunchingWithOptions:), en remplaçant YOUR_API_KEY par votre clé API :
    GMSPlacesClient.provideAPIKey("YOUR_API_KEY")
    GMSServices.provideAPIKey("YOUR_API_KEY")

Objective-C

Ajoutez votre clé API à votre fichier AppDelegate.m comme suit :

  1. Notez que l'instruction d'importation suivante a été ajoutée au fichier :
    @import GooglePlaces;
    @import GoogleMaps;
  2. Modifiez la ligne suivante dans votre méthode application(_:didFinishLaunchingWithOptions:), en remplaçant YOUR_API_KEY par votre clé API :
    [GMSPlacesClient provideAPIKey: @"YOUR_API_KEY"]
    [GMSServices provideAPIKey: @"YOUR_API_KEY"]

Créer et exécuter votre application

  1. Connectez un appareil iOS à votre ordinateur ou sélectionnez un simulateur dans le menu contextuel du schéma Xcode.
  2. Si vous utilisez un appareil, assurez-vous que les services de localisation sont activés. Si vous utilisez un simulateur, sélectionnez un emplacement dans le menu Fonctionnalités.
  3. Dans Xcode, cliquez sur l'option de menu Product/Run (Produit/Exécuter) (ou sur l'icône du bouton de lecture).

Xcode compile l'application, puis l'exécute sur l'appareil ou sur le simulateur.

Vous devriez voir une carte avec un certain nombre de repères centrés autour de votre position actuelle, comme dans l'image de cette page.

Dépannage :

  • Si aucune carte ne s'affiche, vérifiez que vous avez bien obtenu une clé API et que vous l'avez ajoutée à l'application, comme décrit ci-dessus. Recherchez des messages d'erreur concernant la clé API dans la console de débogage de Xcode.
  • Si vous avez limité la clé API à l'identifiant du bundle iOS, modifiez-la pour ajouter l'identifiant du bundle pour l'application : com.google.examples.current-place-on-map.
  • La carte ne s'affichera pas correctement si la demande d'autorisation pour les services de localisation est refusée.
    • Si vous utilisez un appareil, accédez à Paramètres/Général/Confidentialité/Services de localisation, puis réactivez les services de localisation.
    • Si vous utilisez un simulateur, accédez à Simulator/Reset Content and Settings... (Simulateur/Réinitialiser le contenu et les paramètres).
    Lors de la prochaine exécution de l'application, veillez à accepter l'invite des services de localisation.
  • Assurez-vous que votre connexion Wi-Fi ou GPS est bonne.
  • Si l'application se lance, mais qu'aucune carte ne s'affiche, assurez-vous d'avoir mis à jour le fichier Info.plist de votre projet avec les autorisations d'emplacement appropriées. Pour en savoir plus sur la gestion des autorisations, consultez le guide Demander l'autorisation de géolocalisation dans votre application ci-dessous.
  • Utilisez les outils de débogage Xcode pour afficher les journaux et déboguer l'application.

Comprendre le code

Cette partie du tutoriel décrit les principales composantes de l'application current-place-on-map pour vous aider à comprendre comment créer une application similaire.

L'application current-place-on-map comporte deux contrôleurs de vue : un pour afficher une carte indiquant le lieu actuellement sélectionné par l'utilisateur et un pour présenter à l'utilisateur une liste de lieux probables à choisir. Notez que chaque contrôleur de vue utilise les mêmes variables pour suivre la liste des lieux probables (likelyPlaces) et pour indiquer la sélection de l'utilisateur (selectedPlace). La navigation entre les vues est effectuée à l'aide de recherches.

Demande d'autorisation d'accéder à la position

Votre application doit inviter l'utilisateur à donner son consentement pour l'utilisation des services de localisation. Pour ce faire, incluez la clé NSLocationAlwaysUsageDescription dans le fichier Info.plist de l'application et définissez la valeur de chaque clé sur une chaîne décrivant l'usage prévu par l'application des données de localisation.

Configurer le gestionnaire d'établissements

Utilisez CLLocationManager pour connaître la position actuelle de l'appareil et demander des mises à jour régulières lorsque celui-ci change d'emplacement. Ce tutoriel fournit le code nécessaire pour obtenir la position de l'appareil. Pour en savoir plus, consultez le guide Obtenir la position de l'utilisateur dans la documentation Apple Developer.

  1. Déclarez le gestionnaire d'établissements, la position actuelle, la vue plan, le client Places et le niveau de zoom par défaut au niveau de la classe.
  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. Initialisez le gestionnaire d'établissements et GMSPlacesClient dans 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. Déclarez des variables qui contiennent la liste des lieux probables et le lieu sélectionné par l'utilisateur.
  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. Ajoutez des délégués pour gérer les événements du gestionnaire d'établissements à l'aide d'une clause d'extension.
  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);
    }
          

Ajouter une carte

Créez une carte et ajoutez-la à la vue dans viewDidLoad() dans le contrôleur de vue principal. La carte reste masquée jusqu'à ce que la mise à jour de la position soit reçue (les mises à jour de la position sont gérées dans l'extension CLLocationManagerDelegate).

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;
      

Inviter l'utilisateur à sélectionner son lieu actuel

Utilisez le SDK Places pour iOS pour obtenir les cinq lieux de probabilité les plus probables en fonction de la position actuelle de l'utilisateur et présentez la liste dans un UITableView. Lorsque l'utilisateur sélectionne un lieu, ajoutez un repère à la carte.

  1. Obtenez la liste des lieux probables pour renseigner un UITableView, à partir duquel l'utilisateur peut sélectionner le lieu où il se trouve actuellement.
  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. Ouvrez une nouvelle vue pour présenter des lieux probables à l'utilisateur. Lorsque l'utilisateur appuie sur "Obtenir le lieu", nous sélectionnons une nouvelle vue qui affiche une liste de lieux possibles. La fonction prepare met à jour PlacesViewController avec la liste des lieux probables actuels et est automatiquement appelée lorsqu'une séquence est effectuée.
  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. Dans PlacesViewController, remplissez la table à l'aide de la liste des lieux les plus probables, à l'aide de l'extension de délégué 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. Gérez la sélection de l'utilisateur à l'aide de l'extension de délégué 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;
    }
          

Ajouter un repère à la carte

Lorsque l'utilisateur effectue une sélection, utilisez la vue pour revenir à la vue précédente et ajoutez le repère à la carte. L'IBAction unwindToMain est appelé automatiquement lors du retour au contrôleur de vue principal.

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

Félicitations ! Vous avez créé une application iOS qui permet à l'utilisateur de choisir son lieu actuel et qui affiche le résultat sur une carte Google. Au cours de cette procédure, vous avez appris à utiliser le SDK Places pour iOS, le SDK Maps pour iOS et le framework de localisation Apple Core.