Comenzando con Google Maps para Android: Conceptos básicos
Spanish (Español) translation by CYC (you can also view the original English article)
Introducción
Sin lugar a dudas, los mapas son una de las herramientas más útiles para los usuarios cuando se incluyen en una aplicación. Este tutorial es el primero de una serie sobre Google Maps v2 para Android. Esto cubrirá la configuración de la API de Google Maps a través de Google Developer Console, incluido un fragmento de mapa en tus aplicaciones, mostrando la ubicación del usuario, agregando marcadores, dibujando en el mapa y algunos métodos generales que agregarán utilidad a tu aplicación. Todo el código para este tutorial se puede encontrar en GitHub.
1. Configurando la Consola de Desarrollador
Para utilizar la API de Google Maps, debes registrar tu aplicación en la Consola de desarrollador de Google y habilitar la API. Para hacerlo, ve a Google Developer Console. Si ya tienes un proyecto creado, puedes omitir la siguiente sección. Si no, puedes continuar y crear un nuevo proyecto para tu aplicación de mapas.
Paso 1: Crear un proyecto
Para crear un nuevo proyecto, haz clic en el botón azul Crear proyecto en la esquina superior izquierda de la pantalla. Si no ves el botón Crear proyecto, busca un botón etiquetado Crear un proyecto vacío.



Esto te presenta un diálogo que solicita un nombre de proyecto. Para este tutorial, he creado un proyecto llamado TutsPlusMaps. Existen algunas restricciones sobre el nombre del proyecto, ya que solo se permiten letras, números, comillas, guiones, espacios y signos de exclamación.



Una vez que presionas en Crear, aparece un cuadro de diálogo en la esquina inferior derecha de la página con un indicador de carga mientras se está creando el proyecto.
Paso 2: Habilitar la API de Maps
Cuando se haya creado el proyecto o hayas seleccionado un proyecto existente, te llevará a la pantalla de descripción general del proyecto. Desde aquí, deberás expandir las API y el elemento de autenticación en el panel de navegación izquierdo y hacer clic en API.



Si bien hay un cuadro de búsqueda en esta pantalla, observarás que Google colocó los elementos de API de Google Maps en la parte superior de la columna central para que los desarrolladores puedan acceder. Para este tutorial, haz clic en el ítem titulado Google Maps Android API bajo el encabezado API de Google Maps.



Esto te lleva a una pantalla donde puedes hacer clic en el botón azul Habilitar API para habilitar la API de Maps para tu proyecto.



Paso 3: Crear una clave API de Android
Una vez que hayas habilitado la API de Maps, haz clic en el elemento Credenciales en APIs y auth en la barra lateral de navegación para obtener una clave para acceder a la API de Maps en tu aplicación. Cuando se te presente el cuadro de diálogo Credenciales, presiona el botón azul Agregar credenciales y selecciona la clave de API.



Como esta es una aplicación de Android, debes seleccionar Android Key en el siguiente cuadro de diálogo. Si crearas la misma aplicación usando mapas en diferentes plataformas, podrías crear una clave para cada plataforma.



En la siguiente pantalla, haz clic en Agregar nombre de paquete y huella digital. Esto proporciona dos campos, uno para agregar un nombre de paquete y otro para agregar el SHA1 de la clave de firma de la aplicación.
Para este tutorial, usaré el nombre del paquete com.tutsplus.mapsdemo. Para obtener la firma SHA1, debe abrir una terminal o símbolo del sistema y navegar hasta la ubicación de la clave de firma de su aplicación. Esta puede ser tu clave de liberación o debug.keystore. Puedes generar el SHA1 con el siguiente comando:
1 |
keytool -list -v -keystore debug.keystore |



Después de haber creado tu clave SHA1 y haberla ingresado en el campo de texto, haz clic en el botón azul Crear . Luego se te presenta un cuadro de diálogo que contiene la clave de API que necesitas agregar a tu aplicación Android para acceder a la API de Maps.



