Está en la página 1de 19

Curso de Iniciación a Android: Unidad 8

- Android práctico -

Uso de mapas v2 en aplicaciones de Android


La mayoría de los dispositivos Android permiten determinar su ubicación
geográfica actual a través de un módulo GPS (del inglés Global Positioning
System, que se traduce como Sistema de Posicionamiento Global). Android
dispone del paquete android.location, que proporciona la API para determinar
la posición actual geográfica.

En la teoría del curso se explica el uso de la API Google Maps v1. Como esta
versión dejará de estar activa a lo largo de 2013, el objeto de este documento
es describir el uso de la nueva API v2.

Por lo tanto, en este documento vamos utilizar mapas en aplicaciones de


Android haciendo uso de la API Android de Google Maps versión 2.0.

Esta nueva versión presenta muchas novedades interesantes, entre las que
cabe destacar:

• Integración con los Servicios de Google Play (Google Play Services) y la


Consola web de APIs.
• Para utilizar los mapas debemos usar una nueva clase Java específica
del tipo Fragment (MapFragment).
• Uso de mapas vectoriales, aumentando la velocidad de carga y una
mayor eficiencia en cuanto al ancho de banda necesario.
• Mejoras en el sistema de caché reduciendo en gran medida las
desgraciadamente “famosas” áreas en blanco que tardan en cargar.
• Disponibilidad de mapas en 3D, lo que permite mover el punto de vista
del usuario en perspectiva.

Preparación del Entorno de programación

Antes de empezar a utilizar el servicio de mapas de Google es necesario


comprobar que tenemos instalado el paquete correspondiente a las APIs de
Google. Este paquete se llama normalmente “Google APIs by Google, Android
API x, revisión y“.

Al instalar el SDK de Android en Eclipse deberías haber añadido ya este


paquete. Para comprobar que está correctamente instalado, haz clic en el
botón "Opens the Android SDK Manager" de Eclipse:

Debe aparecer el siguiente paquete como instalado ("Installed"):

-1-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Nota: el número de revisión puede ser mayor que 2.

Muy importante: en la versión 2 de la API de Google Maps es necesario instalar


también los paquetes “Google Play services” y ”Android Support Library” (ver
captura de pantalla anterior).

Nota: a la fecha de escritura de este texto, Google no permite probar las


aplicaciones que usan la API Maps v2 en el emulador de Eclipse. Por lo tanto,
debemos utilizar un dispositivo real e instalar y probar la aplicación en él.

Obtención de clave de uso de API Maps v2

Para poder utilizar la API de Google Maps v2 es necesario obtener previamente


una clave de uso (API Key) que estará asociada al certificado con el que
firmamos digitalmente las aplicaciones. En el apartado "Permisos y Seguridad"
de la Unidad 5 ya hemos hablado de estos certificados, necesarios para firmar
aplicaciones de Android.

Si cambiamos el certificado con el que firmamos nuestra aplicación, algo que


normalmente se hace como paso previo a la publicación de la aplicación en el
Android Market, tendremos que modificar también la clave de uso de la API.

Cuando compilamos una aplicación en Eclipse y la probamos, se aplica


automáticamente un certificado de depuración creado por defecto. Por lo tanto,
para poder depurar en un dispositivo Android aplicaciones que hagan uso de

-2-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Google Maps v2, hay que solicitar una clave asociada a este certificado de
depuración. Veamos cómo se pide.

Lo primero que debemos hacer es acceder con el navegador a esta página web
(es la Consola web de gestión de APIs de Google):

https://code.google.com/apis/console/

Es necesario disponer de un usuario de Google como, por ejemplo, del servicio


gMail. En esta ventana introduciremos los campos “Email” y “Password” y
hacemos clic en el botón “Sign in”.

A continuación, aparece esta página:

Debemos pulsar en el botón “Create project…”, después, aparecerá esta


página:

-3-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Después, debemos pulsar en la opción “Google Maps Android API v2”. A


continuación, aceptamos la licencia de uso de esta API:

Veremos que ya aparece activo el uso de esta API:

Finalmente, para obtener la clave de uso de esta API debemos hacer clic en la
opción “API Access” que aparece en el menú de la izquierda:

-4-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Después, pulsamos el botón de abajo “Create new Android key…” y aparecerá


la siguiente ventana superpuesta:

Para obtener la clave SHA1 que solicita la página, en primer lugar, hay que
localizar el fichero donde se almacena el certificado de depuración
"debug.keystore". Podemos conocer la ruta de este fichero accediendo a las
preferencias de Eclipse, sección "Android", apartado "Build":

-5-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

En esta ventana copiamos en el portapapeles la ruta que aparece en el campo


“Default Debug Keystore“. Observa que hemos borrado intencionalmente la
parte de la ruta que será distinta en tu ordenador.

Una vez conocemos la ruta del fichero debug.keystore, vamos a acceder a él


con la herramienta keytool.exe de Java para obtener el hash SHA1 del
certificado. Esto lo hacemos desde una ventana de línea de comandos en el
directorio C:\Program Files (x86)\Java\jre6\bin (o donde esté instalado
Java) mediante la orden:

C:\Program Files (x86)\Java\jre6\bin>keytool -list -alias


androiddebugkey -keystore "ruta_del_certificado\debug.keystore" -
storepass android -keypass android

Nota: es necesario usar la versión 6 de Java, pues en la 7 no funciona.

Si lo hacemos, veremos la siguiente ventana:

-6-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

A continuación, copiamos en el portapapeles el dato que aparece identificado


como “Huella digitales del certificado (SHA1)”.

Después, accedemos de nuevo a la Consola de APIs de Google para solicitar


una clave de utilización de la API de Google Maps v2 para poder depurar
aplicaciones. En esta Web tendremos que escribir la Huella digital SHA1 de
nuestro certificado y el nombre del paquete (en el Ejemplo 2 de esta Unidad
del curso usamos el nombre de paquete es.mentor.unidad8.eje2.mapas.v2)
de la aplicación para obtener la clave de uso de la API:

-7-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

En la siguiente imagen se muestra el resultado:

Nota: Observa que hemos borrado intencionalmente parte de la clave, pues,


cuando solicites ésta, te darán otra diferente.

Ya hemos terminado la preparación del entorno de programación en Eclipse


para poder utilizar los servicios de Google Maps v2 dentro de nuestras
aplicaciones Android.

Cómo incluir mapas en las aplicaciones Android

En el Ejemplo 2b de esta Unidad vamos a desarrollar una aplicación que


incluye un mapa sobre el que podemos hacer unas operaciones sencillas,
como cambiar a vista satélite o desplazar la posición del mapa.

IMPORTANTE

-8-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Para poder ver este proyecto en tu dispositivo Android es necesario que


obtengas la clave de uso de la API de Mapas de Google y la cambies en el
fichero de diseño AndroidManifest.xml del proyecto. Si no lo haces, arrancará
la aplicación del ejemplo pero no se mostrará el mapa, como en la imagen
siguiente:

Para incluir un mapa de Google Maps en una aplicación Android hay que
indicar la clave de uso de Google Maps v2 en el atributo android:value del
archivo AndroidManifest.xml del proyecto, tal y como se muestra a
continuación:

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:allowBackup="false">

<!-- Aquí se escribe la clave de uso de Google Maps -->


<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="clave_API"/>
...

Además, en el fichero AndroidManifest, también debemos incluir los permisos


necesarios para poder utilizar los mapas. En primer lugar, definimos el permiso
llamado “nombre_paquete.java.permission.MAPS_RECEIVE”, en el ejemplo 2
quedaría sí:

<permission
android:name="es.mentor.unidad8.eje2.mapas.v2.permission.MAPS_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission
android:name="es.mentor.unidad8.eje2.mapas.v2.permission.MAPS_RECEIVE"
/>

-9-
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Después, hay que añadir permisos adicionales que permiten a la aplicación


acceder a los servicios web de Google, a Internet y al almacenamiento externo
del dispositivo para guardar la caché de los mapas descargados:

<uses-permission
android:name="com.google.android.providers.gsf.permission.READ_GSERVIC
ES"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Por último, dado que la API v2 de Google Maps Android utiliza OpenGL ES
versión 2, debemos especificar también dicho requisito en el fichero
AndroidManifest añadiendo un nuevo elemento <uses-feature>:

<uses-feature android:glEsVersion="0x00020000"
android:required="true"/>

Una vez hemos configurado el archivo AndroidManifest, antes de escribir el


código fuente, ha que añadir otras librerías externas a nuestro proyecto.

La primera de ellas es la librería de Google Play Services que hemos


descargamos al principio de este texto e integrarla en el proyecto Android. Para
hacerlo, desde Eclipse hacemos clic en la opción de menú principal “File /
Import…” seleccionando la opción “Existing Android Code Into Workspace”:

- 10 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Podemos encontrar esta librería en la carpeta “<carpeta-sdk-


android>/extras/google/google_play_services/libproject/google-play-
services_lib“:

Pulsando en el botón “Aceptar” podemos ver que la librería se ha cargado


