Todos conocemos Google Maps, una herramienta que es capaz de muchas más cosas de las que parece a simple vista. En este capítulo de introducción vamos a crear nuestro primer mapa en Android y añadiremos marcadores.

Api Key de Google Maps

A diferencia de otras librerías que hemos usado, para poder trabajar con Google Maps necesitamos una api key. Esto no es más que un código para verificar que el usuario que crea un proyecto es el creador de la app. No importa si no comprendes mucho esto, a continuación te quedará más claro.

Debemos crear un proyecto en Google Cloud. Una vez accedas a este link verás que en la esquina superior derecha podemos crear un nuevo proyecto. Haremos clic y seleccionaremos un nombre. No es necesario seleccionar Ubicación.

Creando proyecto Google Cloud mapas en kotlin android
Creando proyecto en Google Clouds.

Una vez creado tendremos un panel de control con multitud de opciones que a día de hoy ignoraremos. En el menú lateral seleccionaremos APIs y servicios y una vez dentro en la parte superior pulsamos HABILITAR APIS Y SERVICIOS. Apareceremos en un buscador donde están todas las APIs de Google, en nuestro caso tenemos que buscar Maps SDK for Android.

Maps SDK for Android tutorial kotlin español
Api de Google Maps para Android.

Seleccionamos el API y dentro nos saldrá un botón azul para habilitarla, pulsamos en HABILITAR. Ya tenemos habilitado los mapas en Android en nuestro proyecto, el siguiente paso será generar una API KEY que deberemos añadir en nuestro proyecto. Para ello volvemos al panel de control de nuestro proyecto de Google Cloud y esta vez hacemos click en el menú lateral APIs y servicios > Credenciales.

En la parte superior central pulsaremos en CREAR CREDENCIALES > Clave de API

Crear api google maps para android
Proceso de creación de Clave API.

Nos saldrá un diálogo con la api key creada.

Clave api key google maps en android creada kotlin
Clave de API creada.

Let’s code!

Crearemos un nuevo proyecto, en mi caso lo llamaré MapExample. Como siempre seleccionaremos empty activity.

Para poder utilizar Google Maps tenemos que añadir una dependencia (una librería), así que iremos a Build.Gradle y dentro de dependencies{} añadimos la siguiente línea.

implementation 'com.google.android.gms:play-services-maps:17.0.0'

Una vez sincronizado vamos a proceder a añadir el api key que hemos creado. Con la vista en modo project vamos a app > src > main > res > values y haremos click derecho en la carpeta new > Values Resource File, crearemos un fichero llamado google_maps_api.

<resources>
    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">KEY</string>
</resources>

Este será el contenido de nuestro fichero, vamos a analizarlo. Hemos creado un recurso de tipo string, llamado google_maps_key en cual contendrá nuestra api key. Debemos sustituir la palabra KEY por nuestra api key.

Como ya tenemos el recurso creado, debemos decirle a nuestro proyecto android que ya tenemos una api key válida, es por ello que iremos al fichero AndroidManifest.xml y dentro de la etiqueta <application> añadiremos nuestra propia etiqueta.

<meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

Con esto le decimos al proyecto que ya tenemos una api key y que el valor de esta está alojada en el recurso de tipo string con nombre google_maps_key.

Añadiendo lógica y diseño

Ya con todo configurado es el momento de empezar a implementar el mapa. Iremos a activity_main.xml y sustituiremos el contenido del layout que nos viene por defecto por un componente fragment.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragmentMap"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

No hemos trabajado con este componente nunca, no es muy habitual. A diferencia del capítulo 22 – Fragments en Kotlin en esta ocasión estamos creando el fragment desde el layout, pero le estamos diciendo que sea de tipo com.google.android.gms.maps.SupportMapFragment, que es un fragment que viene dentro de la librería que instalamos anteriormente.

Es el turno de nuestra clase MainActivity. Lo primero que haremos será crear una función llamada createMapFragment() que será la encargada de inicializar el fragment que hemos creado en el layout. Esta función la llamaremos desde el método onCreate().

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        createMapFragment()
    }

    private fun createMapFragment() {
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.fragmentMap) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

Creamos una variable y le decimos a supportFragmentManager que busque un fragment que tenga una id llamada fragmentMap, que será la id del fragment que añadimos en activity_main.xml, luego a nuestra variable que contiene un SupportMapFragment (fragment de tipo mapa) la inicializamos con la función getMapAsync(this).

Es en este momento en el que te estarás empezando a volver loco porque hay un error en la última línea de la función. Esto es porque getMapAsync(this) necesita que nuestra activity implemente la función onMapReady() y para ello tenemos que añadir la interfaz OnMapReadyCallback.

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

Esta interfaz que hemos implementado nos obliga a sobrescribir la función onMapReady(), que se llamará automáticamente cuando el mapa haya cargado. Es por eso que nuestra activity nos marca un error, pues no hemos sobrescrito el método todavía.

    override fun onMapReady(googleMap: GoogleMap) {
        
    }

Esta función nos devolverá un objeto GoogleMap que será muy útil, es por ello que debemos guardarlo en una variable. ¿Cómo lo haremos? Muy sencillo, crearemos una variable en la parte superior de la clase y le asignaremos el objeto GoogleMap cuando lo recibamos.

    private lateinit var map: GoogleMap

    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap
    }

Nuestra clase completa quedaría así.

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var map: GoogleMap

    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        createMapFragment()
    }

    private fun createMapFragment() {
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.fragmentMap) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

}

Ahora ejecutamos la aplicación y veremos nuestro mapa.

Google Maps funcionando en app android con kotlin
Google Map funcionando en nuestra app.

Markers y animaciones

Google también nos permite añadir markers, pequeñas etiquetas para marcar un lugar a través de sus coordenadas. Para ello crearemos una nueva función que la llamaremos cuando el método onMapReady() se ejecute.

Los markers se crean de una forma muy sencilla, basta con crear una instancia de un objeto LatLng() que recibirá dos parámetros, la latitud y la longitud. Yo en este ejemplo he puesto las coordenadas de mi playa favorita.

val favoritePlace = LatLng(28.044195,-16.5363842)
 map.addMarker(MarkerOptions().position(favoritePlace).title("Mi playa favorita!"))

Una vez creado el objeto con las coordenadas, llamaremos a nuestro mapa y con la función addMarker() le añadiremos MarkerOptions().position(favoritePlace).title(«Mi playa favorita!»), simplemente le hemos puesto las coordenadas anteriormente creadas y hemos asignado un title que se mostrará cuando el usuario pulse el marker. El title es opcional.

Terminaremos añadiendo una animación para que el mapa haga zoom donde creamos el marker.

map.animateCamera(
            CameraUpdateFactory.newLatLngZoom(favoritePlace, 18f),
            4000,
            null
        )

La función animateCamera() recibirá tres parámetros:

  • Un CameraUpdateFactory que a su vez llevará otros dos parámetros, el primero las coordenadas donde queremos hacer zoom y el segundo valor (es un float) será la cantidad de zoom que queremos hacer en dichas coordenadas.
  • La duración de la animación en milisegundos, por ejemplo 4000 milisegundos son 4 segundos.
  • Un listener que no vamos a utilizar, simplemente añadimos null.

Nuestra clase MainActivity quedaría así.

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var map: GoogleMap

    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap
        createMarker()
    }

    private fun createMarker() {
        val favoritePlace = LatLng(28.044195,-16.5363842)
        map.addMarker(MarkerOptions().position(favoritePlace).title("Mi playa favorita!"))
        map.animateCamera(
            CameraUpdateFactory.newLatLngZoom(favoritePlace, 18f),
            4000,
            null
        )
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        createMapFragment()
    }

    private fun createMapFragment() {
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.fragmentMap) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

}

Ejecutamos la app y tendremos nuestra app completa.

Mapa creado en Android con Kotlin con marker y animaciones.
Mapa completo.