viernes, 30 de mayo de 2014

Plugin geolocalización

Este plugin de Cordova/Phonegap nos provee información útil sobre la localización física del dispositivo, por ejemplo, la latitud (1) o la longitud (2).
fuente: wikipedia.org

Este plugin funciona nutriéndose de información que le es suministrada tanto por el GPS del dispositivo, como por señales de red(Wifi, bluetooth, RFID, direcciónes IP y las IDs de GSM/CDMA.

Debemos saber que con el uso de este plugin podrían surgir problemas de privacidad, ya que el almacenamiento de esta información sensible de forma periódica podría revelar costumbres y hábitos de los usuarios. Por lo tanto, en la política de privacidad de nuestras aplicaciones, debemos dejar claro y explicar qué uso damos a los datos obtenidos por nuestras apps.

Soporte

Las plataformas que soportan este plugin son numerosas, y entre ellas encontramos las más importantes:

  • Amazon Fire OS
  • Android
  • BlackBerry 10
  • Firefox OS
  • iOS
  • Tizen
  • Windows Phone 7 and 8
  • Windows 8


Instalación

Para poder instalar en nuestro proyecto el plugin geolocation, debemos situarnos en la carpeta de la aplicación y teclear por consola:
phonegap plugin add org.apache.cordova.geolocation

Componentes

Al trabajar con este plugin, contamos con tres métodos para acceder a la información que nos interesa:

  • navigator.geolocation.getCurrentPosition
Uso: navigator.geolocation.getCurrentPosition(geolocationSuccess, [geolocationError], [geolocationOptions]);

Devuelve la posición actual a la función geolocationSuccess por un objeto Position pasado como parámetro. Opcionalmente podemos incluir dos parámetros más. Uno es la función callback que será llamada si sucede algún error(con un objeto PositionError como parámetro, en este caso), y un objeto que representa las opciones. Veremos qué opciones podemos pasarle más adelante.


  • navigator.geolocation.watchPosition
Uso: var watchId = navigator.geolocation.watchPosition(geolocationSuccess, [geolocationError], [geolocationOptions]);

Devuelve la posición del dispositivo cuando hay un cambio en ésta, como sucedía con el acelerómetro, usamos una variable para referenciar el intervalo. Puede incluirse una función callback de error por si algo no va bien, y el objeto con las opciones que hemos llamado geolocationOptions.


  • navigator.geolocation.clearWatch
Su uso es el siguiente: navigator.geolocation.clearWatch(watchID);
Detiene la espera de cambios en la posición del dispositivo, es decir, su refresco de datos que referencia el parámetro watchID, en este caso.


El objeto geolocationOptions

Podemos incluir este objeto en nuestras llamadas a los métodos del plugin, que contiene las opciones con las que se hará la llamada. Un ejemplo válido podría ser: { maximumAge: 3000, timeout: 5000, enableHighAccuracy: true };

¿Qué opciones podemos incluir?
  • enableHighAccuracy: valor booleano con el que establecemos una mayor precisión en la obtención de datos. En el ejemplo anterior estaríamos solicitando, además de las redes inalámbricas, el gps como fuente de datos.
  • maximumAge: Valor numérico que expresa el mayor tiempo en milisegundos que tendrá un valor cacheado, obtenido tiempo atrás, para que lo tenga en cuenta la aplicación. En el ejemplo anterior desechamos todo muestreo de datos con una antigüedad mayor a tres segundos.
  • timeout: Si en el tiempo especificado, expresado en milisegundos, no se ha llamado a la función geolocationSuccess de los métodos getCurrentPosition o watchPosition, pasará a llamarse a la función geolocationError(o como hubiésemos llamado a las funciones en nuestro programa).

El objeto Position

Es un objeto de sólo lectura que tiene como propiedades coords y timestamp. La propiedad coords devuelve a su vez un objeto, el objeto Coordinates(coordenadas). El objeto Coordinates tiene varias propiedades que son la información definitiva que normalmente vamos a solicitar con el uso de la geolocalización, tales como la latitud, o la altura.

Estas son las propiedades de Coordinates(todas son de tipo numérico):
  • latitude: Latitud en grados decimales.
  • longitude: Igual, pero con la longitud.
  • altitude: Expresa la altura.
  • accuracy: Nivel que expresa los metros de exactitud con los que se dan los valores de latitud y longitud.
  • altitudeAccuracy: Lo mismo pero con la altura.
  • heading: Dirección del viaje, expresado en grados en sentido de las agujas del reloj y tomando como 0 el norte real.
  • speed: Velocidad actual del dispositivo, expresada en metros por segundo.

El objeto PositionError

Disponemos del objeto PositionError para especificar las causas que provocaron un error al acceder a la geolocalización del terminal. cuenta con dos propiedades:
  • message: un mensaje en el que se describen los detalles del error encontrado.
  • code: puede ser uno de los códigos de error listados a continuación.
Constantes de PositionError
  • PositionError.PERMISSION_DENIED: es devuelto cuando el usuario no ha dado permiso para recolectar datos de posicionamiento.
  • PositionError.POSITION_UNAVAILABLE: es devuelto cuando el dispositivo no puede encontrar la posición. Suele ocurrir cuando no estamos conectados a una red, o no se encuentra el satélite.
  • PositionError.TIMEOUT: devuelto cuando el dispositivo no puede encontrar su posición en el tiempo que especificamos en las opciones de la llamada a los métodos anteriormente descritos que sirven para obtener la posición(getCurrentPosition o watchPosition).

Ejemplo práctico

Una vez vista la teoría, pasemos a ver cómo se usa este plugin a nivel práctico. Para ello, he preparado un ejemplo sencillo partiendo del esqueleto preparado en apartados anteriores.

Personalizamos un poco el config.xml...

Vamos a mostrar en pantalla de forma constante datos de posicionamiento, o el error que se produjera en caso de no poder acceder a éstos.

El html de la aplicación quedaría así(más bien la etiqueta body):
<body>
        <div class="container">
            <h1 class="text-center">Geolocalización</h1>
            <div id="longitud"></div>
            <div id="latitud"></div>
            <div id="mensaje"></div>
            <div id="error"></div>
        </div>
        
        <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
        <script type="text/javascript" src="./js/jquery-1.11.0.min.js"></script>
        <script type="text/javascript" src="./js/bootstrap.min.js"></script>
        <script type="text/javascript" src="./js/fastclick.js"></script>
        <script type="text/javascript" src="./js/index.js"></script>
        <script type="text/javascript">
            window.addEventListener('load', function() {
                new FastClick(document.body);
            }, false);
            app.initialize();
        </script>
    </body>

No tiene mucho misterio, dejamos 4 divs listos para que se rellenen mediante javascript. El fichero index.js es el que se adjunta a continuación:
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        // función callback onSuccess
// este método recibe el objeto Position, que contiene los datos que nos interesan
function onSuccess(position) {
            longitud.html("Longitud: " + position.coords.longitude);
            latitud.html("Latitud: " + position.coords.latitude);
            divError.html("No hay errores");
            //damos información de latitud en palabras
            if(position.coords.latitude >= 0){
                mensaje.html("Latitud norte");
            }else{
                mensaje.html("Latitud sur");
            }
}

//La función callback onError recibe el objeto PositionError
function onError(error) {
            longitud.html("ERROR");
            latitud.html("ERROR");
            divError.html(error.code);
            mensaje.html("Mensaje: " + error.message);
}

        //guardamos los elementos DOM en variables
        var longitud = $("#longitud");
        var latitud = $("#latitud");
        var mensaje = $("#mensaje");
        var divError = $("#error");
        //referenciamos watchID para almacenar los datos cada 3 segundos
        //Si cada 3 segundos no recibimos una actualización de la posición, se lanzará un error
var watchID = navigator.geolocation.watchPosition(onSuccess, onError, { timeout: 3000, enableHighAccuracy: true });
    }
};