globalmente en Eclipse.

A continuación, vamos a importar esta librería en el proyecto del ejemplo del


curso. Con el botón derecho del ratón sobre la carpeta del proyecto, hacemos
clic en “Properties” y accedemos a la sección Android de las preferencias. En la
ventana que aparece podemos añadir una nueva librería en la sección inferior

- 11 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

llamada “Library” pulsando en el botón “Add…”, seleccionando la librería recién


importada y añadiéndola a la lista de librerías disponibles en el proyecto:

En el esquema del proyecto debemos ver la librería de Google Play importada:

Finalmente, si deseamos que la aplicación se pueda ejecutar desde versiones


anteriores de Android (concretamente en la versión de Android 2.3 del curso)
debemos asegurarnos de que el proyecto incluye la librería android-support-

- 12 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

v4.jar. Podemos encontrar esta librería en el directorio “<carpeta-sdk-


android>/extras/android/support/v4/android-support-v4.jar“. Debemos copiar
esta librería al directorio “/lib” de nuestro proyecto (puede ser necesario crear
esta carpeta dentro del proyecto).

A continuación, hay que refrescar con la tecla F5 el proyecto para que


aparezca la librería e importarla con la opción “Build Path > Add to Build Path”
del menú desplegable que aparece al hacer clic con el botón derecho del ratón
sobre dicha librería:

Nota: las versiones más recientes de ADT de Eclipse incluyen por defecto esta
librería en nuestros proyectos.

Estudio del código fuente del ejemplo

En la anterior versión 1 de la API, para incluir un mapa en la aplicación hay que


utilizar la clase Java MapView y su actividad contenedora debe ser del tipo
MapActivity. Con la nueva versión 2 de la API pasamos a tener una única
clase específica heredada de Fragment llamada MapFragment.

Esto nos permite, entre otras cosas, añadir uno o varios mapas a cualquier
actividad contando por supuesto con todas las ventajas del uso de la clase
Fragment.

Nota importante: como el nuevo control de mapas se basa en la clase


Fragment, para mantener la compatibilidad con versiones de Android anteriores
a la 3.0 hay que utilizar la librería de soporte android-support (ver nota
anterior).

- 13 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Fragments es una nueva funcionalidad del SDK de Android que facilita el


desarrollo de las interfaces de las aplicaciones tanto en tabletas cómo en
teléfonos.

Los Fragments son trozos de una Activity, podemos hacer una similitud con
los “paneles” en la programación visual. Además, pueden ejecutar código y son
reutilizables. Es decir, podemos utilizar un Fragment en distintos sitios de una
misma aplicación.

Son útiles en las tabletas y los teléfonos porque los Fragments permiten, por
ejemplo, en el caso de que tengamos una tableta mostrar una Activity con 2
fragments (como una lista de datos y el detalle del dato seleccionado al lado).
Por otra parte, en el caso de un teléfono podemos mostrar 2 Activities
separadas cada una con su propio Fragment (una pantalla tiene la lista y
haciendo clic en un registro se abre otra pantalla con el detalle). Veamos el
esquema de las interfaces de usuario a continuación:

Esto facilita la programación de la aplicación al permitir definir fragmentos de


información que se pueden colocar en la interfaz de usuario casi si modificar
código y reutilizando los distintos paneles en función del terminal Android.

Además, el uso de la antigua versión 1 de la API de Google Maps era más


complicado, la nueva versión simplifica el trabajo al programador. Por ejemplo,
la consulta de la posición actual o la configuración del tipo de mapa se hacían
directamente usando la clase MapView, mientras que la manipulación de la
posición y el zoom se hacían a través del controlador asociado al mapa
MapController. Además, el tratamiento de las coordenadas y unidades
utilizadas eran algo peculiares, teniendo estar continuamente convirtiendo de
grados a microgrados y éstos a objetos GeoPoint.

Con la nueva API, todas estas operaciones se realizan directamente sobre la


clase base GoogleMap. Para obtener la referencia a este objeto, debemos usar
el método getMap() del fragmento MapFragment que contenga nuestro mapa.

En el Ejemplo 2 la Actividad principal hereda la clase FragmentActivity, tal y


como vemos en el siguiente código:

public class MapasActivity extends android.support.v4.app.FragmentActivity {


// Variables donde se definen los controles de la Actividad
private GoogleMap mapa = null;
private Button sateliteBtn = null;
private Button irBtn = null;
private Button animarBtn = null;
private Button posicionBtn = null;
private CameraUpdate controlMapa = null;

- 14 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Obtenemos una referencia a las Vistas de la Actividad
// Obtenemos la referencia al mapa
// En Android 3.0 a superior podemos usar el método
// getFragmentManager()en lugar de getSupportFragmentManager
// y SupportMapFragment en lugar de MapFragment.
mapa = ((SupportMapFragment)getSupportFragmentManager().
findFragmentById(R.id.mapa)).getMap();

// Botones de la aplicación
sateliteBtn = (Button)findViewById(R.id.SateliteBtn);
irBtn = (Button)findViewById(R.id.IrBtn);
animarBtn = (Button)findViewById(R.id.AnimarBtn);
posicionBtn = (Button)findViewById(R.id.PosicionBtn);

// Definimos el Controlador del mapa: movemos el mapa a una posición y hacemos


// zoom a 5 (puede tomar el valor de 1 a 21)
controlMapa = CameraUpdateFactory.newLatLngZoom(new LatLng(40.41, -3.69), 5F);
// Modemos el mapa
mapa.moveCamera(controlMapa);

// Definimos el evento onClick del botón Satélite


sateliteBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// Intercambiamos la capa de tipo satélite en el mapa
if(mapa.getMapType()==GoogleMap.MAP_TYPE_SATELLITE) {
mapa.setMapType(GoogleMap.MAP_TYPE_NORMAL);
// Cambiamos el texto del botón
sateliteBtn.setText("Satélite");
// Seleccionamos la imagen que muestra el botón
sateliteBtn.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.tierra, 0, 0);
} else {
mapa.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
sateliteBtn.setText("Normal");
sateliteBtn.setCompoundDrawablesWithIntrinsicBounds(0,
R.drawable.mapa, 0, 0);
}
}
});

// Definimos el evento onClick del botón Ir a...


irBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// Definimos un nuevo punto de localización
LatLng loc = new LatLng(40.654754, -4.690958);
// Creamos una posición nueva de cámara
CameraPosition camPos = new CameraPosition.Builder()
.target(loc) // Centramos el mapa en la localización
.zoom(12) // Establecemos el zoom en 12
.bearing(45) // Establecemos orientación con el noreste arriba (45º)
.tilt(0) // No modificamos el punto de vista de la cámara
.build(); // Establecemos el nuevo punto de vista de la cámara
controlMapa = CameraUpdateFactory.newCameraPosition(camPos);
// Movemos la cámara a la nueva posición en el mapa
mapa.moveCamera(controlMapa);
}
});

- 15 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

// Definimos el evento onClick del botón Animar


animarBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// Definimos un nuevo punto de localización
LatLng loc = new LatLng(40.93779, -4.1167040);
// Creamos una posición nueva de cámara
CameraPosition camPos = new CameraPosition.Builder()
.target(loc) // Centramos el mapa en la localización
.zoom(12) // Establecemos el zoom en 12
.bearing(0) // Establecemos la orientación con el norte arriba (0º)
.tilt(0) // No modificamos el punto de vista de la cámara
.build(); // Establecemos el nuevo punto de vista de la cámara
controlMapa = CameraUpdateFactory.newCameraPosition(camPos);
// Animamos el movimiento de la cámara en el mapa
mapa.animateCamera(controlMapa);
}
});

// Definimos el evento onClick del botón Posición Actual


posicionBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// Obtenemos la posición actual de la cámara en el mapa
CameraPosition camPos = mapa.getCameraPosition();
// Obtenemos la latitud y longitud de la cámara en el mapa
LatLng pos = camPos.target;
// Mostramos un mensaje al usuario
Toast.makeText(MapasActivity.this,
"Posición actual - Lat: " + pos.latitude + " - Lng: " + pos.longitude,
Toast.LENGTH_LONG).show();
}
});
} // end clase Actividad

A continuación, vamos a explicar las partes importantes del código anterior.

En el método onCreate() de la Actividad se invoca el método


getSupportFragmentManager() para obtener la referencia al componente
GoogleMap.

Como todas las operaciones se realizan directamente sobre el objeto GoogleMap,


componente base de la API, debemos acceder a este componente invocando
al método getMap() del fragmento MapFragment que contenga nuestro mapa.

Por defecto, cuando usamos un GoogleMap en una aplicación, se muestra en el


modo de mapa tradicional (callejero). Sin embargo, este componente también
permite cambiar las capas a la vista satélite o ver fotos de la calle con
StreetView. Para ello, utilizar el método setMapType() indicando como parámetro
el tipo de mapa:

• MAP_TYPE_NORMAL
• MAP_TYPE_HYBRID
• MAP_TYPE_SATELLITE
• MAP_TYPE_TERRAIN

- 16 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

