martes, 27 de mayo de 2014

Plugins

Por defecto, al crear un proyecto Phonegap mediante línea de comandos en nuestro sistema, éste es muy básico. Se crea sólo la estructura de documentos, además de que usa la API justa y necesaria para funcionar. Para acceder a elementos hardware de los dispositivos móviles tales como cámara o vibración desde nuestra aplicación, necesitamos ampliar la API en nuestro proyecto. En Phonegap y Cordova, lo hacemos incluyendo plugins, que aumentan las capacidades de nuestra aplicación, pudiendo acceder a elementos a los que antes no se podía.

He aquí una lista con los plugins de Phonegap:

  • Battery Status: Sirve para monitorizar el estado de la batería.
  • Camera: Plugin que nos permite lanzar la cámara del dispositivo.
  • Contacts: Con este plugin podemos tener acceso a la agenda del teléfono.
  • Device: Obtenemos información básica del dispositivo.
  • Device Motion (Acelerómetro): Nos da acceso al acelerómetro del dispositivo.
  • Device Orientation (Compass): Podemos obtener la dirección a la que apunta el dispositivo.
  • Dialogs: Notificaciones.
  • FileSystem: Accedemos al sistema de ficheros mediante javascript.
  • File Transfer: También tendremos acceso al sistema de ficheros del dispositivo.
  • Geolocation: Hace que nuestras aplicaciones puedan localizar físicamente al usuario.
  • Globalization: Permite determinadas representaciones según las preferencias locales del usuario.
  • InAppBrowser: Lanza URLs a través de otra instancia de navegador en la app.
  • Media: Grabación y reproducción de audio.
  • Media Capture: Captura ficheros multimedia.
  • Network Information (Conexión): Nos da información sobre el estado de conexión del dispositivo.
  • Splashscreen:  Manipulamos las llamadas splash screen de las aplicaciones.
  • Vibration: Con esta API podemos hacer vibrar el dispositivo.


Si queremos añadir plugins para acceder a los elementos de nuestro dispositivo, podemos hacerlo mediante línea de comandos. Los comandos para añadir los plugins podemos consultarlos aquí. De este modo podemos añadir a nuestro código fuente las líneas necesarias para usar esos plugins sin temor de que haya fallos al compilar. Por ejemplo, si tecleamos el siguiente código:
phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-battery-status.git
estaríamos añadiendo las utilidades necesarias para acceder a los datos de la batería del dispositivo tales como el nivel de carga.
Podemos saber qué plugins tenemos instalados en el proyecto haciendo uso del siguiente comando:
phonegap local plugin list

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.


martes, 20 de mayo de 2014

Cargar vistas nuevas manteniendo el estado de la aplicación

Si en nuestras aplicaciones queremos cargar varias pantallas, y pasar de una a otra manteniendo el estado de la aplicación, en este capítulo veremos algunas soluciones. Puede ocurrir que queramos tener una vista para las opciones de la aplicación aparte de la vista principal, por ejemplo.

En Android, para pasar de una pantalla a otra pasando información(las opciones de configuración de la app, por seguir con el ejemplo anterior), existen las intenciones, de forma que preparamos un array asociativo con los datos que nos interesan antes de cargar la nueva pantalla.

Voy a proponer dos soluciones para que las usemos en Phonegap.

La primera requiere aprender herramientas nuevas. Como estamos usando javascript, podemos aprovecharnos de frameworks como Emberjs.


fuente: http://emberjs.com/

Ember está basado en el patrón MVC(modelo vista controlador) y permite lanzar aplicaciones "single-page" complejas. Si ya tenemos conocimientos sobre este framework, nos podría servir. En este enlace podemos ver un ejemplo sencillo de registro y login con Emberjs, si queremos implementarlo en Phonegap solamente tendríamos que pegar el fichero html y los javascript en la carpeta www de nuestro proyecto esqueleto.



Otra opción es tener todas nuestras vistas cargadas en la aplicación, pero tener en todo momento sólo una visible en pantalla, aplicando con javascript clases CSS a las vistas que queramos mostrar u ocultar. Podemos tener una clase CSS .oculto{display: none;} y .visible{display: block;}. En el html de la aplicación un <div class="oculto"> y un <div class="visible">. La capa visible será la principal de la aplicación, y la oculta será la que mantendremos sin mostrar, hasta que se solicite. En ese caso aplicamos y eliminamos las clases CSS oculto y visible según nos convenga.
A continuación veremos un ejemplo en el que ponemos esto en práctica. Usaremos el esqueleto creado en capítulos anteriores.
El body del html es el siguiente:

<body>
        <div id="vistaOpciones" class="oculto container-fluid">
            <div class="col-xs-4 col-xs-offset-4">
                <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="col-xs-4 col-xs-offset-4">
                <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>
        <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);
        </script>
    </body>

Nos fijamos que en el mismo html tenemos dos div que representan a las dos "pantallas" de nuestra aplicación. Uno de ellos tiene la clase visible y otro la clase oculto, por lo que sólo se mostrará el div con id vistaPrincipal. Mediante javascript, al pulsar en los botones, se producirán  reacciones en la aplicación(reacciones instantáneas, porque tenemos FastClick) que harán que se cambie de pantalla en nuestra aplicación, pulsando en el botón OPCIONES o en el botón Volver. En la vista vistaOpciones hay dos botones además del que nos devuelve a la pantalla principal.

Estos botones al ser pulsados producen cambios que se mantienen al cambiar de pantalla. No estamos cambiando de documento html en ningún momento, por lo que las variables que tengamos en javascript y las clases CSS que tengan los elementos html no se recargan. En este ejemplo sólo mantenemos clases CSS al cambiar de pantalla(el color del texto), pero podríamos guardar valores en variables que afecten el comportamiento de nuestra aplicación.
A continuación vemos el código javascript del ejemplo:

$(function(){
    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");
    });
});

Y este es el CSS de la aplicación usada:

.visible{
    display:block;
}

.oculto{
    display:none;
}

.fondoAzul{
    color: #2222FF;
}

.fondoRojo{
    color: #ff2222;
}

Aquí tenemos el código de la aplicación, listo para compilar. Si deseamos, en config.xml podemos editar su id y su nombre.

lunes, 19 de mayo de 2014

FastClick

En este capítulo hablaré brevemente sobre FastClick, una librería muy útil que elimina un delay de 300 milisegundos que hay en los navegadores móviles, entre que hacemos una pulsación en algún elemento y se procesa el evento deseado. Esto no sucede en los navegadores de escritorio.

fuente: http://blog.hexacta.com/

El retraso de 300 ms entre el evento touch end y el click esta implementado en el navegador móvil para soportar double taps o dobles pulsaaciones, es decir, espera 300 ms a la espera de recibir otro tap y saber si se trata de un double tap.
El double tap se suele usar en los dispositivos para hacer zoom sobre algún elemento de la página. Ya depende de nosotros si queremos darle esa funcionalidad o eliminarla a cambio de mayor velocidad de respuesta en nuestras aplicaciones móviles.

¿Cómo funciona fastclick? Lo primero que haremos será incluirlo en nuestro html de la siguiente manera:
<script type='application/javascript' src='/donde/quiera/que/este/fastclick.js'></script>

Y lo agregamos a los elementos que queremos que respondan rápidamente.
window.addEventListener('load', function() {
                new FastClick(document.body);
}, false);

En este caso, todo el body. Fastclick captura el evento touchend e inmediatamente dispara el evento click sobre el elemento pulsado, y anula el evento click que disparará el browser 300 ms después, para que no ocurra por duplicado.

En principio parece poco tiempo, pero se nota. Vamos a ver la diferencia entre usar FastClick en nuestras aplicaciones móviles Phonegap y no usarlo.

Tomaremos como base la calculadora implementada en el capítulo anterior. De hecho, ya está implementado FastClick en ella. Para evitar su uso, sólo tenemos que comentar las siguientes líneas en el .html:

window.addEventListener('load', function() {
                new FastClick(document.body);
}, false);

Compilamos la aplicación y al ejecutarla podremos notar ese retraso, y si no lo notamos, vamos a implementar FastClick en todos los botones de la calculadora menos en uno, para que al pulsar ese botón comparemos el tiempo de respuesta respecto a los demás botones. Como apuntaba antes, estas pruebas es conveniente usarlo en un móvil, porque en navegadores de escritorio no sucede este retraso, y no notaremos diferencia alguna.

Descomentamos las líneas que habíamos comentado antes, y compilamos y ejecutamos la calculadora de nuevo. Al incluir la librería FastClick en el html, y añadir las líneas que hemos descomentado, FastClick actúa en todos los "toques" que hagamos en pantalla(porque añadimos el addEventListener en window) de forma automática. Si deseamos que algún elemento cuente con el retraso original de 300 milisegundos, añadimos la clase needsclick al elemento en cuestión.

Si nos fijamos en el código de la tecla 0 de la calculadora, veremos que, a diferencia de las demás, tiene la clase needsclick que hace que FastClick no actúe al pulsarla. Para comprobar la diferencia pulsamos alternativamente la tecla 0 y cualquier otro número, y veremos que el tiempo que tardan en aparecer en la pantalla de la calculadora es diferente.

nota del autor: pensaba que los 300 ms eran cosa de Android, pero parece ser que es cosa de los navegadores web móviles, y nuestra aplicación en definitiva será un webview.

Calculadora jQuery

En un capítulo anterior comentaba la facilidad de compilar programas para plataformas móviles, a partir de proyectos web que ya tuviésemos escritos. Con este primer ejemplo veremos esto en la práctica.

Para empezar copiamos la carpeta esqueleto que contiene el proyecto base que preparamos en el capítulo anterior. Si queremos modificamos el id y el nombre de la app en el fichero config.xml.

Copiamos el siguiente código en el body del documento index.html, que quedaría así:

<div class="container">
            <h1 class="text-center">PhoneGap</h1>
            <div id="calculator">
                <div class="well result"> 0 </div>
                <div class="digits">
                    <div class="row">
                        <button class="btn btn-default digit col-xs-3">7</button>
                        <button class="btn btn-default digit col-xs-3">8</button>
                        <button class="btn btn-default digit col-xs-3">9</button>
                        <button class="btn btn-default digit col-xs-3">+</button>
                    </div>
                    <div class="row">
                        <button class="btn btn-default digit col-xs-3">4</button>
                        <button class="btn btn-default digit col-xs-3">5</button>
                        <button class="btn btn-default digit col-xs-3">6</button>
                        <button class="btn btn-default digit col-xs-3">-</button>
                        
                    </div>
                    <div class="row">
                        <button class="btn btn-default digit col-xs-3">1</button>
                        <button class="btn btn-default digit col-xs-3">2</button>
                        <button class="btn btn-default digit col-xs-3">3</button>
                        <button class="btn btn-default digit col-xs-3">×</button>
                    </div>
                    <div class="row">
                        <button class="btn btn-default digit col-xs-3 needsclick">0</button>
                        <button class="btn btn-danger  digit col-xs-3">C</button>
                        <button class="btn btn-info    digit col-xs-3">=</button>
                        <button class="btn btn-default digit col-xs-3">÷</button>
                    </div>        
                </div>
            </div>
</div>

Si ejecutamos el index.html en un navegador veremos que tenemos una calculadora, cuya maquetación hemos logrado mediante Bootstrap. Bootstrap maqueta automáticamente la web mediante el uso de ciertas clases en los elementos del html. Todas las clases usadas en los elementos de esta aplicación son para que sean procesados por Bootstrap y ahorrarnos nosotros el escribir CSS. Además, nos facilita enormemente el crear diseños responsive, lo cual es importantísimo para nuestros propósitos, ya que existe una gran variedad pantallas en las que puede ejecutarse nuestra aplicación.
Por su parte, el id calculator, y las clases result, digits y digit servirán para seleccionar elementos en el javascript que añadiremos después. Ignoremos por el momento la clase needsclick que tiene el <button> de contenido 0.


Aplicación en navegador de pc:

A continuación pegamos el siguiente código al index.js:

var app = {
    // Application Constructor
    initialize: function() {
        //this.bindEvents();
    }
};

jQuery(function($) {
  var digits = $('#calculator .digits .digit');
  var leftBuffer = '';
  var rightBuffer = '';
  var calculator = { left: false, right: false, result: 0, operator: '+' };

  function calculate() {
    calculator.result = eval(calculator.left + calculator.operator + calculator.right);
    $('#calculator .result').text(calculator.result);
    calculator.left = null;
    calculator.right = null;
    leftBuffer = calculator.result + '';
    rightBuffer = '';
  }

  function isDigit(key) {
    var digits = "0123456789";
    var digit = false;
    if(digits.indexOf(key) != -1)
      digit = true;
    return digit;
  }
  

  digits.click(function() {
    var key = $(this).text();
    console.log(leftBuffer, rightBuffer);
    if(isDigit(key)) {
      if(calculator.left) {
        rightBuffer += key.toString();
        $('#calculator .result').text(rightBuffer);
      } else {
        leftBuffer += key.toString();
        $('#calculator .result').text(leftBuffer);
      }
    } else if(key != '=' && key != 'C') {
      switch(key) {
        case '÷': key = '/'; break;
        case '×': key = '*'; break;
      }
      calculator.operator = key;
      calculator.left = leftBuffer;
    } else if(key == 'C'){
      leftBuffer = '';
      rightBuffer = '';
      calculator.left = null;
      calculator.right = null;
      calculator.result = 0;
      $('#calculator .result').text(calculator.result);
    } else {
      calculator.right = rightBuffer;
      if(calculator.left.substring(calculator.left.length-1, 1) == '.')
        calculator.left += '0';
      if(calculator.right.substring(calculator.right.length-1, 1) == '.')
        calculator.right += '0';
      calculate();
    }
  });
});

He mantenido el objeto app para que no se produzcan errores al abrir ahora index.html en el navegador. Si deseamos podemos eliminarlo y comentar en el index.html la línea app.initialize(); Por lo demás, con el código mostrado, simplemente hacemos que la página web reaccione al pulsar las teclas de la calculadora.

Refrescamos la página y vemos que tenemos una aplicación web simple que simula el funcionamiento de una calculadora. No entraremos en detalles sobre el funcionamiento del código javascript, ya que no es el fin de este tutorial. En lo que sí que tenemos que centrarnos es en el hecho de que es una aplicación que puede ejecutarse en cualquier navegador y que en principio no está destinada a móviles. Pero al estar situada dentro de www en nuestro proyecto phonegap, podemos compilar y ya tendremos aplicaciones móviles, sin tener que hacer nada más con el código.

Abrimos en la carpeta esqueleto una consola y escribimos:

phonegap run android

Ahora podremos ver la versión móvil de la aplicación que acabamos de ver en la máquina virtual de Android de nuestro equipo. Si lo deseamos podríamos obtener el .apk para instalar en nuestro móvil desde Phonegap Build, o una vez compilado el proyecto en local, en la carpeta platforms/android/ant-build. Usad en este caso la versión unaligned del .apk.

Aplicación móvil:

Esqueleto básico para el tutorial

Para todos los proyectos de este tutorial, partiremos de la misma base. Dejaremos lista una carpeta con los directorios y ficheros necesarios para poder empezar con cualquiera de los programas que usaremos. Así, cada vez que vayamos a empezar una nueva app tan sólo tendremos que copiar esa carpeta con las configuraciones listas.
Se trata del proyecto Phonegap básico de la versión 3.4, al que añadiremos Android a su carpeta platforms. Suponemos que tenemos instalado el SDK de Android. Posteriormente añadiremos Bootstrap para ayudarnos a maquetar las vistas, jQuery para simplificar las sintaxis de javascript y FastClick, una librería que elimina un retraso de 300 milisegundos que tiene lugar en Android desde que se pulsa un botón hasta que el sistema de Google lo interpreta como un click. Su funcionamiento lo veremos en la primera aplicación de ejemplo.

Vamos a la carpeta en la que vayamos a guardar la base para nuestro proyectos posteriores y escribimos en línea de comandos:

phonegap create esqueleto

Descargas

Ahora vamos a añadir Bootstrap, versión 3.1.1. Nos descargamos Bootstrap de la página oficial y descomprimimos la carpeta fonts de Bootstrap y la añadimos a la carpeta www del proyecto. También extraemos a la carpeta css del proyecto el fichero bootstrap.min.css. Hacemos lo propio con bootstrap.min.js en la carpeta js.

fuente: getbootstrap.com/


A continuación descargaremos jQuery de su web, y añadiremos el fichero jquery-1.11.0.min.js a la carpeta js del proyecto. Es evidente que la versión que usaremos de jquery es la 1.11.

fuente: jquery.com/


Lo siguiente será la librería FastClick, que la descargamos aquí. El fichero fastclick.js lo situaremos también en la carpeta js.



Código

Cuando tengamos todas las librerías completaremos el fichero index.html de manera que quede así.

<!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>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">PhoneGap</h1>
            
        </div>

        <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>
</html>

Analizando un poco el código, vemos que al final del body hemos añadido los javascript de jquery, bootstrap, fastclick, el nuestro propio, e inicializamos fastclick de la manera que se nos aconseja hacer en su web. En el head del documento hemos añadido el css de bootstrap.

Ya tenemos el esqueleto básico de un proyecto Phonegap, ahora vamos a añadirle la plataforma Android para compilar en local(puedes saltarte este paso si quieres compilar únicamente mediante Phonegap Build).
El siguiente comando lo escribimos dentro de la carpeta esqueleto:

phonegap build android

Ya tenemos listo el proyecto que nos servirá para todos los ejemplos del tutorial. Cuando vayamos a crear un nuevo proyecto, con copiar la carpeta esqueleto que hemos dejado lista, y renombrarla, bastará. Obviamente es deseable que editemos el fichero config.xml para cambiar el nombre y el id de la aplicación que creemos en cada momento.

Código fuente.

viernes, 16 de mayo de 2014

¿Cómo se programa? Desarrollo Phonegap = desarrollo web

Ok, sabemos qué es Phonegap, está instalado en nuestro pc, sabemos crear proyectos, e incluso hemos visto las posibilidades para compilar. Pero, ¿Cómo se programa en Phonegap?. A la hora de desarrollar aplicaciones móviles con Cordova/Phonegap, debemos pensar que estamos desarrollando aplicaciones web frontend, con la excepción de que accedemos al hardware de dispositivos móviles si lo necesitamos. Si lo hacemos así, nuestros primeros pasos serán más sencillos. Es decir, nuestra aplicaciones lucirán como queramos por medio de html y CSS, y se comportarán como deseemos mediante código javascript, ni más ni menos.

Para empezar a tener una visión general de cómo se va a comportar una aplicación desarrollada en Phonegap, vamos a analizar los componentes principales de una aplicación.

Elementos de la aplicación

Las vistas de la aplicación serán elementos de html, y los representaremos en archivos .html. Por ejemplo, si queremos mostrar una imagen, en una aplicación de Android nativa, se hace uso de las vistas, concretamente de una vista de imagen. En Phonegap esto lo mostramos con la etiqueta img de html. Las diferentes actividades de la aplicación con las que contábamos en Android, no serán más que distintos ficheros html a los que podremos acceder mediante enlaces <a>***.

Estilos

El estilo visual de la página web aplicación móvil lo conseguiremos con CSS3, aplicando estilos a los elementos html. Es importante hacer diseños responsive, puesto que nuestras aplicaciones podrán ser ejecutadas tanto en móviles como en tablets.

Comportamiento

La lógica de la aplicación la implementamos con javascript, como con cualquier aplicación web frontend. Con esto nos referimos a las acciones que sucederán al pulsar un botón, o a "jugar" con los elementos que veremos por pantalla según el estado de la aplicación...

Ayudas

Por supuesto podemos hacer uso de frameworks para facilitarnos la vida (y para incrementar el peso de las apps, todo sea dicho), como jQuery, Emberjs, Angularjs para javascript, o Bootstrap para los estilos CSS y conseguir diseños agradables a la vista con poco esfuerzo. Otras ayudas como Sass, Less para CSS, haml para html, CoffeeScript para javascript... son bienvenidas también.

Antes de usar las API que nos proporcionan Phonegap/Cordova, vamos a implementar algunas aplicaciones de ejemplo, que no necesitan acceder a ningún componente de los dispositivos móviles en los que serán ejecutadas. Esto nos servirá para entender el que considero el verdadero potencial de Phonegap. No sólo desarrollar aplicaciones móviles multiplataforma, además podemos, teniendo ya una aplicación web desarrollada previamente, hacer su versión móvil con muy poco esfuerzo.


*** Si alguien ya ha programado antes en Android puede preguntarse de qué forma podemos guardar el estado de la aplicación al pasar de una pantalla a otra, cosa que en Android se hace mediante el envío de intenciones. Al pasar de una página html a otra, el navegador "olvida" el estado de la web cuando carga el nuevo fichero html. Por ejemplo, relleno un campo con un nombre y pulso un enlace, y al cargar otra página y volver a la primera, el campo está vacío, porque se ha recargado la vista de nuevo. Como vamos a programar aplicaciones web, disponemos de diferentes formas, como pueden ser el uso de frameworks de javascript para hacer aplicaciones single-page (emberjs por ejemplo), o cargar todas las "pantallas" en la misma vista html, pero fuera de los límites de la pantalla del móvil, y mediante javascript y CSS hacer esas pantallas visibles aplicando distintas clases de CSS para que se coloquen dentro de la pantalla (o fuera de la misma). En siguientes apartados veremos cómo hacer esto de ambas formas, con ejemplos sencillos.