2. Configurando el Proyecto Android
En este punto, puedes crear el proyecto inicial de Android con el mismo nombre de paquete que usaste para crear la clave API. Una vez que se haya creado tu proyecto, abre el archivo build.gradle. Debes importar la biblioteca Play Services para mapas. En este ejemplo, también necesitas importar la biblioteca Play Services de las ubicaciones para establecer una posición inicial para tu mapa. Coloca las siguientes líneas en el nodo dependencies
del archivo build.gradle.
1 |
compile 'com.google.android.gms:play-services-maps:7.8.0' |
2 |
compile 'com.google.android.gms:play-services-location:7.8.0' |
Una vez que hayas importado tus bibliotecas, puedes cerrar build.gradle y abrir tu archivo AndroidManifest.xml. Por encima del nodo application
, debes declarar que la aplicación utiliza OpenGL ES 2.0 y definir los permisos necesarios para tu aplicación.
Ten en cuenta que el permiso ACCESS_FINE_LOCATION
solo es necesario para esta demostración a fin de obtener la ubicación del usuario para definir dónde debe mostrarse inicialmente el mapa. Si tienes una ubicación conocida en tu propia aplicación, no es necesario utilizar la ubicación del usuario.
1 |
<uses-feature
|
2 |
android:glEsVersion="0x00020000" |
3 |
android:required="true"/> |
4 |
|
5 |
<uses-permission android:name="android.permission.INTERNET" /> |
6 |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
Dentro del nodo application
, necesitas agregar dos partes de metadatos. El primero informa a la aplicación que se utiliza Play Services y el segundo vincula la clave de Maps API con tu aplicación. En el siguiente fragmento de código, @string/google_api_key
es una referencia de cadena a la clave de Google Developer Console.
1 |
<meta-data
|
2 |
android:name="com.google.android.gms.version" |
3 |
android:value="@integer/google_play_services_version" /> |
4 |
|
5 |
<meta-data
|
6 |
android:name="com.google.android.geo.API_KEY" |
7 |
android:value="@string/google_api_key"/> |
Una vez que hayas terminado de actualizar AndroidManifest.xml, avanza y cierra el archivo. A continuación, debes crear una nueva clase Java, llamada MapFragment
, que amplía SupportMapFragment
. SupportMapFragment
se utiliza aquí en lugar de com.google.android.gms.maps.MapFragment
para agregar compatibilidad hacia atrás antes de API 12.
Si tu aplicación no necesita dispositivos que ejecuten versiones anteriores de Android, puedes usar com.google.android.gms.maps.MapFragment
. Una vez que hayas creado el fragmento base, debes implementar las seis interfaces que utilizaremos para esta demostración.
1 |
public class MapFragment extends SupportMapFragment implements GoogleApiClient.ConnectionCallbacks, |
2 |
GoogleApiClient.OnConnectionFailedListener, |
3 |
GoogleMap.OnInfoWindowClickListener, |
4 |
GoogleMap.OnMapLongClickListener, |
5 |
GoogleMap.OnMapClickListener, |
6 |
GoogleMap.OnMarkerClickListener { |
-
ConnectionCallbacks
yOnConnectionFailedListener
están diseñados para monitorear el estado deGoogleApiClient
, que se usa en esta aplicación para obtener la ubicación actual del usuario. -
OnInfoWindowClickListener
se activa cuando el usuario hace clic en la ventana de información que aparece sobre un marcador en el mapa. -
OnMapLongClickListener
yOnMapClickListener
se activan cuando el usuario toca o mantiene presionada una parte del mapa. - Se llama a
OnMarkerClickListener
cuando el usuario hace clic en un marcador en el mapa, que generalmente también muestra la ventana de información para ese marcador.
Cuando se te solicite, haz clic en la bombilla roja que aparece junto al nombre de la clase para agregar los métodos necesarios para estas interfaces.
Una vez que hayas creado el fragmento inicial, debes informar a MainActivity que debe usar este fragmento. Abre activity_main.xml de la carpeta de recursos y cámbialo para que incluya el fragmento como vista.
1 |
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android" |
2 |
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" |
3 |
android:layout_height="match_parent" |
4 |
tools:context=".MainActivity"> |
5 |
|
6 |
<fragment
|
7 |
android:id="@+id/map" |
8 |
android:name="com.tutsplus.mapsdemo.MapFragment" |
9 |
android:layout_width="match_parent" |
10 |
android:layout_height="match_parent"/> |
11 |
|
12 |
</RelativeLayout>
|
Después de actualizar el diseño de Activity, deberías poder ejecutar tu aplicación y ver un mapa de la Tierra que está completamente alejado y enfocado en la latitud 0, longitud 0.



3. Inicializando el mapa
Paso 1: Declarar tipos de mapas
Volviendo a nuestra clase MapFragment
, necesitas definir algunos valores globales en la parte superior de la clase para usar en tu aplicación.
1 |
private GoogleApiClient mGoogleApiClient; |
2 |
private Location mCurrentLocation; |
3 |
|
4 |
private final int[] MAP_TYPES = { GoogleMap.MAP_TYPE_SATELLITE, |
5 |
GoogleMap.MAP_TYPE_NORMAL, |
6 |
GoogleMap.MAP_TYPE_HYBRID, |
7 |
GoogleMap.MAP_TYPE_TERRAIN, |
8 |
GoogleMap.MAP_TYPE_NONE }; |
9 |
private int curMapTypeIndex = 0; |
Aquí mGoogleApiClient
y mCurrentLocation
se utilizan para obtener la ubicación del usuario para inicializar la cámara de mapa. MAP_TYPES
y curMapTypeIndex
se utilizan en el código de muestra para alternar entre diferentes tipos de visualización de mapa. Cada uno de los tipos de mapas tiene un propósito diferente, por lo que uno o más pueden ser adecuados para tus propias aplicaciones.
GoogleMap.MAP_TYPE_SATELLITE
muestra una vista de satélite del área sin nombres ni etiquetas de calles.



GoogleMap.MAP_TYPE_NORMAL
muestra un mapa genérico con nombres y etiquetas de calles.



GoogleMap.MAP_TYPE_HYBRID
combina el modo satelital y el normal, que muestra imágenes satelitales de un área con todas las etiquetas.



GoogleMap.MAP_TYPE_TERRAIN
es similar a un mapa normal, pero las texturas se agregan para mostrar los cambios en la elevación del entorno. Estas texturas son más visibles cuando el mapa está en ángulo con un arrastre de dos dedos.



GoogleMap.MAP_TYPE_NONE
es similar a un mapa normal, pero no muestra etiquetas ni coloraciones para el tipo de entorno en un área. Permite mostrar el tráfico y otras superposiciones en el mapa.



Paso 2: Creando el API Client
A continuación, debes crear tu GoogleApiClient
e iniciar LocationServices
para obtener la ubicación actual de tu usuario. Como mencioné antes, si tienes una ubicación configurada que deseas mostrar en lugar de enfocarte en el usuario, puedes omitir el uso de LocationServices
.
1 |
@Override
|
2 |
public void onViewCreated(View view, Bundle savedInstanceState) { |
3 |
super.onViewCreated(view, savedInstanceState); |
4 |
|
5 |
setHasOptionsMenu(true); |
6 |
|
7 |
mGoogleApiClient = new GoogleApiClient.Builder( getActivity() ) |
8 |
.addConnectionCallbacks( this ) |
9 |
.addOnConnectionFailedListener( this ) |
10 |
.addApi( LocationServices.API ) |
11 |
.build(); |
12 |
|
13 |
initListeners(); |
14 |
}
|
El método initListeners
vincula las interfaces que declaraste en la parte superior de la clase con el objeto GoogleMap
asociado con SupportMapFragment
. Así es como se ve la implementación:
1 |
private void initListeners() { |
2 |
getMap().setOnMarkerClickListener(this); |
3 |
getMap().setOnMapLongClickListener(this); |
4 |
getMap().setOnInfoWindowClickListener( this ); |
5 |
getMap().setOnMapClickListener(this); |
6 |
}
|
Es posible que hayas notado que el GoogleApiClient
y los receptores se crean y enlazan onViewCreated
en lugar del típico onCreate
Esto se debe a que el objeto GoogleMap
no se ha inicializado cuando se llama a onCreate
, por lo que debemos esperar hasta que la vista esté completamente creada antes de intentar llamar a getMap
para evitar una NullPointerException
.
Paso 3: Configurando el Mapa
Como configurarás la cámara de mapas una vez que hayas encontrado la ubicación del usuario a través de Play Services, utilizaremos el ciclo de vida de Play Services para iniciar nuestro mapa. Puedes conectar GoogleApiClient
en onStart
. Cuando el cliente se haya conectado, puedes tomar la ubicación recuperada más recientemente del usuario y usarla para apuntar la cámara del mapa.
1 |
@Override
|
2 |
public void onStart() { |
3 |
super.onStart(); |
4 |
mGoogleApiClient.connect(); |
5 |
}
|
6 |
|
7 |
@Override
|
8 |
public void onStop() { |
9 |
super.onStop(); |
10 |
if( mGoogleApiClient != null && mGoogleApiClient.isConnected() ) { |
11 |
mGoogleApiClient.disconnect(); |
12 |
}
|
13 |
}
|
14 |
|
15 |
@Override
|
16 |
public void onConnected(Bundle bundle) { |
17 |
mCurrentLocation = LocationServices |
18 |
.FusedLocationApi |
19 |
.getLastLocation( mGoogleApiClient ); |
20 |
|
21 |
initCamera( mCurrentLocation ); |
22 |
}
|
En el método initCamera
, se inicializa la cámara y algunas propiedades básicas del mapa. Empieza creando un objeto CameraPosition
a través de CameraPosition.Builder
, con un objetivo establecido para la latitud y la longitud de tu usuario y un nivel de zoom establecido.
La inclinación y el rumbo se utilizan aquí en tus valores predeterminados para ilustrar que están disponibles las opciones. Una vez que tienes un objeto CameraPosition
, puedes animar la cámara de mapa a esa posición usando CameraUpdateFactory
.
1 |
private void initCamera( Location location ) { |
2 |
CameraPosition position = CameraPosition.builder() |
3 |
.target( new LatLng( location.getLatitude(), |
4 |
location.getLongitude() ) ) |
5 |
.zoom( 16f ) |
6 |
.bearing( 0.0f ) |
7 |
.tilt( 0.0f ) |
8 |
.build(); |
9 |
|
10 |
getMap().animateCamera( CameraUpdateFactory |
11 |
.newCameraPosition( position ), null ); |
12 |
|
13 |
getMap().setMapType( MAP_TYPES[curMapTypeIndex] ); |
14 |
getMap().setTrafficEnabled( true ); |
15 |
getMap().setMyLocationEnabled( true ); |
16 |
getMap().getUiSettings().setZoomControlsEnabled( true ); |
17 |
}
|
Al final de este método, observarás que las últimas cuatro líneas establecen algunas propiedades para el mapa. Establece el tipo de mapa, como se describió anteriormente en este tutorial, y habilita las superposiciones de flujo de tráfico en vivo en las dos primeras líneas. setMyLocationEnabled
agrega un botón a la esquina superior derecha de MapFragment
que mueve automáticamente la cámara a la ubicación de tu usuario cuando se presiona.
Finalmente, al llamar a setZoomControlsEnabled
se agregan los botones + y - en la esquina inferior derecha, lo que permite al usuario cambiar el nivel de zoom del mapa sin tener que usar gestos. Hay algunas cosas más interesantes que puedes configurar con UiSettings
, como agregar una brújula o deshabilitar los gestos, que puedes encontrar en la documentación de referencia de Android.
4. Marcando ubicaciones
Una de las funciones de mapa más utilizadas implica indicar ubicaciones con marcadores. Como se necesita una latitud y una longitud para agregar un marcador, debes usar OnMapClickListener
para permitir que el usuario elija un punto en el mapa para colocar un objeto Marker
.
1 |
@Override
|
2 |
public void onMapClick(LatLng latLng) { |
3 |
|
4 |
MarkerOptions options = new MarkerOptions().position( latLng ); |
5 |
options.title( getAddressFromLatLng( latLng ) ); |
6 |
|
7 |
options.icon( BitmapDescriptorFactory.defaultMarker() ); |
8 |
getMap().addMarker( options ); |
9 |
}
|
Este método crea un marcador rojo genérico donde el usuario ha tocado. Se pueden establecer opciones adicionales, como establecer un marcador como arrastrable, a través del objeto MarkerOptions
. Puedes encontrar atributos adicionales en la documentación oficial de referencia de Android. Si deseas cambiar el color del marcador, puedes llamar a BitmapDescriptorFactory.defaultMarker
al agregar un icono a MarkerOptions
. El método defaultMarker
acepta un valor flotante que define el tono. El matiz se puede establecer manualmente o como un valor estático predefinido de BitmapDescriptorFactory
. Cabe señalar que addMarker
devuelve un objeto Marker
, que se puede almacenar para eliminar marcadores específicos manualmente si es necesario.



Si deseas evitar el uso de los pines de colores genéricos para tus marcadores de ubicación, puedes establecer un mapa de bits como el icono en el objeto MarkerOptions
. Para demostrar esto, reemplaza el método onMapLongClick
para que uses el ícono de la aplicación de la carpeta de recursos como Marker
cuando tu usuario presione el mapa durante mucho tiempo.
1 |
@Override
|
2 |
public void onMapLongClick(LatLng latLng) { |
3 |
MarkerOptions options = new MarkerOptions().position( latLng ); |
4 |
options.title( getAddressFromLatLng( latLng ) ); |
5 |
|
6 |
options.icon( BitmapDescriptorFactory.fromBitmap( |
7 |
BitmapFactory.decodeResource( getResources(), |
8 |
R.mipmap.ic_launcher ) ) ); |
9 |
|
10 |
getMap().addMarker( options ); |
11 |
}
|
Probablemente hayas notado que el método getAddressFromLatLng
se está utilizando en ambos métodos clic. Este es un método de ayuda que toma un LatLng
y lo ejecuta a través de un Geocoder
para obtener una dirección de calle. En los dos últimos ejemplos, estamos usando este método para mostrar una dirección de calle cuando se toca un marcador.
1 |
private String getAddressFromLatLng( LatLng latLng ) { |
2 |
Geocoder geocoder = new Geocoder( getActivity() ); |
3 |
|
4 |
String address = ""; |
5 |
try { |
6 |
address = geocoder |
7 |
.getFromLocation( latLng.latitude, latLng.longitude, 1 ) |
8 |
.get( 0 ).getAddressLine( 0 ); |
9 |
} catch (IOException e ) { |
10 |
}
|
11 |
|
12 |
return address; |
13 |
}
|
14 |
|
15 |
@Override
|
16 |
public boolean onMarkerClick(Marker marker) { |
17 |
marker.showInfoWindow(); |
18 |
return true; |
19 |
}
|



5. Dibujar en el mapa
El objeto GoogleMap
tiene un conjunto de métodos que hacen que sea más fácil dibujar formas y colocar imágenes en el mapa. Para dibujar un círculo simple, solo necesitas crear un objeto CircleOptions
, establecer un radio y una ubicación central, y definir los colores y el tamaño de trazo/relleno.
Una vez que tengas un objeto CircleOptions
, puedes llamar a addCircle
para dibujar el círculo definido en la parte superior del mapa. Al igual que cuando se colocan marcadores, los objetos que se dibujan en el mapa devuelven un objeto del tipo de elemento dibujado para que pueda ser referenciado más adelante si es necesario.
1 |
private void drawCircle( LatLng location ) { |
2 |
CircleOptions options = new CircleOptions(); |
3 |
options.center( location ); |
4 |
//Radius in meters
|
5 |
options.radius( 10 ); |
6 |
options.fillColor( getResources() |
7 |
.getColor( R.color.fill_color ) ); |
8 |
options.strokeColor( getResources() |
9 |
.getColor( R.color.stroke_color ) ); |
10 |
options.strokeWidth( 10 ); |
11 |
getMap().addCircle(options); |
12 |
}
|



Para dibujar una forma cerrada distinta, puedes tomar múltiples puntos LatLng
y crear un objeto PolygonOptions
. Como puedes ver a continuación, los PolygonOptions
se crean de forma similar a CircleOptions
. En lugar de usar un método center
y radius
, usas add
con una lista de puntos. Puedes llamar a addPolygon
para dibujar la forma. Para este ejemplo, simplemente dibuja un triángulo en el mapa.
1 |
private void drawPolygon( LatLng startingLocation ) { |
2 |
LatLng point2 = new LatLng( startingLocation.latitude + .001, |
3 |
startingLocation.longitude ); |
4 |
LatLng point3 = new LatLng( startingLocation.latitude, |
5 |
startingLocation.longitude + .001 ); |
6 |
|
7 |
PolygonOptions options = new PolygonOptions(); |
8 |
options.add( startingLocation, point2, point3 ); |
9 |
|
10 |
options.fillColor( getResources() |
11 |
.getColor( R.color.fill_color ) ); |
12 |
options.strokeColor( getResources() |
13 |
.getColor( R.color.stroke_color ) ); |
14 |
options.strokeWidth( 10 ); |
15 |
|
16 |
getMap().addPolygon( options ); |
17 |
}
|



El último tipo de dibujo que aprenderás es agregar una imagen como una superposición en el mapa. Las superposiciones pueden ser útiles si tienes un mapa dibujado para un área que deseas mostrar sobre un tipo de mapa normal. Esto se puede lograr creando GroundOverlayOptions
con una ubicación establecida, ancho y alto, y la imagen que deseas usar como BitmapDescriptor
.
En el siguiente método, dibuja el icono del iniciador para la aplicación como una superposición en los mosaicos del mapa.
1 |
private void drawOverlay( LatLng location, int width, int height ) { |
2 |
GroundOverlayOptions options = new GroundOverlayOptions(); |
3 |
options.position( location, width, height ); |
4 |
|
5 |
options.image( BitmapDescriptorFactory |
6 |
.fromBitmap( BitmapFactory |
7 |
.decodeResource( getResources(), |
8 |
R.mipmap.ic_launcher ) ) ); |
9 |
getMap().addGroundOverlay( options ); |
10 |
}
|
Conclusión
En este tutorial, has aprendido a crear una API key y habilitar Google Maps para Android. También aprendiste sobre la clase MapFragment
y algunas de las características básicas que puedes activar para un mapa.
Aprendiste cómo colocar marcadores, recibir las interacciones con el mapa y dibujar en el mapa para mostrar información adicional.
En el siguiente tutorial de esta serie, aprenderás a superponer una View
sobre MapFragment
, cómo interactuar con mapas de nivel interior y cómo mostrar una vista de calle a tus usuarios.