Despues de obtener el evento deviceready, procedemos con el funcionamiento de la aplicación. Rellenamos los div del html con los datos que nos proporciona el objeto Position, o PositionError, según se llame a onSuccess o a onError, en la penúltima línea del código. Podemos fijarnos que hemos incluído la opción timeout con valor de 3000. Si pasan tres segundos sin datos, por ejemplo por tener desactivado el gps y las redes, el error, que debe informarnos sobre la imposibilidad de acceder al sistema de posicionamiento, debe cambiar al error que lanza la opción timeout.

Todo este código está muy bonito, pero no serviría de nada si no instalamos el plugin antes de compilar.

Finalmente adjunto imágenes de la app ejecutándose en un terminal Android:

Sin acceso a ubicación:
 Error de código 2 (recordemos, POSITION_UNAVAILABLE):


Pasan 3 segundos sin datos, así que el error cambia a código 3 (TIMEOUT):


Activamos la localización:

Ahora todo va como esperábamos:

2 comentarios:

  1. Hola Rafael! muy buena la entrada!, me preguntaba si podrias pasarme el codigo fuente, ya que intento hacer funcionar tu codigo pero no lo consigo y estoy realmente interesado en poder usarlo. Gracias.
    Saludos.
    Jesús.

    ResponderEliminar
    Respuestas
    1. Hola !! Disculpa el retraso, tardé en dar con el disco duro (externo) que contenía el código fuente de los ejemplos jeje. Aquí lo tienes: https://www.dropbox.com/s/8vuxl9x2womipib/geolocv2.zip?dl=0

      Eliminar