JQuery Mobile: Desarrollo de aplicaciones y portales web para dispositivos móviles

1
44119

JQuery Mobile: Desarrollo de aplicaciones y portales web para dispositivos móviles

Índice de contenidos

Introducción

Actualmente gracias a las tarifas planas es muy común navegar por Internet a través de nuestros teléfonos móviles, smartphones y tablets (y seguramente pronto será también la televisión).

Sin embargo, la gran mayoría de la información accesible en Internet está pensada teniendo en mente que van ser accedidas a través de un ordenador de escritorio, pero poco a poco, somos más los que accedemos a través de nuestros tablets, smartphones,.. dispositivos mucho más limitados en cuanto a ancho de banda, capacidad de procesamiento, resolución de pantalla y batería, lo cual hace que la navegación sea menos agradable de lo que el usuario espera.

De ahí que muchos negocios hayan decidido dar un valor añadido creando una versión web específica para dispositivos móviles que satisfaga las necesidades de sus usuarios/clientes.

JQuery Mobile, es una de las opciones (otras alternativas) que tenemos los desarrolladores a la hora de crear un web para
móvil, se trata de una librería javascript y un conjunto de estilos e imágenes con las que
podremos crear un website (html, css y js) para los clientes más extendidos: Android, Blackberry, iPhone, iPad, WebOS, etc. Listado de plataformas compatibles.

Objetivo: Usabilidad y velocidad

Aunque siempre debería de ser importante, en el caso de los webs para tablets, smartphones, etc. es de vital importancia debido a la escasez de recursos (Red, RAM, CPU, etc), usar técnicas de optimización así como generar
un código HTML de calidad que además permita al usuario con una pantalla de reducidas dimensiones trabajar de forma usable.

Por ejemplo, cualquier web se podrían mejorar muchísimo realizando cosas como:

  • Usar imágenes optimizados para que ocupen el mínimo número de KB.
  • Comprimir y optimizar CSS, HTML y Javascript.. quitar espacios, funciones no usadas, fusionar varios css en uno, etc.
  • Reducir el número de imágenes externas para disminuir el número de peticiones HTTP. Por ejemplo, creando CSS image sprites.
  • No meter librerías de JavaScript que no aportan apenas nada e incrementan el tiempo de carga. (Usa correctamente defer y async)
  • Usar comprensión en la transferencia de datos cuando sea posible (gzip ó deflate).
  • Usar correctamente las cabeceras del protocolo HTTP para cachear los recursos estáticos.
  • Usar AppCache y LocalStorage de HTML5.
  • etc.

Pues bien, casi todo esto hay que tenerlo en cuenta si deseas una experiencia agradable con tiempos de respuesta rápidos en clientes con conexiones lentas y recursos limitados

Además, Google tiene en cuenta para el SEO el tiempo de carga de una página, penalizando las webs que tardan más en cargarse.

Si quieres analizar una web y ver la calidad en cuanto tiempo de carga de la misma puedes hacerlo usando la herramienta online gratuita pagespeed
(por cortesía de Google).

En el siguiente enlace os dejo una charla sobre aspectos de optimización a tener en cuenta cuando desarrollamos aplicaciones web para móviles, Mobile Web Performance

El usuario debería de poder usar la aplicación sin tener que estar usando zooms o haciendo scrolls de pantalla, es decir, debería de ser lo más parecido posible a una
aplicación nativa
.

Ejemplos de webs construidas con JQuery Mobile

Aprendiendo lo básico de JQuery, haciendo ejemplos

JQuery Mobile, está construido sobre JQuery core, por lo que es necesario tener conocimientos del mismo para poder usarlo y por lo tanto requiere tener habilitado el JavaScript.

Como una de las finalidades de JQM es construir aplicaciones rápidas, en donde el usuario no tenga esperas molestas (debido al ancho de banda reducido),
lo que se hace es almacenar varias pantallas lógicas en un único archivo HTML e ir mostrándolas y ocultándolas.

El desarrollador no tendrá que aprender un completo nuevo lenguaje para construir sus aplicaciones con JQM, tan sólo tendrá
que usar el HTML que ya conoce y algún que otro atributo y elemento nuevo, pero nada que asuste 🙂

Con lo anterior no quiero decir que todo el web deba estar en un único archivo HTML, sino que hay que usar el sentido común e ir agrupando las páginas relacionadas
por semántica, flujo de navegación o alguna otra forma de organización.

Se asimilan mejor las ideas poniendolas en práctica… veamos unos ejemplos:

Vea primero el ejemplo en acción y luego observe el código fuente del mismo expuesto a continuación:

Emulador del navegador de smartphones, móviles y tablets para probar nuestras aplicaciones webs.

  
  
  
  
jQuery Mobile Ejemplo 1  
    
  
  
  
  

Página 1

Inicio contenido de la Página 1

Fin contenido de la Página 1

Pie de la página 1

Página 2

Contenido de la Página 2

Pie de la página 2

Página 3

Contenido de la Página 3

Pie de la página 3

En el ejemplo anterior podemos ver lo siguiente:

  • El DOCTYPE indica que es una página HTML versión 5.
  • En la sección <head> de la página HTML importamos las librerías de JQuery y JQuery Mobile, así como la hoja de estilos de JQuery Mobile.
  • La página HTML está compuesta por tres páginas lógicas, las cuales están delimitadas por las etiquetas
    <section id="paginaID" data-role="page"> y </section>
  • Cada página (section) está compuesta por los elementos:

    • <header data-role="header">: Cabecera de la página.
    • <div data-role="content">: Cuerpo de la página.
    • <footer data-role="footer">: Pie de la página.

    En realidad, lo que le indica a JQuery Mobile lo que es una página, una cabecera, cuerpo o pie, es el atributo data-role=»page».

  • Cuándo se carga el HTML, JQuery a través de JavaScript analizará el HTML, lo modificará internamente en base a los atributos que reconoce (data-role, etc) y mostrará la primera página que se encuentre.
  • Para navegar de una página a otra, simplemente debemos crear un enlace y establecer el identificador de la página destino en su atributo href.
  • Si deseamos aplicar un efecto a la navegación entre páginas debemos especificar en el enlace el atributo data-transition=»xxxx»
  • Si deseamos convertir un enlace en un botón debemos especificar en el enlace el atributo data-role="button"
  • Si deseamos decorar un botón con una imagen debemos especificar en el enlace el atributo data-icon=»home»
  • Si deseamos que la página a la que deseamos navegar sea mostrada como un diálogo modal, debemos especificar en el enlace el atributo data-rel="dialog"

Continuemos aprendiendo en base a ejemplos, como antes vea primero el ejemplo en acción y luego observe el código fuente del mismo expuesto a continuación:

  
  
  
jQuery Mobile Application  
    
  
  
  
  

Página 1

Pie Página 1

Listas anidadas

Barra de herramientas

Contenido de la seccion de inicio

Pie Barra de herramientas

Formularios

Idiomas que es capaz de leer:

Pie Formularios

En el ejemplo anterior podemos ver lo siguiente:

  • Podemos crear estructuras de tablas (celdas y columnas) usando clases css en donde ui-grid-b es una tabla de 3 columnas, ui-grid-c es una tabla de 4 columnas, etc. Ver documentación.
  • Podemos simular N pantallas usando listas html (<ul>) anidadas agregándoles el atributo data-role="listview". Ver documentación.
  • Existen una gran variedad de controles de formulario con el que podemos recoger y/o mostrar información a los usuarios de una manera elegante y usable. Ver documentación.

¿Cómo detecto si acceden a través de un móvil o de un ordenador tradicional?

Seguramente sólo desees redirigir al usuario a una Web para móvil cuando accedan a través de su móvil y continuar mostrando la web clásica cuando se accedan desde un pc de sobremesa o portátil, pues bien, puedes
programartelo tu mismo y analizar las cabeceras User-Agent, etc. o bien usar una de las soluciones ya creadas, como por ejemplo:

Referencias y enlaces interesantes:

Otros frameworks o librerías alternativos para el desarrollo web para móviles:

Conclusiones

Como se ha podido ver en este artículo, JQuery Mobile es una excelente solución para crear una web específica para móviles de manera que permita a los usuarios de las plataformas más extendidas acceder
a la información de una forma más rápida y cómoda.

Si bien le he detectado alguna anomalia, es un proyecto estable en donde se están invirtiendo considerables esfuerzos para continuar madurándolo.

Bueno, espero que os sea de utilidad, recuerda que puedes profundizar más, esto es sólo una introducción. Si os gusta este tema, podeis continuar viendo las conferencias/charlas que publiqué en este tutorial, son bastante interesantes.

Un saludo, Carlos García

1 COMENTARIO

  1. Carlos, soy hugo de mendoza argentina, queria hacerte una consulta, resulta que estuve probando tu codigo fuente, y compila absolutamente todo, incluso le doy clean-build y da todo ok, aunque hice unos cambios en el package y en la url donde puso el php, aun asi todo ok, pero cuando ejecuto desde el emulador me dice que esta aplicacion no la puede ejecutar. esta aplicacion tiene una operacion ilegal. la clase no es un midlet. Carlos no entiendo donde puede estar el error, te comento ademas que el php lo coloque en mi localhost, tengo server propio y se que funciona bien y sin problema ya que compilo y ejecuto codigo java, jsp y todo ok, server propio pero ip dinamica, cual piensas puede ser el error, te envio el codigo aunque toque solo dos lineas, la del package y la del path del prueba.php. uso netbeans 7.1 y win xp3

    package phone;

    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    import javax.microedition.io.*;
    import java.io.*;

    /**
    * Formulario principal de la aplicación
    *
    * @author Carlos García. Autentia Real Business Solutions.
    */
    public class PhoneTestForm extends Form implements CommandListener,
    java.lang.Runnable {

    private PhoneTest midlet;
    private Command cmdExit;
    private Command cmdTest;
    private Display display;
    private String nl;

    /** Constructor */
    public PhoneTestForm(PhoneTest midlet) {
    super(\\\»MENU PRINCIPAL\\\»);

    this.midlet = midlet;
    this.display = Display.getDisplay(midlet);

    this.createUI();
    }

    /**
    * Crea el interfaz gráfico
    */
    private void createUI(){
    String nl = this.getLS();
    this.cmdExit = new Command(\\\»Salir\\\», Command.EXIT, 0);
    this.cmdTest = new Command(\\\»Probar\\\», Command.OK, 0);

    this.append(\\\»Esta aplicación realiza una prueba de conectividad para ver si su teléfono es capaz de conectarse a Internet.\\\»);
    this.append(nl);
    this.append(\\\»Si la prueba es satisfactoria en unos 10 segundos aparecerá la palabra OK en la pantalla de su terminal.\\\»);
    this.append(nl);
    this.append(\\\»Autentia Real Business Solutions.\\\»);

    this.addCommand(cmdExit);
    this.addCommand(cmdTest);
    this.setCommandListener(this);
    }

    /**
    * Realiza las operaciones de finalización
    */
    private void cmdExit_click() throws Exception {
    midlet.destroyApp(false);
    }

    /**
    * Realiza la prueba
    */
    private void cmdTestClick() {
    Thread testThread = new Thread(this);
    testThread.start();
    }

    /**
    * Devuelve el separador de linea
    */
    private String getLS() {
    String nl = System.getProperty(\\\»line.separator\\\»);

    if (\\\»\\\».equals(nl) || (nl == null)) {
    nl = \\\»\\\
    \\\»;
    }

    return nl;
    }

    /**
    * Realiza la conexión en Background (Es requerido lo dice la
    * especificación)
    */
    public void run() {
    HttpConnection http = null;
    DataInputStream is = null;
    String p1 = null;
    String p2 = null;
    int code;
    StringBuffer buffer;
    byte[] bytes;
    boolean testOK = false;
    Exception exception = null;
    try { // Configura la solicitud
    p1 = \\\»Profile/\\\» + System.getProperty(\\\»microedition.profiles\\\») + \\\» Configuration/\\\» + System.getProperty(\\\»microedition.configuration\\\»);
    p2 = System.getProperty(\\\»microedition.locale\\\»);
    http = (javax.microedition.io.HttpConnection) Connector.open(\\\»http://localhost:3306/BaseDatos/data/mibasedato/prueba.php\\\», Connector.READ);
    //o agregar BaseDatos/data/mibasedato/
    http.setRequestMethod(HttpConnection.GET);
    http.setRequestProperty(\\\»User-Agent\\\», p1);
    if (p2 != null) {
    http.setRequestProperty(\\\»Accept-Language\\\», p2);
    }

    // Leemos la respuesta
    code = http.getResponseCode();
    if (code != HttpConnection.HTTP_OK) {
    exception = new Exception(http.getResponseMessage());
    } else {
    is = http.openDataInputStream();
    bytes = this.readFully(is);
    p1 = this.getHeaderField(http, \\\»CABECERA\\\»);

    try {
    p2 = new String(bytes);
    p2 = p2.trim();
    if (\\\»OK\\\».equals(p1)
    && \\\»Autentia. Real Business Solutions\\\».equals(p2)) {
    testOK = true;
    }
    } catch (Exception ex) {
    // NADA
    }
    }
    } catch (java.lang.Exception ex) {
    exception = ex;
    }

    // Cerramos la connexión
    try {
    http.close();
    } catch (Exception ex) {
    }

    try {
    this.clear();
    } catch (Exception ex) {
    // NADA
    }

    if (testOK) {
    this.append(\\\»OK\\\»);
    } else if (exception != null) {
    this.append(exception.toString());
    } else {
    if (p1 == null) {
    this.append(\\\»\\\
    p1 null\\\»);
    } else {
    this.append(p1);
    }

    if (nl == null) {
    this.append(\\\»\\\
    \\\»);
    } else {
    this.append(this.nl);
    }

    if (p2 == null) {
    this.append(\\\»\\\
    p2 null\\\»);
    } else {
    this.append(p2);
    }
    }
    }

    /**
    * @return Devuelve todos los bytes disponibles y cierra el stream
    */
    public byte[] readFully(DataInputStream input) throws java.io.IOException {
    ByteArrayOutputStream bo = null;
    int value;

    try {
    bo = new ByteArrayOutputStream(1024); // 1Kb
    while (true) {
    bo.write(input.readByte());
    }
    } catch (java.io.EOFException ex) {
    }

    byte[] bytes = bo.toByteArray();

    // Cerramos los stream y liberamos recursos
    bo.close();
    input.close();
    bo = null;
    input = null;

    return bytes;
    }

    private void clear() {
    this.removeCommand(cmdTest);
    for (int i = this.size() – 1; i >= 0; i–) {
    this.delete(i);
    }
    }

    /**
    * Lee una cabecera Http. Algunos terminales tienen un bug en el método
    * getHeader(\\\»CabeceraDeseada\\\»)
    */
    private String getHeaderField(HttpConnection http, String header)
    throws java.io.IOException {
    int index = 0;
    String name = http.getHeaderFieldKey(index);
    while (name != null) {
    if (this.equalsIgnoreCase(name, header)) {
    return http.getHeaderField(index);
    }
    index++;
    name = http.getHeaderFieldKey(index);
    }
    return null;
    }

    /**
    * Compara dos cadenas de caracteres de modo case-insentivive
    */
    private boolean equalsIgnoreCase(String str1, String str2) {
    str1 = str1.toLowerCase();
    str2 = str2.toLowerCase();
    return str1.equals(str2);
    }

    /**
    * Receptor de eventos
    */
    public void commandAction(Command cmd, Displayable d) {
    try {
    if (cmd == cmdExit) {
    this.cmdExit_click();
    return;
    }
    if (cmd == cmdTest) {
    this.cmdTestClick();
    return;
    }
    } catch (java.lang.Exception ex) {
    display.setCurrent(new Alert(ex.toString()), this);
    }
    }
    }

    package phone;

    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.Display;

    /**
    * Esta aplicación sirve para ver si el dispositivo es capaz o no de conectarse
    * a internet y leer y escribir correctamente
    *
    * @author Carlos García Pérez. Autentia Real Business Solutions
    */
    public class PhoneTest extends MIDlet {
    private boolean started;

    /** Constructor */
    public PhoneTest() {
    started = false;
    }

    /**
    * Punto de inicio del MIDLET. Muestra el formulario principal.
    */
    public void startApp() throws MIDletStateChangeException {
    if (started) {
    return;
    }

    this.started = true;
    Display display = Display.getDisplay(this);
    display.setCurrent(new PhoneTestForm(this));
    }

    /**
    * Liberamos recursos
    */
    public void destroyApp(boolean unconditional) throws MIDletStateChangeException {
    this.notifyDestroyed();
    }

    /**
    * Pause, discontinue ….
    */
    public void pauseApp() {
    }
    }

    muchas gracias

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad