jueves, 22 de mayo de 2014

Eventos Phonegap


Con javascript podemos capturar eventos en nuestras aplicaciones web, de forma que, por ejemplo, al hacer "click" en algún elemento nuestra aplicación lo detecte y reaccione de la forma que nos interese.

Con Phonegap podemos hacer uso de algunos eventos predeterminados pensados para tener lugar en aplicaciones móviles. Por ejemplo, en lugar de tener listener de eventos tales como hover con el ratón(entrar con el mouse en algún elemento), nos puede interesar que la aplicación reaccione al pulsar teclas de los terminales móviles, como las teclas de volumen, o las teclas de retroceso u opciones, o simplemente cuando nos quede poca batería mientras usamos la aplicación. Estos son los eventos comunes:
  • deviceready (este es el más importante, se lanza cuando Phonegap/Cordova se haya cargado por completo)
  • pause
  • resume
  • backbutton
  • menubutton
  • searchbutton
  • startcallbutton
  • endcallbutton
  • volumedownbutton
  • volumeupbutton
Los siguientes,
  • batterycritical
  • batterylow
  • batterystatus
han sido añadidos por org.apache.cordova.battery-status, y los eventos online y offline han sido creados por org.apache.cordova.network-information.

Compatibilidad

No todos los eventos son compatibles con todas las plataformas. Para verlos todos y comprobar compatibilidades podemos mirar este enlace. Es importante comprobarlo porque en mi caso, por ejemplo, intenté implementar el evento volumeupbutton en Android y al no reaccionar, pude comprobar tiempo después(tiempo de desesperación y frustración informática) que sólo es compatible con BlackBerry.

Este punto puede ser crucial a la hora de decantarnos por la programación con Phonegap/Cordova o programación nativa para cada sistema, para nuestras aplicaciones móviles. Como casi siempre, depende del uso de la aplicación, y la importancia que le demos a las funciones que pueden no estar soportadas.

Por ejemplo, puede no ser muy importante el uso de la tecla de volumen, por lo que podríamos añadir esa funcionalidad como algo extra en nuestra aplicación. En BlackBerry, que soporta este evento, éste sería capturado, y la aplicación reaccionaría de la forma que programemos. Por contra en Android, que no soporta este evento, al pulsar las teclas de volumen subiríamos o bajaríamos el volumen del terminal, siendo ignorado el evento que pretendemos capturar. En este caso podríamos considerar las otras opciones positivas que nos proporciona Phonegap y usarlo para hacer nuestro proyecto, dada la baja importancia que hemos decidido darle al hecho de pulsar las teclas de volumen. Sin embargo, si el uso de las teclas de volumen es muy importante, la cosa cambia. Imaginemos que nuestro proyecto es un videojuego, y que las teclas de volumen son cruciales para el manejo del mismo. En este caso es más conveniente recurrir a la programación nativa de cada sistema operativo, puesto que con Phonegap este problema de compatibilidad no nos permitiría acceder a los eventos que queremos en todos los dispositivos.

Ejercicio

A continuación implementaré un ejercicio en el que nuestra aplicación reacciona ante algunos de los eventos anteriores.

Para el siguiente ejemplo voy a tomar como base la aplicación llamada intenciones del capítulo anterior. En ella, recordemos, se puede cambiar de la vista principal a otra de opciones pulsando botones dibujados en pantalla. Esto es lo más común que vamos a tener en cualquier aplicación, pero deseamos que desde la vista principal se pueda acceder también a la de opciones pulsando la tecla de opciones de Android, y que desde la pantalla de opciones, al pulsar la tecla de retroceso(la flecha pequeña) volvamos a la principal.

Partimos, por tanto, del código fuente que ya teníamos, así que copiamos el ejemplo anterior, y si lo deseamos modificamos su nombre e id desde el config.xml.

Consideraciones importantes

Hay que prestar atención a algunos detalles antes de analizar el código, y en general los códigos a partir de este ejemplo. Dado que hasta ahora hemos realizado aplicaciones web normales, no teníamos más añadir el código necesario para que al probarlo en nuestro navegador web de escritorio el resultado fuera satisfactorio. Pero ahora entran en juego elementos exclusivos de los terminales móviles, como algunos eventos exclusivos para estos dispositivos, y posteriormente plugins para acceder al hardware de los móviles, por lo que hay que añadir algunas líneas de código y tener claras algunas cosas.

Es necesario añadir la siguiente línea en el código html:
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
De hecho, viene por defecto al crear un proyecto nuevo Phonegap o Cordova. La había ignorado hasta ahora, e incluso eliminado, porque esa línea, al ejecutar los ficheros html en el navegador de escritorio sólo lanzaba un error por consola(la del navegador), porque no encontraba el fichero cordova.js. Sin embargo, al probar este ejemplo, me he dado cuenta de que sin esa línea, la aplicación móvil no funciona.

La explicación es la siguiente. El fichero no se encuentra en el www de nuestro proyecto, a pesar de que en el html, en la declaración del script, podemos pensar que está ahí. Donde realmente busca el fichero, es el la carpeta platform_www que se encontrará en las plataformas que tengamos agregadas a nuestro proyecto. Si no tenemos plataformas agregadas, no lo encontraremos. Como partimos del proyecto esqueleto que creamos en capítulos anteriores, tenemos añadida la plataforma Android(recordemos, para poder compilar en local sin tener que recurrir a Phonegap Build). Si entramos en platforms/android/plaform_www, efectivamente, veremos el fichero cordova.js ubicado ahí. En tiempo de compilación, el framework hace uso de los ficheros situados tanto en el www del proyecto como en el platform_www de cada plataforma añadida en platforms.




Por lo tanto, si eliminamos esa línea, nuestra aplicación funcionará como una aplicación web sin más, sin las posibilidades que ofrecen Phonegap/Cordova de acceso a eventos o hardware móvil.Es el archivo cordova.js, el que proporciona los enlaces a la API.

Otra cosa a tener en cuenta, si vamos a trabajar con eventos de Phonegap, y más adelante con las API que nos proporcionan los plugins Phonegap, es tratar de lanzar el evento "deviceready" antes que nada, y a partir de ahí, cargar el resto de código javascript, incluyendo los listeners para los demás eventos.

Con esas consideraciones presentes, he modificado ligeramente el código html y javascript, que quedan de la siguiente manera.

/////////////////////////////////////////////////index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="format-detection" content="telephone=no" />
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="css/index.css" />
    <title>Proyecto Phonegap</title>

    <script type="text/javascript" src="./js/jquery-1.11.0.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="cordova.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);
    </script>
</head>
<body onload="onLoad()">
    <div id="vistaOpciones" class="oculto container-fluid">
        <div class="">
            <h2>Opciones</h2>
            <p>Color de texto</p>
            <button id="botonRojo" class="btn btn-danger">
                Rojo
            </button>
            <button id="botonAzul" class="btn btn-primary">
                Azul
            </button>
            <br><br>
            <button id="botonPrincipal" class="btn btn-default">
                Volver
            </button>
        </div>
    </div>

    <div id="vistaPrincipal" class="visible container-fluid">
        <div class="">
            <h2>Vista principal</h2>
            <p>Pulsa para cargar la vista de las opciones, al volver se recordará la opción elegida</p>
            <button id="botonMenu" class="btn btn-default">
                OPCIONES
            </button>
        </div>
    </div>
</body>
</html>

Nos fijamos que hemos subido todos los scripts al header, esto no tiene mayor importancia, pero sí el hecho de haber añadido la línea <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
de la que ya he hablado antes.

También hemos añadido código al <body>, que una vez cargado, llamará a la función onLoad() del index.js.

Echemos ahora un vistazo al index.js:


//////////////////////////////////////////////////////index.js

function onLoad() {
    $(document).bind( "deviceready", function( event ) {
        onDeviceReady();
    });
}

function onDeviceReady() {
    // Register the event listener
    $(document).bind({
        backbutton: function(){
            if(!($('#vistaOpciones').hasClass("visible"))){
                alert("Has pulsado la tecla atras, pero no estás en el menú");
            }else{
                hacerVisible(vistaPrincipal);
                hacerOculto(vistaOpciones);
            } 
        },
        menubutton: function(){
            hacerVisible(vistaOpciones);
            hacerOculto(vistaPrincipal);
        },
        volumedownbutton: function() {
            alert("down");
        },
        volumeupbutton: function() {
            alert("up");
        }
    });

    var vistaPrincipal = $('#vistaPrincipal');
    var vistaOpciones = $('#vistaOpciones');
    var botonMenu = $('#botonMenu');
    var botonPrincipal = $('#botonPrincipal');
    var botonAzul = $('#botonAzul');
    var botonRojo = $('#botonRojo');
    function hacerVisible(elemento){
        elemento.addClass("visible");
        elemento.removeClass("oculto");
    }
    function hacerOculto(elemento){
        elemento.addClass("oculto");
        elemento.removeClass("visible");
    }
    botonMenu.click(function(){
        hacerVisible(vistaOpciones);
        hacerOculto(vistaPrincipal);
    });
    botonPrincipal.click(function(){
        hacerVisible(vistaPrincipal);
        hacerOculto(vistaOpciones);
    });
    botonRojo.click(function(){
        $('p').addClass("fondoRojo");
        $('p').removeClass("fondoAzul");
    });
    botonAzul.click(function(){
        $('p').removeClass("fondoRojo");
        $('p').addClass("fondoAzul");
    });

}

Nada más ejecutarse el onLoad(), añadimos un event listener al documento, de forma que cuando se produzca el evento deviceready, lanzaremos lo que sea, en este caso la función onDeviceReady, y ya en ella escribimos el resto del código. Pero al hacerlo así, nos aseguramos de que lo que se ejecute desde ese punto, lo hace tras el evento deviceready, lo que nos garantiza que Phonegap se ha cargado por completo.

Podríamos decir que deviceready es el evento más importante, y una vez suceda éste, podremos implementar el resto de eventos.

Como vemos, lo he hecho con bind, gracias a jquery. Podríamos usar document.addEventListener("deviceready", miFuncion, false);
Pero he optado por aprovechar la sintaxis que me brinda jquery.

Cuando se ejecuta la función onDeviceReady(), vemos que tenemos el mismo código que ya teníamos en el ejemplo del capítulo anterior, pero hemos añadido listeners para los eventos backbutton, menubutton, volumedownbutton y volumeupbutton. Si se pulsa el botón de menú, la aplicación reacciona ocultando la capa principal y haciendo visible la capa de opciones(hacerVisible() y hacerOculto() ). Si se pulsa alguna tecla de volumen, y como ya he comentado antes estamos en BlackBerry, la aplicación nos muestra un alert. Si pulsamos la tecla de retroceso, comprobamos si tenemos la capa de opciones visible, preguntando si tiene la clase CSS visible. Si no lo tiene, significa que estamos en la pantalla principal, y lanzo un alert avisando de que no se hará nada. Si esa capa está visible, la tecla retroceso hace que volvamos a la pantalla principal. Podemos comprobar que los botones de las opciones y en general el resto de funcionalidades de la aplicación sigue funcionando.



De este modo hemos visto algunos eventos de Phonegap, y hemos añadido con ellos más funcionalidades a una aplicación que ya teníamos, haciéndola reaccionar a los eventos propios del dispositivo móvil.


No hay comentarios:

Publicar un comentario