En el evento onClick del botón sateliteBtn hemos usado el método


setMapType() para intercambiar el modo satélite y el estándar.

Esta nueva versión de la API da más libertad que la anterior versión a la hora
de cambiar el centro del mapa, ya que podemos mover libremente el punto de
vista (o Cámara, como lo denomina Android) por un espacio en 3 dimensiones
(3D). Por lo tanto, ya no sólo debemos hablar de latitud-longitud (target) y zoom,
sino también de orientación (bearing) y ángulo de visión (tilt). La manipulación
de estos 2 últimos parámetros permite visualizar edificios en 3D de muchas
ciudades.

El movimiento de la cámara se realiza siempre mediante la construcción de un


objeto de la clase CameraUpdate o de sus clases heredadas con los parámetros
necesarios.

Para movimientos básicos como la actualización de la latitud y longitud o el


nivel de zoom podemos utilizar la clase CameraUpdateFactory y sus métodos
estáticos. Por ejemplo, usamos esta clase en el método onCreate() de la
actividad para posicionar el mapa y hacer zoom a 5.

El nivel de zoom del mapa contiene un valor entero entre 1 y 21, siendo 21 el
que ofrece mayor nivel de detalle en el mapa.

Además, esta clase dispone, entre otros, de los siguientes métodos:

• CameraUpdateFactory.zoomIn(): aumenta en 1 el nivel de zoom.


• CameraUpdateFactory.zoomOut(): disminuye en 1 el nivel de zoom.
• CameraUpdateFactory.zoomTo(nivel_de_zoom): establece el nivel de zoom.
• CameraUpdateFactory.newLatLng(lat, long): establece la lat-lng
expresadas en grados.
• CameraUpdateFactory.newLatLngZoom(lat, long, zoom): establece la lat-lng
y el zoom respectivamente.
• CameraUpdateFactory.scrollBy(scrollHorizontal, scrollVertical): mueve
la cámara lateralmente por el mapa (panning).

Una vez hemos creado el objeto CameraUpdateFactory con los parámetros de


posición que deseamos establecer en el mapa hay que invocar uno de los
métodos moveCamera() o animateCamera() del objeto GoogleMap, si queremos que
la actualización de la vista se muestre directamente o de forma animada
respectivamente.

Aparte de los movimientos básicos que hemos estudiado anteriormente, es


posible modificar los demás parámetros de la cámara o varios de ellos
simultáneamente mediante el método general
CameraUpdateFactory.newCameraPosition() que recibe como parámetro un objeto
de tipo CameraPosition. Este objeto los construimos indicando todos los
parámetros de la posición de la cámara a través de su método Builder().

- 17 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

En este ejemplo hemos incluido un botón irBtn que centra el mapa sobre un
punto determinado, aplica un nivel de zoom (12), establece la orientación con el
noreste arriba (45º) y no modifica el punto de vista de la cámara. Si pruebas el
ejemplo del curso, verás que el desplazamiento a la posición y el zoom al nivel
indicados se hacen de forma instantánea sin ningún tipo de animación
mediante el uso del método moveCamera().

En el botón animarBtn hemos usado es método animateCamera() para animar el


movimiento del mapa.

Finalmente, si el usuario se mueve de forma manual por el mapa, es posible


conocer la posición actual de la cámara mediante el método
getCameraPosition() del mapa que devuelve un objeto del tipo CameraPosition.
Usando sus diferentes métodos y propiedades podemos conocer con exactitud
la posición de la cámara, su orientación y el nivel de zoom.

En el botón posicionBtn hemos usado es método getCameraPosition() para


mostrar la posición actual en el mapa.

Desde Eclipse puedes abrir el proyecto Ejemplo 2b (Mapas) de la Unidad 8.


Estudia el código fuente y ejecútalo para mostrar en el AVD el resultado del
programa anterior, en el que hemos utilizado un mapa.

Si ejecutas la aplicación en el emulador de Android, verás que tiene el siguiente


aspecto:

- 18 -
Curso de Iniciación a Android: Unidad 8
- Android práctico -

Atención: si intentas ejecutar este ejemplo en el emulador del curso verás en la


Vista Logcat de Eclipse los siguientes errores:

A la fecha de redacción de este documento, no es posible ejecutar aplicaciones


que requieran la utilización de Google Play.

Otro error que puede aparecer es el siguiente. Si al cargar el proyecto del


ejemplo 2 aparece el error “CameraPosition cannot be resolved to a type”:

Debemos importar de nuevo la librería de Google Play en Eclipse y en el


proyecto.

- 19 -

También podría gustarte