Ocultando la barra de direcciones del navegador de Android

Introducción

Con los beneficios que las nuevas características de HTML5 y CSS3 traen a los desarrolladores de aplicaciones móviles cada día es mas frecuente que se desarrollen sitios y aplicaciones web diseñadas específicamente para estos dispositivos.

Las aplicaciones web móviles son en esencia una página web que emula en cierta medida el look-and-feel de las aplicaciones nativas para permitirle al usuario acceder a la funcionalidad de la aplicación con los beneficios (y desventajas) de una aplicación web pero con una experiencia similar a las aplicaciones convencionales.  Para hacer esto existen varios frameworks sin embargo hay ocasiones en las que es preferible no basarse en ellos sino implementar una página web estándar.

Ocultando la barra de direcciones en el navegador web de Android
Ocultando la barra de direcciones en el navegador web de Android

En esos casos probablemente la primera de las adaptaciones que se desea realizar es el ocultar la barra de direcciones del navegador ya que así se dará la impresión de aplicación nativa y no de página web convencional inmersa en un navegador.

En Android esto es posible lograr de cierta manera.  La barra de direcciones no puede ser eliminada por completo pero puede ser ocultada, es decir, no se verá durante la ejecución de la aplicación web móvil hasta que el usuario decida hacer el scroll necesario para acceder a ella.

Procedimiento

El procedimiento para lograr esto se basa en dos pasos que se deben realizar mediante Javascript.  El primero de ellos consiste en garantizar el la página web de la aplicación móvil cuenta con suficiente altura para poderse realizar.  Para esto se manipula el alto del body.  El segundo paso consiste en simular desde código un scroll lo que activará la característica del navegador de ocultar la barra de direcciones.

/**
 * Hide the URL address bar on standard Android's browser by setting enough
 * document height and auto scrolling to active the bar hiding feature
 */

function hideAddressBar()
{
  if(!window.location.hash)
  {
      if(document.height < window.outerHeight + 10)
      {
          document.body.style.height = (window.outerHeight + 50) + 'px';
      }

      setTimeout(function()
      {
      	window.scrollTo(0, 1);
      }, 50);
  }
}

Finalmente se invoca esta función una vez se ha cargado completamente (load) la página web, garantizando también que esto se haga durante los cambios de orientación del dispositivo.

/**
 * Start up procedure to hide the Android's URL bar
 */

window.addEventListener("load", function()
{

	if(!window.pageYOffset)
	{
		hideAddressBar();
	}

	window.addEventListener("orientationchange", hideAddressBar);

});

Enlaces

Experimentando un poco con el Canvas de HTML5

Introducción

Entre las muchas maravillas que nos trae HTML5 está el componente Canvas cuya funcionalidad es sorprendente en comparación con lo que nos tenía acostumbrados la versión anterior.  Durante este fin de semana decidí jugar un poco con el Canvas para experimentar con su funcionalidad básica de dibujar.

Para esto desarrollé una aplicación web muy simple que permite dibujar puntos y líneas en un lienzo blanco.  El color de las lineas puede ser modificado entre amarillo, azul y rojo.

La aplicación web resultante puede ser consultada desde un navegador web de escritorio o uno de un dispositivo móvil ya que no sólo se manejaron los eventos de ratón convencionales sino que también se incluyeron los eventos de touch que permiten detectar la interacción con las pantallas táctiles.

Demostración

Demostración uso básico de Canvas
Demostración uso básico de Canvas

Enlaces

Arrastrar y soltar con HTML5

Introducción.

En este artículo se revisarán los pasos necesarios para implementar la facilidad de arrastrar y soltar (drag and drop) en una página web aprovechando las funcionalidades provistas por HTML5.  Para este desarrollo se utilizará jQuery para facilitar la implementación, sin embargo esto no es estrictamente necesario.

Establecer los elementos “arrastrables”.

El primer paso consiste en establecer cuales elementos podrán ser arrastrados, para hacer esto se les deberá agregar el atributo draggable=’true’.  En el caso del ejemplo, los elementos arrastrables son imágenes de la siguiente manera.

<img id="tool0" draggable="true" title="tool" src="img/tool0.png" alt="tool" />
<img id="tool1" draggable="true" title="tool" src="img/tool1.png" alt="tool" />
<img id="tool2" draggable="true" title="tool" src="img/tool2.png" alt="tool" />

Definir el comportamiento de los elementos “arrastrables”.

El siguiente paso es establecer que se debe hacer cuando los objetos arrastrables son manipulados, es decir, manejar sus eventos.  Estos eventos corresponden con los siguientes y su implementación se debe definir cuando la estructura de la página se encuentra completamente cargada.

 dragstart  El elemento se empieza a arrastrar.
 drag  El elemento está siendo arrastrado.
 dragend  El elemento ha dejado de ser arrastado.

Durante el manejo del evento dragstart se realizan las siguientes tareas.

  1. Almacenar la información del elemento arrastrable (su id en este caso) necesaria para ser procesado en caso de ser soltado exitosamente.
  2. Agregar una nueva clase CSS (itemSelected) para modificar su apariencia mientras es arrastrado.
  3. Modificar la imagen del elemento arrastrado la cual por defecto es la del mismo elemento.
$('.page #main #items .item').bind('dragstart', function(event) {

    // Store information about the item dragged.

    event.originalEvent.dataTransfer.setData("text/plain", event.target.getAttribute('id'));

    // Add a CSS class to highlight the dragged item.

    $(event.target).addClass('itemSelected');

    // Set an image as drag icon.  The image was preloaded.

    var dragIcon = document.createElement('img');
    dragIcon.src = 'img/hand.png';

    event.originalEvent.dataTransfer.setDragImage(dragIcon, 139, 43);
});

Durante el manejo del evento drag no se realizan tareas especiales en este caso.

$('.page #main #items .item').bind('drag', function(event) {
    // The item is being dragged!
});

Durante el manejo del evento dragend se realiza una única tarea y corresponde con retirar la clase CSS añadida durante dragstart para indicar que el elemento ya no está siendo arrastrado actualmente.

$('.page #main #items .item').bind('dragend', function(event) {

    // Remove the CSS class that highlights it while beign dragged.

    $(event.target).removeClass('itemSelected');
});

Definir el comportamiento de las “zonas de descarga”.

El paso final consiste en establecer que se debe hacer cuando los objetos arrastrables interactúan con las zonas de descarga (drop zones), es decir, manejar sus eventos.  Estos eventos corresponden con los siguientes y su implementación también se debe definir cuando la estructura de la página se encuentra completamente cargada.

 dragenter  El elemento arrastrable ha entrado a una zona de descarga.
 dragleave  El elemento arrastrable ha salido de una zona de descarga.
 dragover  El elemento arrastrable está siendo arrastrado sobre una zona de descarga.
 drop  El elemento arrastrable ha sido soltado sobre una zona de descarga.

Durante el manejo del evento dragenter se agrega una nueva clase CSS (itemOnDropArea) para modificar la apariencia de la zona de descarga mientras un elemento es arrastrado sobre ella.

$('.page #main #boxes .box').bind('dragenter', function(event) {

    // Add a CSS class to highlight the drop zone used.

    $(event.target).addClass('itemOnDropArea');

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento dragleave se realiza la tarea contraria, se remueve la clase CSS agregada durante el suceso del evento anterior para mostrar que ningún elemento es arrastrado ahora sobre la zona de descarga.

$('.page #main #boxes .box').bind('dragleave', function(event) {

    // Remove the CSS class that highlights the used drop zone.

    $(event.target).removeClass('itemOnDropArea');

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento dragover no se realiza en este caso ninguna tarea interesante además de indicarle al navegador que evite su comportamiento por defecto el cual es impedir que se realice.

$('.page #main #boxes .box').bind('dragover', function(event) {

    // Prevents the default event that denies the DnD
    // behaviour.  Acts as "event.preventDefault()" in
    // vanilla Javascript.

    return false;
});

Durante el manejo del evento drop, que sucede cuando el elemento arrastrable se suelta sobre la zona de descarga, se realizan las siguientes tareas en la aplicación de demostración.

  1. Obtener la información almacenada en el objeto dataTransfer definida durante el manejo del evento dragstart.
  2. Obtener la información del objeto arrastrable.
  3. Obtener la información de la zona de descarga.
  4. Determinar si la descarga del objeto es válida o no en la zona de descarga específica.
  5. Realizar una acción según se determine en la tarea anterior: remover el elemento o mostrar un mensaje de error.
  6. Evitar que se efectúe el comportamiento por defecto relacionado con el evento.
$('.page #main #boxes .box').bind('drop', function(event) {

	// Get the stored information about the draggable item,
	// the element ID in this case.

	var itemId = event.originalEvent.dataTransfer.getData("text/plain");

	// Get the type of the draggable item, stored in the
	// ALT attribute in this case.

	var itemType = $("#" + itemId).attr('alt');

	// Get the drop zone's ID to difference the type of it.

	var dropboxType = $(event.target).attr('id');

	// Check if the draggable item can be or not dropped
	// into the current drop zone.

	if(dropboxType == 'toolbox')
	{
		if(itemType == 'tool')
			$("#" + itemId).remove();
		else
			alert("That is a FRUIT, put it on the Fruit's Basket!");
	}

	if(dropboxType == 'fruitbasket')
	{
		if(itemType == 'fruit')
			$("#" + itemId).remove();
		else
			alert("That is a TOOL, put it on the Toolbox!");
	}

	// Remove the CSS class that highlights the used drop zone.

	$(event.target).removeClass('itemOnDropArea');

	// Prevents the default event that denies the DnD
	// behaviour.  Acts as "event.preventDefault()" in
	// vanilla Javascript.

	return false;
});

El prototipo.

En este prototipo se utilizan los fragmentos de código mostrados en este artículo, en él se muestran en la parte inferior dos series de objetos arrastrables (herramientas y frutas) y en la parte superior dos zonas de descarga (una caja de herramientas y una canasta de frutas).  La página web permitirá que el usuario arrastre los elementos a cualquiera de de las zonas de descarga, sin embargo sólo aceptará que se almacenen en la zona correcta.  En caso de intentarse hacer lo contrario se obtendrá un mensaje de error.

Prototipo de demostración de arrastrar y soltar con HTML5
Prototipo de demostración de arrastrar y soltar con HTML5

Enlaces.

Primeros pasos con PhoneGap para Android

Introducción.

PhoneGap en pocas palabras es un framework para el desarrollo de aplicaciones móviles que posibilita a los desarrolladores a que implementen sus proyectos utilizando las tecnologías estándar de web: HTML5, CSS3 y Javascript, y este las convierte a aplicaciones híbridas, es decir, aplicaciones nativas de las diferentes plataformas móviles existentes que tienen acceso a gran parte del API nativo.

Tomado de http://www.phonegap.com/
Tomado de http://www.phonegap.com/

Esto lo logra empaquetando la aplicación web original con un navegador basado en webkit para desplegarla como si fuera una aplicación verdaderamente nativa.

Actualmente este framework soporta seis de las principales plataformas móviles del mercado: iOS, Android, Blackberry, PalmOS, Windows Mobile y Symbian.  Para mas información acerca del estado actual del soporte en cada una de estas plataformas consultar las características soportadas.

Existen otros frameworks similares a este entre los que se destacan Appcelerator Titanium, Mobl y Sencha Touch de los cuales espero estar escribiendo mas adelante.

En este artículo se describirá el proceso de instalación de PhoneGap, la creación de un proyecto base para el desarrollo con este framework y la elaboración de un ejemplo simple.

Instalar PhoneGap.

Descargar la última versión disponible del framework desde la siguiente ubicación.

https://code.google.com/p/phonegap/downloads/list

Para efectos de la documentación se utilizará la versión 0.9.5.1 que corresponde con las mas reciente para esta fecha.

$ wget http://phonegap.googlecode.com/files/phonegap-0.9.5.1.zip

Se descomprime el paquete recién descargado y se mueve a su ubicación final.

$ unzip phonegap-0.9.5.1.zip

$ mkdir ~/phonegap

$ mv phonegap-0.9.5.1 ~/phonegap/0.9.5.1

Crear la plantilla base de un proyecto Android.

A continuación se relacionan los pasos que se deben realizar para crear un proyecto PhoneGap para Android utilizando Eclipse y el plugin ADT instalados anteriormente.

Iniciar Eclipse y crear un nuevo proyecto a través del menú File > New > Android Project.

Crear un nuevo proyecto Android
Crear un nuevo proyecto Android

En el diálogo de información del proyecto a crearse especificar al menos los siguientes campos y presione el botón Finish para continuar.

  1. Nombre del proyecto (project name).
  2. API de Android a utilizarse (build target).  En este caso se utilizará el API 2.2.
  3. Nombre de la aplicación (application name).
  4. Crear una actividad (create activity).
Información básica del proyecto Android
Información básica del proyecto Android

En el Explorador de Paquetes (package explorer)  de Eclipse crear bajo el proyecto una carpeta /assets/www y otra /libs.

Copiar en la carpeta /assets/www el archivo phonegap.0.9.5.1.js y copiar en /libs el archivo phonegap.0.9.5.1.jar.  Ambos archivos se encuentran bajo el directorio ~/phonegap/0.9.5.1/Android creado durante el paso de instalación anterior.

Estructura del proyecto Android
Estructura del proyecto Android

Hacer clic derecho sobre el directorio /libs y seleccionar el menú Build Path > Configure Build Path… Allí en la pestaña Libraries agregue la referencia a /libs/phonegap.0.9.5.1.jar presionando el botón Add JARs…

Agregar al proyecto la referencia al JAR de PhoneGap.
Agregar al proyecto la referencia al JAR de PhoneGap.

Realizar las siguientes modificaciones al código fuente de la actividad.  Este archivo se ubica bajo la carpeta /src del proyecto (/src/com.jimezam.phonegap.demo/App.java en este caso).

  1. Reemplazar la línea 3 (import android.app.Activity;) con la siguiente: import com.phonegap.*;
  2. En la línea 6 cambiar la superclase de App de Activity a DroidGap.
  3. Reemplazar la línea 11 (setContentView(R.layout.main);) con la siguiente: super.loadUrl(“file:///android_asset/www/index.html”);
Modificaciones a la actividad inicial.
Modificaciones a la actividad inicial.

Hacer clic derecho sobre el archivo AndroidManifest.xml y seleccionar el menú Open With… > Text Editor.  A este documento realizar las siguientes modificaciones.

1. Agregar el siguiente texto entre la apertura de la etiqueta <manifest> y la apertura de la etiqueta <application>.

<supports-screens
android:largeScreens=”true”
android:normalScreens=”true”
android:smallScreens=”true”
android:resizeable=”true”
android:anyDensity=”true”
/>
<uses-permission android:name=”android.permission.CAMERA” />
<uses-permission android:name=”android.permission.VIBRATE” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_LOCATION_EXTRA_COMMANDS” />
<uses-permission android:name=”android.permission.READ_PHONE_STATE” />
<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.RECEIVE_SMS” />
<uses-permission android:name=”android.permission.RECORD_AUDIO” />
<uses-permission android:name=”android.permission.MODIFY_AUDIO_SETTINGS” />
<uses-permission android:name=”android.permission.READ_CONTACTS” />
<uses-permission android:name=”android.permission.WRITE_CONTACTS” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />

2. Agregar el siguiente atributo a la etiqueta <activity>.

android:configChanges=”orientation|keyboardHidden”

Modificaciones al documento AndroidManifest.xml.
Modificaciones al documento AndroidManifest.xml.

Finalmente crear el archivo /assets/www/index.html con el código fuente para la demostración.

<!DOCTYPE HTML>
<html>
<head>
<title>PhoneGap demostration with Android</title>
<script type=”text/javascript” charset=”utf-8″ src=”phonegap.js”></script>
</head>
<body>
<h1>Hello Android’s World with PhoneGap</h1>
</body>
</html>

Ejecutar el proyecto en el emulador.

Seleccionar el menú Run > Run As > Android Application.

Ejecutar como aplicación Android.
Ejecutar como aplicación Android.

Estos son un par de ejemplos de aplicaciones web simples ejecutándose con PhoneGap en el emulador de Android.

Hola Mundo web con Android
Hola Mundo web con Android

The Simple List 0.1
The Simple List 0.1

Enlaces.

Experimentando con jQuery Mobile: The Simple List 0.1

Introducción.

Después de experimentar con jQTouch durante la implementación de un prototipo de aplicación para el 6CCC, me ha tomado unas cuantas horas para elaborar un nuevo prototipo de aplicación web móvil, esta vez utilizando jQuery Mobile como framework para el nivel de presentación.

Su uso es muy similar al visto anteriormente, sin embargo considero que este proyecto cuenta con mejor documentación que el primero.  Ambos se basan en la mejora progresiva (Progresive Enhancement) y en la degradación aceptable (Graceful degradation) lo que los hace fáciles de entender por parte de los desarrolladores que estén habituados al uso de HTML/CSS/Javascript.

El prototipo.

Esta aplicación permite administrar una lista simple de elementos al estilo de las cosas por hacer.  La idea con este prototipo es el experimentar el uso del framework jQuery Mobile.

Para la persistencia se utiliza la facilidad del LocalStorage provisto por HTML5 y que es soportado por los navegadores web modernos incluyendo los incorporados en los sistemas operativos de los dispositivos móviles.

Estas son a grandes razgos las funcionalidades y flujos de información del prototipo.

The Simple List 0.1
The Simple List 0.1

 

Estas son algunas de las pantallas (page) de la aplicación web.

El prototipo puede probarse en línea a través de la web (ver sección de enlaces) y ya que su código fuente se encuentra completamente documentado, servirá también como ejemplo práctico para quienes estén interesados en aprender a desarrollar utilizando este framework web.

Enlaces.