[Tutorial] Creación de lector de RSS de GeeksMS con jQueryMobile y PhoneGap

Hola que tal, vamos a comenzar revisando la primera parte del tutorial de la creación de un simple lector de RSS con JQueryMobile, JQuery y PhoneGap, también ocuparemos el emulador Ripple para Chrome que nos va servir para nuestros desarrollos de aplicaciones web móviles .

Para este lector utilicé la fuente  RSS de GeeksMS, y el plugin JGFeed para obtener estas fuentes vía jQuery.

Las Pantallas a utilizar (acá estoy utilizando un emulador de Android), serán Pantalla de Inicio, con menú inferior de Refrescar y Opciones. La Pantalla de opciones nos permitirá seleccionar el número de feeds a mostrar, el tiempo de actualización y si vamos a permitir que al momento de agitar el teléfono se realice una actualización.

Pantalla de Inicio

Pantalla de Configuración

image image

Para la creación, me acomoda bastante WebMatrix, aunque no vayamos a escribir código del lado del servidor, esta muy bueno para codificar, entonces manos a la obra, veamos como se crea este ejemplo.

Estructura del Proyecto

La estructura del ejemplo es bastante sencilla ya que la mayoría de los scripts los vamos a obtener desde CDN.

image

Estructura del la Pagina

JQueryMobile sigue una estructura de página que puedes revisar acá, en donde la pagina principal pude estar divida en varias subpáginas o data-role"=”page”, de modo que una sola página web puede contener a todo un sitio. Para mayor información puedes revisar la documentación de jquerymobile en lo que a la anatomía de las páginas respecta:
http://jquerymobile.com/demos/1.0b2/#/demos/1.0b2/docs/pages/page-anatomy.html

image

1º Parte de la Codificación , inclusión de Scripts

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.css" />

<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>

<script type="text/javascript" src="http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.js"></script>

<script type="text/javascript" src="Scripts/jGFeed/jquery.jgfeed-min.js"></script>

<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>

La primera línea tiene que ver con la forma de desplegar la página web cuando se muestra en los navegadores web, (en el caso de no usar PhoneGap, podemos ver este proyecto como una pagina web y no como una app nativa). Luego incluimos los estilos y scripts necesarios para JQueryMobile, JGFeed y PhoneGap.

Como habíamos visto, la página está divida en secciones, que corresponden a los data-role=”page” , ahora veremos la estructura de la primera sección.

Sección de Página Principal

<div data-role="page" id="principal">

  <div data-role="header" data-position="fixed" >

    <h1>Geeks•ms RSS</h1>

  </div>

  <div data-role="content">

    <ul id="lista" data-role="listview"></ul>

  </div>

  <div data-role="footer" data-position="fixed">

    <div data-role="navbar"data-theme="c">

      <ul>

        <li><a href="#" id="refrescar" data-role="button"
              
data-icon="refresh" >Refrescar</a>

        </li>

        <li><a href="#configurar" data-transition="slide"
            
 data-role="button" data-icon="gear">Opciones</a
>
        </
li>

      </ul>

    </div>

  </div>

</div>

Veamos un poco la estructura, tenemos el header, en donde mostramos el título, luego, y lo importante, la lista no ordenada con el data-role=”listview”,  en esta lista vamos a agregar los ítems de lista que vamos a obtener desde el Feed de RSS de Geeks. Finalmente en el footer, vamos a tener el menú de navegación con las opciones de refrescar y opciones, estos botones van a tener iconos datos por el atributo data-icon, gráficamente vemos algo así:

image

Sección de la Página de Opciones

<div data-role="page" id="configurar">

  <div data-role="header"  >

    <h1>Opciones</h1>

  </div>

  <div data-role="fieldcontain">

    <label for="slider">Numero de Feeds a Mostrar</label>

    <br>

    <input type="range" name="cantidad"
          
id="cantidad" value="1" min="1" max="20" 
/>

    <br>

    <label for="slider">Tiempo de Actualización(min):</label>

    <br>

    <input type="range" name="tiempo"
          
id="tiempo" value="1" min="1" max="20" 
/>

    <p>

    <label for="slider">Refrescar al Agitar</label>

       <select name="shake" id="shake" data-role="slider">

             <option value="off">Off</option>

             <option value="on">On</option>

       </select>

    </p>

    <p>Aplicación de prueba desarrollada por Chalalo.
      No es una  aplicación oficial GeeksMS, si quieres modificarla,
      siéntete con toda la  libertad.
<br
>

    </p>

     <p><a href="#" id="volver" 
          
data-role="button" data-icon="back">Volver</a>
     </
p
>

  </div>

  <div data-role="footer" data-position="fixed">

    <h1>www.chalalo.cl</h1>

  </div>

</div>

Utilizamos dos controles type=”range” que básicamente corresponde al slider, y el render que hace este JQM es simplemente genial, como puedes ver en la imagen, además vamos a ocupar un objeto select al cual le vamos a agregar el atributo data-role=”slider” para que se vea como la imagen siguiente:

image

Codificación de la página principal

Revisemos parte por parte codificación y su esquema de funcionamiento es el siguiente:

image

Una vez que el documento esté listo (previamente a la inicialización de variables),, se establece mediante una el sertInterval la periodicidad con la cual vamos a cargar los feed desde la fuente, esto es, un ciclo cada cierta cantidad de segundos,  luego vamos a registrar un listener que gatille la función startWatch que va a monitorear si el acelerómetro del dispositivo se ha movido lo suficiente como para considerar es un “shake”, esto se consulta en la funcion onSuccess.

var cantidad=10;
var tiempoRefresco=15;
var watchID = null;

$(document).ready(function(e) {

    cargarFeeds(cantidad);

    document.addEventListener("deviceready",startWatch(), false);

       setInterval(function() {

           cargarFeeds(cantidad);

       }, tiempoRefresco * 60000)

Como puedes ver, al inicio se cargan las variables, en donde la cantidad de feeds por defecto es 10 y el tiempo de refresco es 15 minutos, además declaramos la variable watchID que nos va a servir para utilizar PhoneGap y el acelerómetro del dispositivo, luego llamamos a la función cargaFeeds, con el parámetro cantidad, también hacemos referencia a la variable tiempo de refresco y al listener que indica cuando el dispositivo está realmente listo para utilizar utilizar phonegap.

Ya que hablamos de PhoneGap veamos las funciones que involucran al SDK:

function startWatch() {

     var options = { frequency: 3000 };

     watchID = navigator.accelerometer.watchAcceleration(onSuccess, onError, options);

 }

function stopWatch() {

     if (watchID) {

          navigator.accelerometer.clearWatch(watchID);

          watchID = null;

        }

    }

 

 

function onSuccess(acceleration) {

      var max = 1;

      if (Math.abs(acceleration.x) > max

                    || Math.abs(acceleration.y) > max

                    || Math.abs(acceleration.z) > max) {

          cargarFeeds(cantidad);

        }

    }

 

function onError() {

        alerta(‘Error al Agitar!’,‘GeeksMS’,‘Aceptar’);

    }

      

function alerta(mensaje,titulo,boton) {

        navigator.notification.alert(mensaje,titulo,boton);

    }

Veamos de que tratan las funciones,

  • startWatch: inicializa la detección de la aceleración del dispositivo según un intervalo de tiempo regular(300ms). cada vez que es detectada la aceleración ya sea en el eje Y,X o Z, se va a llamar a la función onSuccess para determinar la magnitud de dicha aceleración y si la vamos a considerar con la intensidad necesaria para hacer el refresco.
  • stopWatch: Si bien startWatch asignaba la referencia a la variable watchID, se puede utilizar clearWatch para limpiar esta referencia, esta funciona la vamos a utilizar cuando no está seteada la opción de refrescar al agitar en la pantalla de configuración.
  • onSucess:Recibe como argumento la aceleración, dentro se establece como máximo de nivel de aceleración el valor 1, esto tiene que ver con que tan sensible al agitar el dispositivo vamos a realmente determinar que se hizo un “shake”, a menor número, más sensible, si la aceleración de los ejex x o y o z es mayor a 1, entonces llamamos a la función cargaFeeds
  • onError: Si se produce un error, enviamos una alerta(alerta nativa del dispositivo)
  • alerta: utilizada para llamar al método alert de la clase notificación de PhoneGap.

Para  más información de uso de la clase accelerometer pincha :
 http://docs.phonegap.com/phonegap_accelerometer_accelerometer.md.html

Veamos ahora la clase cargarFeeds, que es la que se encarga de cargar desde la fuente RSS la cantidad especificada de post.

function cargarFeeds(cantidad){

try{

    $.mobile.loadingMessage = "Recuperando Feeds";

    $.mobile.showPageLoadingMsg();

    $.jGFeed(‘http://geeks.ms/blogs/MainFeed.aspx’,

          function(feeds){

            if(!feeds){

            $.mobile.hidePageLoadingMsg();

             alerta(‘Error , no se puede Obtener RSS!’,‘GeeksMS’,‘Aceptar’);

                 return false;

              }else{

                var lista = $(‘#lista’);

                lista.html("<li data-role=’list-divider’ data-theme=’a’>" +
            cantidad +
" Post, Actualización :" + getFechaHora() + "</li>"
);

                for(var i=0; i<feeds.entries.length; i++){

                    var entry = feeds.entries[i];

                    var html="<li>";

                    html+="<a href=’"+ entry.link + "’><h3>"+
                            entry.title +
"</h3>"
;

                    html+="<p><strong>"+ entry.author +
                          
"</strong> – "+entry.publishedDate +"</p>"
;

                    html+="</a></li>";

                    lista.append(html);

                    lista.listview("refresh");

                 }     

                           $.mobile.hidePageLoadingMsg();

              }}, cantidad);

              return true;

       }catch(err){

          alerta(‘Error , no se puede Obtener RSS!’,‘GeeksMS’,‘Aceptar’);

       }

 }

Esta función ,recibe la cantidad de post que vamos a obtener, y utiliza la librería jGFeed para la obtención de los feeds, puedes ver que utilizo :

$.mobile.loadingMessage = "Recuperando Feeds";
$.mobile.showPageLoadingMsg();

Para mostrar el mensaje de cargando…

.image

Luego obtengo la lista definida como:
    <ul id="lista" data-role="listview"></ul>

A continuación vamos agregando los feeds al elemento UL mediante HTML que contiene los tags <li> formado por los tags correspondientes y concatenando con el objeto entry que corresponde a una entrada RSS, es importante que vayamos refrescando el lista invocando:

list.listview(“refresh”)

Ya que de otra manera, no veríamos redenrizada la lista con los estilos que agrega jquerymobile. Personalmente no lo hice en un principio y la lista no se veía correctamente.

Sin list.listview(“refresh”) Triste

Con list.listview(“refresh”)  Sonrisa

image image

Las llamadas de los menú de navegación (Refrescar y Opciones) utilizan  las siguientes funciones:

$("#refrescar").click(function(e) {
    
cargarFeeds(cantidad);

});

$("#configurar").bind("pageshow", function() {

      $("#cantidad").val(cantidad).slider("refresh");

      $("#tiempo").val(tiempoRefresco).slider("refresh");

         var shake = $("#shake");

         if (watchID!=null){

            shake[0].selectedIndex = 1;

         }else{

           shake[0].selectedIndex =0;

         }

      shake.slider("refresh");

   });

           

En donde se hace al pinchar sobre el menú refrescar  vamos a llamar a la función cargarFeeds. A continuación tenemos el código que se va a ejecutar cuando pinchan sobre el menú opciones, recordemos que el menú opciones tiene un link a la sección de la pagina #configurar. Lo que se hace entonces, es unir mediante el método bind de jquery, el evento pageshow, de manera de ejecutar una función al momento de mostrar la sección de configuración en la pantalla, esta función a ejecutar setea los valores de los controles range y slider; utilizamos siempre al setear “refresh” para reflejar los cambios cuando se realiza en render.

Finalmente para esta página utilizo una función helper simplemente para obtener formateada la fecha de la ultima actualización.

function getFechaHora(fec){

       var fec=new Date;

       var dia=fec.getDate();

       var mes=fec.getMonth();

       var anio=fec.getFullYear();

       var horas = fec.getHours() ;

       var minutos = fec.getMinutes() ;

       var segundos = fec.getSeconds() ;

       if (dia<10) dia=‘0’+dia;

       if (mes<10) mes=‘0’+mes;

 

       if (horas <10) horas = "0" + horas;

       if (minutos <10) minutos = "0" + minutos;

       if (segundos <10) segundos = "0" + segundos;

 

   return anio+‘/’+mes+‘/’+dia+" "+horas+":"+minutos+":"+segundos;       

}

Codificación de la página de Opciones

$("#volver").click(function(e) {

    cantidad=$("#cantidad").val();

    tiempoRefresco = $("#tiempo").val();

    var shake = $("#shake");

    if (shake[0].selectedIndex == 0){

         stopWatch();

    }else{

       if (watchID == null){

              startWatch();

              }

        }

       cargarFeeds($("#cantidad").val()); 

       $.mobile.changePage("#principal", "slide", false, true);

     });

Este código, tal como se indica, se va a ejecutar cuando se hace click en el botón volver, seteando las variables globales como la cantidad de feed,el tiempo de refresco , y el seteo si vamos a permitir que se actualicen los feed agitando el teléfono, si es que el watchID está en nulo, ejecutamos la función startWatch,si no, quiere decir que la referencia watchID está activa y que siga su correcto funcionamiento.

image

Probando la Aplicación

Para probar la aplicación sin PhoneGap podemos hacer uso de cualquier navegador en su ultima versión (IE9 funciona correctamente), sin embargo, hay un plugin muy bueno para Chrome que sirve para probar aplicaciones web móviles según su respectiva plataforma, se llama Ripple y es de RIM, entre otras cosas, nos va a permitir simular tener la aplicación instalada con PhoneGap sobre un dispositivo, la geo localización y el agitar el teléfono. Instálalo desde: http://ripple.tinyhippos.com/

image

Si vemos la sección de la izquierda, podremos simular el efecto Shake y mover el teléfono en los ejes xyz.

Veamos un video mostrando el funcionamiento(el refresco pasa rápido, apenas se nota, pero lo hace).

Descarga el código de la aplicación desde acá:

Puedes ir al WebSite de PhoneGap para ver como configurar esta página para correrla como aplicación nativa de un dispositivo móvil.
http://www.phonegap.com/start

Espero que te sirva de guía Sonrisa
Saludos!!
Gonzalo

5 comentarios en “[Tutorial] Creación de lector de RSS de GeeksMS con jQueryMobile y PhoneGap”

  1. Hola, he descargado tu código para probar la aplicación, pero
    parece que debe de tener algun error, aunque no lo he encontrado, pero me ocurre que al iniciarse aparece toda la pantalla en blanco, sabes a que puede ser debido?

    Un saludo.

  2. Hola de nuevo, parece que el problema es una llave de mas
    al cerrar este método

    function(feeds){

    if(!feeds){

    $.mobile.hidePageLoadingMsg();

    alerta(‘Error , no se puede Obtener RSS!’,’GeeksMS’,’Aceptar’);

    return false;

    }else{

    var lista = $(‘#lista’);

    lista.html(“

  3. ” + cantidad + ” Post, Actualización :” + getFechaHora() + “
  4. “);

    for(var i=0; i

    “+ entry.title +”

    “;

    html+=”

    “+ entry.author +” – “+entry.publishedDate +”

    “;

    html+=”“;

    lista.append(html);

    lista.listview(“refresh”);

    }

    $.mobile.hidePageLoadingMsg();

    }}, cantidad);

    aqui donde pasas la cantidad, cierras dos llaves, quitando una he conseguido que funcione la aplicación pero aun así no obtengo los feeds, despues en la pantalla de configuracion el botón volver tampoco funciona.
    Un saludo.

  5. Hola Giorgo, gracias, no había visto el comentario, me llegaban al correo y no se que pasa, voy a revisar lo que me dices, a mi me funciona, que raro, mi gtalk es gonpec, en o por twitter @chalalo, para que veamos el problema.

  6. Esta usando phonegap, lo tienes que usar en un emulador, no en el browser. No tienes tampoco que quitar esta parte tampoco, sino no estará bien.

    }}, cantidad);

    El código esta bien, pero, tienes que llevarlo a un ripple o integrarlo a una app nativa (estructura android o iphone) para que lo pruebes.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *