Compila una app de navegación simple para iOS en Swift con el SDK de Navigation de Google Maps Platform

1. Antes de comenzar

En este codelab, aprenderás a crear una app simple para iOS que usa el SDK de Navigation de Google Maps Platform para navegar a un destino preconfigurado.

Así se verá tu app cuando hayas terminado.

7e7c194a98d6dfa4.png

Requisitos previos

Qué aprenderás

  • Cómo crear una app simple para iOS en Swift que usa el SDK de Navigation para navegar a un destino
  • Cómo integrar el SDK de Navigation desde el repositorio remoto de Cocoapods
  • Cómo administrar los permisos de ubicación y el acuerdo del usuario con las condiciones del usuario final del SDK de Navigation
  • Cómo inicializar el SDK
  • Cómo establecer un destino y comenzar la guía de navegación

Requisitos

  • La versión estable más reciente de XCode
  • Una Cuenta y un proyecto de Google con la facturación habilitada
  • Un dispositivo iOS o un dispositivo emulado que se ejecuta en el simulador de XCode Cualquiera que elijas, debe cumplir con los requisitos mínimos del SDK de Navigation.

2. Prepárate

Si aún no tienes una cuenta de Google Cloud Platform y un proyecto con la facturación habilitada, configura tu proyecto de Google Cloud siguiendo las instrucciones de Comienza a usar Google Maps Platform.

Selecciona un proyecto de Google Cloud en la consola

En el Cloud Console, haz clic en el menú desplegable del proyecto y selecciona el proyecto que deseas usar para este codelab.

El menú desplegable del selector de proyectos en la consola de Google Cloud.

Habilita el SDK de Navigation en tu proyecto

Habilita las API y los SDK de Google Maps Platform necesarios para este codelab en el Google Cloud Marketplace.

Navega a APIs y servicios > Biblioteca en la consola de Google Cloud y busca "SDK de Navigation".

Deberías ver un resultado de la búsqueda.

La pantalla de la biblioteca de APIs en la consola de Google Cloud, en la que se muestra la página del SDK de Navigation.

Haz clic en SDK de Navigation para abrir la página Detalles del producto. Haz clic en Habilitar para habilitar el SDK en tu proyecto.

Repite este proceso para el SDK de Google Maps para iOS.

Crea una clave de API

Genera una clave de API en la página Credenciales de Cloud Console. Todas las solicitudes a Google Maps Platform requieren una clave de API. En la página Credenciales de la consola, haz clic en "+Crear credenciales" en la parte superior de la página y selecciona "Clave de API" en las opciones.

Para el uso en producción, se recomienda establecer una restricción de aplicación para tu clave de API, pero es opcional para este codelab.

3. Obtén los archivos del proyecto de muestra

En esta sección, se describe cómo configurar un proyecto básico de app de XCode vacío clonando archivos del repositorio de GitHub para este codelab. El repositorio de GitHub contiene versiones anteriores y posteriores del código del codelab. El codelab comenzará con una plantilla de proyecto vacía y se compilará hasta el estado final. Puedes usar el proyecto terminado en el repositorio como referencia si te quedas atascado.

Clona el repositorio o descarga el código

Navega hasta el directorio en el que deseas almacenar el codelab.

Luego, clona el repositorio o descarga el código:

git clone https://github.com/googlemaps-samples/codelab-navigation-101-ios-swift

Si no tienes git instalado, haz clic en este botón para obtener el código:

Para que puedas comenzar lo más rápido posible, el repositorio contiene un código inicial en la carpeta Starter que te ayudará a seguir este codelab. También hay un proyecto Solution terminado en caso de que quieras adelantarte o verificar tu progreso en cualquier momento. Para usar el proyecto de solución, deberás seguir las instrucciones de "Instala con Cocoapods" que se indican a continuación y, luego, ejecutar el comando "pod update" desde la carpeta solution/Navigation SDK Codelab.

Una vez que hayas clonado el repositorio de forma local, usa XCode para abrir la carpeta Starter como un proyecto existente. Verifica que el proyecto se compile y se ejecute.

Conecta un dispositivo o configura el simulador de XCode

4. Agrega el SDK de Navigation a tu app

Hay tres formas de integrar el SDK de Navigation en un proyecto de XCode:este codelab usa CocoaPods. Para obtener detalles sobre cómo realizar la integración con Swift Package Manager o instalar manualmente el SDK, consulta Crea el proyecto de Xcode y instala el SDK de Navigation en la documentación del SDK de Navigation.

Instala con Cocoapods

Si todavía no tienes la herramienta CocoaPods, instálala en macOS ejecutando el siguiente comando desde la terminal. Para obtener más detalles, consulta la Guía de introducción de CocoaPods.

sudo gem install cocoapods

Crea un archivo nuevo llamado Podfile en la carpeta de tu proyecto, dentro de la carpeta starter/Navigation SDK Codelab (en XCode, File > New > File > Other > Empty, guarda como "Podfile").

Agrega el siguiente contenido a tu Podfile:

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '15.0'

target 'Navigation SDK Codelab' do
  pod 'GoogleNavigation', '9.1.1'
end

Ahorra Podfile.

Abre una terminal y cambia el directorio a la ubicación en la que guardaste tu Podfile (debe ser la carpeta "starter/Navigation SDK Codelab" en el repositorio del codelab).

cd "<path-to-starter-project-folder>/Navigation SDK Codelab"

Ejecuta el comando pod install. Esto instalará las APIs especificadas en el Podfile, junto con las dependencias.

pod install

Cierra Xcode. Luego, haz doble clic en el archivo .xcworkspace de tu proyecto para abrirlo y que se inicie Xcode. A partir de este momento, usa el archivo .xcworkspace para abrir el proyecto.

Verifica que se haya agregado un directorio de Pods a la estructura del proyecto y que contenga los pods "GoogleMaps" y "GoogleNavigation".

6e81772ee067d452.png

Agrega tu clave de API

Agrega tu clave de API a AppDelegate.swift de la siguiente manera:

  1. Agrega las siguientes instrucciones de importación:
import GoogleMaps
import GoogleNavigation
  1. Agrega lo siguiente a tu método application(_:didFinishLaunchingWithOptions:):
GMSServices.provideAPIKey("YOUR_API_KEY")

Reemplaza "YOUR_API_KEY" por la clave de API que creaste en el paso anterior.

Compila tu proyecto y corrige los errores.

5. Configura los permisos de la app

El SDK de Navigation depende de los indicadores de GPS para proporcionar la ubicación ajustada a la ruta y la guía paso a paso, por lo que tu app deberá pedirle al usuario que otorgue acceso a datos de ubicación precisos.

Para ello, agregarás algunas propiedades a Info.plist de tus apps en Xcode, agregarás código a tu app para solicitar permiso al usuario en el tiempo de ejecución y controlarás los errores, como que no se otorgue el permiso o que la ubicación no esté disponible.

Abre Info.plist en Xcode. Debe verse más o menos así.

6532a85bd9ac8fb4.png

Solicita permiso de ubicación precisa

Puedes agregar valores nuevos colocando el puntero del mouse sobre la fila "Information Property List" hasta que veas un ícono "+". Haz clic en "+" para ver un diálogo con nombres de propiedades sugeridos, pero ten en cuenta que también puedes agregar propiedades de forma manual.

Agrega las siguientes propiedades y valores a Info.plist:

Propiedad

Valor

Privacy - Location Always And When In Use Usage Description

"This app requires your device location in order to provide turn-by-turn navigation"

Privacy - Location When In Use Usage Description

"This app requires your device location in order to provide turn-by-turn navigation"

allowsBackgroundLocationUpdates

Solicita permiso de ubicación en segundo plano

Agrega las siguientes propiedades y valores a Info.plist:

UIBackgroundModes > Add Row > Item 0: App registers for location updates (selecciona este valor de la lista desplegable de sugerencias)

Info.plist debería verse más o menos así cuando termines.

3b0c49018451d0ff.png

Solicita acceso a la ubicación en el tiempo de ejecución

Agrega las siguientes instrucciones de importación a ViewController.swift:

import GoogleNavigation

Agrega la siguiente declaración a tu clase ViewController:

var locationManager: CLLocationManager!

Agrega una anulación de método para loadView() y llama a locationManager.requestAlwaysAuthorization():

override func loadView() {
        locationManager = CLLocationManager()
        locationManager.requestAlwaysAuthorization()

Ahora, tu app solicitará la ubicación del usuario y la pondrá a disposición de tu app si otorga permiso .

Solicite permiso para mostrar notificaciones

Agrega el siguiente código a loadView() para solicitar permiso al usuario para mostrar notificaciones, que serán necesarias para mostrar instrucciones de maniobra de navegación.

UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) {
        granted, error in
        // Handle denied authorization to display notifications.
          if !granted || error != nil {
              print("User rejected request to display notifications.")
          }
        }

Compila y ejecuta la app, y verifica que se te solicite compartir la ubicación y habilitar las notificaciones.

ad5f665a21170c49.png

6. Agrega una interfaz de usuario de navegación

En este paso, agregarás un mapa y lo configurarás para que muestre una ubicación. Luego, le mostrarás al usuario un diálogo con las condiciones de uso del SDK de Navigation.

Agrega una vista de mapa a tu app

Agrega esta línea para declarar una variable GMSMapView en tu ViewController.

var mapView: GMSMapView!

Agrega el siguiente código a loadView() en tu Viewcontroller.swift para inicializar el mapa.

let camera = GMSCameraPosition.camera(withLatitude: 51.483174, longitude: -0.177369, zoom: 14)
let options = GMSMapViewOptions()
options.camera = camera
options.frame = .zero
        
mapView = GMSMapView(options: options)
view = mapView

Compila y ejecuta tu app. Deberías ver un mapa centrado en el sudoeste de Londres.

1d46ce5c0851cae3.png

Muestra el diálogo de condiciones de uso del producto del SDK de Navigation

Agrega el siguiente código a ViewController.swift en el mismo método loadView() que el código anterior. Esto mostrará las condiciones de uso para el usuario final del SDK de Navigation. Si no se aceptan, no se habilitará la navegación.

// Show the terms and conditions.
let companyName = "Navigation SDK Codelab"
GMSNavigationServices.showTermsAndConditionsDialogIfNeeded(withCompanyName: companyName) { termsAccepted in
  if termsAccepted {
    // Enable navigation if the user accepts the terms.
    self.mapView.isNavigationEnabled = true
    // Request authorization for alert notifications which deliver guidance instructions
    // in the background.
  } else {
    // Handle the case when the user rejects the terms and conditions.
  }
}

Compila y ejecuta la app para ver el diálogo.

29f17ae5b4c07c9f.png

7. Agrega objetos de escucha para eventos clave de navegación

En este paso, se mostrará cómo configurar objetos de escucha para eventos clave, como la llegada a un destino o el cambio de ruta del conductor.

Para escuchar estos eventos, tu controlador de vista debe adoptar el protocolo GMSNavigatorListener.

Agrega este protocolo a la definición de clase en ViewController.swift.

class ViewController: UIViewController,
                      GMSNavigatorListener {

Ahora, agrega una línea de código para configurar el objeto de escucha en loadView():

// Add a listener for GMSNavigator.
mapView.navigator?.add(self)

Por último, agrega dos métodos a tu clase para controlar los eventos que se generan.

// Listener to handle arrival events.
func navigator(_ navigator: GMSNavigator, didArriveAt waypoint: GMSNavigationWaypoint) {
  print("You have arrived at: \(waypoint.title)")
}

// Listener for route change events.
func navigatorDidChangeRoute(_ navigator: GMSNavigator) {
  print("The route has changed.")
}

8. Establece un destino y comienza la guía

En esta sección, aprenderás a establecer un destino y comenzar la guía de navegación.

Crea una función nueva para la lógica de navegación.

Primero, agrega una función nueva llamada startNav() a tu ViewController. Esta contendrá la lógica para establecer un destino y comenzar a navegar.

// Create a route and start guidance.
@objc func startNav() {
}

Crea un Waypoint para el destino.

A continuación, crea un array de destinos con un solo punto de ruta.

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
  destinations.append(
    GMSNavigationWaypoint.init(
      placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
      title: "Trafalgar Square")!)
}

Llama a setDestinations()y controla la respuesta.

A continuación, llama a setDestinations y controla el GMSRouteStatus que se muestra.

Si el GMSRouteStatus es "OK", inicia la guía configurando isGuidanceActive=true en el objeto navigator de mapView. De lo contrario, imprime una instrucción para mostrar que hubo un error.

Si el valor GMSRouteStatus que se muestra es "OK", llama a mapView.locationSimulator.simulateLocationsAlongExistingRoute() para comenzar a simular la conducción por la ruta.

// Create a route and start guidance.
@objc func startNav() {
  var destinations = [GMSNavigationWaypoint]()
    destinations.append(
      GMSNavigationWaypoint.init(
        placeID: "ChIJH-tBOc4EdkgRJ8aJ8P1CUxo",
          title: "Trafalgar Square")!)
      
  mapView.navigator?.setDestinations(
    destinations
  ) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      return
    }
    //If routeStatus is OK, start guidance.
    self.mapView.navigator?.isGuidanceActive = true
    //start simulating driving along the route. self.mapView.locationSimulator?.simulateLocationsAlongExistingRoute()
    self.mapView.cameraMode = .following
  }
}

Controla los estados de error comunes

Es útil controlar los errores de GMSRouteStatus de forma más explícita, en especial cuando se depuran problemas iniciales con tu app nueva. Por ejemplo, es posible que obtengas permisos de ubicación, claves de API o errores de "no se encontró ruta" con más frecuencia al principio debido a tu configuración de depuración, por lo que puede ser útil controlar estos estados de error.

Agrega código que controle estos casos específicos y que imprima una instrucción en la consola.

mapView.navigator?.setDestinations(
  destinations
) { routeStatus in
    guard routeStatus == .OK else {
      print("Handle route statuses that are not OK.")
      switch routeStatus {
       case .locationUnavailable:
        print("Location unavailable.") //check permissions
      case .noRouteFound:
        print("No route found.") //check start location and destination
      case .waypointError:
        print("Waypoint error") //check Place ID
      default:
        print("Not sure what happened")
      }
    return
  }

Agrega un botón para iniciar la guía de navegación

Por último, agrega un botón a la IU y conéctalo al método startNav. Crea un método llamado makeButton() con el siguiente código. Llama a tu función makeButton() desde loadView().

// Add a button to the view.
func makeButton() {
  // A button to 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)
}

Compila y ejecuta tu app.

Nota: Ejecuta el código en

startNav()

llamará al

setDestinations()

método que genera un cargo después de los primeros 1,000 destinos usados. Consulta Uso y facturación para obtener más información.

9. ¡Felicitaciones!

Bien hecho, llegaste a tu destino.

7a69dcb75c904d7.png

Creaste una app simple que proporciona instrucciones de navegación paso a paso a un destino con el SDK de Navigation de Google Maps Platform.

Configuraste los permisos de la app y el diálogo de condiciones del usuario final del SDK de Navigation, y especificaste un destino con un ID de lugar. Controlaste varios estados de éxito y error en tu app.

10. Ve más allá

Si quieres llevar más lejos el desarrollo de tu app, consulta los siguientes temas para inspirarte.

  • Escucha más eventos de navegación. Agrega código para mostrar un mensaje si el tiempo o la distancia restantes superan un umbral.
  • Personaliza la interfaz de navegación.
  • Si quieres un desafío mayor, intenta agregar un selector de lugares de la API de Places para permitir que el usuario establezca el destino. Sugerencia: Las apps de demostración del SDK de Navigation tienen una implementación de muestra. Ejecuta pod try GoogleNavigation en la carpeta de tu proyecto para ver el código.