Crear aplicaciones para Firefox OS utilizando AngularJS

30 junio, 2015 4:28 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks. Traducción por Marisol García Obando.

Cuando comienzas a desarrollar para Firefox OS podrías decepcionarte de las herramientas que se te proporcionan. No hay juego de herramientas de interfaz de usuario estándar o un framework de JavaScript en la que todas las aplicaciones se basen. Esta no es una situación específicamente mala porque en esencia Firefox OS es la web; y así se da una completa libertad en las herramientas que se utilizan. Esto nos da la ventaja de usar cualquier tecnología nueva que aparezca también en Firefox OS. La desventaja es que te pierdes en cosas que podrían ser utilizadas para Android o iOS, como plantillas incorporadas, transición de vistas y componentes de interfaz de usuario.

En Telenor Digital decidimos construir un marco de aplicación listo para salir (ready-to-go) que se ocupa de estas deficiencias, construido sobre AngularJS, el framework MVW de Google. La plantilla es el resultado de la iteraciones en nuestras aplicaciones internas construidas para Firefox OS, y permite lo siguiente:

  1. Construir sobre AngularJS, lo cual proporciona vínculos de datos, de plantillas, rutas y estructura de código.
  2. Construir en el conjunto de componentes de interfaz de usuario  y transiciones, en el estilo de Firefox OS.
  3. Capacidad para publicar aplicaciones como una página web para móviles (hosted app), o como un paquete de aplicaciones para el Marketplace de Firefox OS.
  4. Acceso fuera de línea. Toda aplicación construida con la plantilla trabaja sin conexión, y incluso cuando está alojada en un servidor web propio.
  5. Un sistema de construcción para crear versiones con un comando, incluyendo minificación y caché de plantilla para un óptimo desempeño.

Echemos un vistazo a cómo luce la demostración de la aplicación. Es una aplicación estándar CRUD que muestra un un patrón de lista detallada: http://janjongboom.com/ffos-list-detail/. Puedes hacer click sobre el ítem para ver el detalle, editarlo o añadir nuevos ítems. El botón “+” es un botón de instalación (solo visible en Firefox) y permite añadir la aplicación a tu teléfono (Android / FxOS).

Demo lista detallada
Obtener el código

Para comenzar a construir, haz esto:

  • git clone git@github.com:comoyo/ffos-list-detail.git
  • npm install
  • ./node_modules/bower/bin/bower install
  • Ahora puedes abrir www/index.html en cualquier navegador, o usar el gestor de aplicaciones y añadir el directorio www como un paquete de aplicación.

Estructura

La aplicación se aloja en el directorio www/ y se compone de los siguientes subdirectorios:

  • components/, esta es una biblioteca de terceros, cargada mediante bower
  • css/, hojas de estilos. List todos los estilos utilizados por la aplicación en css/main.css. Estos serán combinados en una sola hoja de estilos, para un funcionamiento óptimo.
  • img/, mantiene los iconos de la aplicación en tres formatos.
  • js/, nuestro código
    • controllers/, el código que une los datos con la interfaz de usuario
    • lib/, bibliotecas externas que no están en brower
    • services/, proveedores de datos o código que no están unido a la interfaz de usuario
    • app.js, punto de la aplicación inicial, contiene configuraciones globales como rutas
    • main.js, archivo de arranque basado en RequireJS. Lista todas las carpetas JavaScript que usamos. Cuando creas una nueva carpeta JS, la añades aquí.
  • views/, vista de plantillas
  • index.html, archivo de arranque donde cargamos la aplicación. Es probable que nunca tendrás que tocar esto.
  • manifest.appcache, archivo AppCache. Tendrás que hacer la lista de todas las imágenes y otros recursos (que no sean CSS/JS) que necesita tu aplicación, para permitir que las aplicaciones alojadas funcionen sin conexión.
  • manifest.webapp, archivo App manifest de Firefox OS.

No necesitas ninguna herramienta de construcción configurada durante el desarrollo, puedes simplemente editar los archivos en www, y actualizar el index.html a voluntad. Ese es el poder de la web 🙂 Por supuesto, si estás desarrollando en el administrador de aplicaciones, pulsa Actualizar para actualizar la aplicación.

Ahora vamos a añadir algunas nuevas funciones a esta aplicación, para ver cómo el desarrollo de nuevas características funciona en la práctica.

Añadir un nuevo botón

Digamos que queremos añadir una pantalla de créditos que muestra quien construyó la aplicación. Lo primero que tenemos que hacer es añadir un botón en alguna parte. En nuestro caso vamos a ponerlo en la pantalla principal de la aplicación. El código de la vista está en www/views/list.html.

Los componentes que se ven provienen de el  Firefox OS Building Blocks, que son los mismos bloques que se utilizan para construir el propio Firefox OS. Vamos a añadir un nuevo botón en la parte inferior de la pantalla, por debajo de </ul> y de </section>:

Credits

Aquí es importante el atributo ng-tap. Cuando presionamos este ítem vamos al URL /credits, con animación popup. Hay soporte para cuatro animaciones: forward, backward, popup y popdown; pero puedes crearla por tu cuenta utilizando simplemente CSS.

Ahora, cuando vemos esto no parece todavía un botón, porque aún necesitamos el bloque de construcción (Building Block) de botón. Debemos ir a css /main.css y añadir la siguiente línea para que se vea bonito:

@import url("../components/building-blocks/style/buttons.css");

Botón de créditos

Todo esto está documentado en la página del sitio web de Building Blocks.

Conectándolo

Cuando hacemos clic en el botón no sucede nada (bueno, nos redirecciona de vuelta a la vista de lista), y eso es porque no escuchamos la URL /credits aún. Para arreglar esto tenemos que crear un controlador de ruta (como en cualquier estructura de servidor MV*). Abre la lista de rutas en js/app.js, y agrega un controlador para la URL de créditos (antes del controlador otherwise):

.when('/credits', {
  templateUrl: 'views/credits.html',
  controller: 'CreditsCtrl'
})

Aquí le decimos qué controlador queremos consultar (con código JS), y que vista (con HTML) pertenece a este. Vamos a crear la vista primero. Añade un nuevo archivo llamado credits.html en el directorio views.

back

Credits

This application is made by {{ name }}.

Para el estilo de esta vista podemos añadir algún contenido en css/app.css, por ejemplo añadir un poco de relleno y hacer el texto más grande:

.view.credits {
  padding: 1.5rem;
  font-size: 2rem;
}

Ahora escribe un sencillo controlador para rellenar el contenido de {{ name }}, utilizando el enlace de datos estándar de AngularJS. Añade un nuevo archivo llamado credits.js en www/js/controllers:

/* We use RequireJS AMD style modules to get a reference to the app object */
define(['app'], function(app) {
  /* Tell that we're defining a controller with name
    CreditsCtrl, and with dependencies on $scope, we specify this as string
    to not break when minifying
  */
  app.controller('CreditsCtrl', ['$scope',
    /* Implementation. AngularJS does dependency injection to fill the $scope var */
    function CreditsCtrl($scope) {
      /* Data binding to the view */
      $scope.name = 'Your name';
    }
  ]);
});

Lo último es decirle a RequireJS que tenemos un nuevo archivo JS que necesitamos incluir en nuestra construcción, editando js/main.js y añadiendo una línea sobre 'js/controllers/edit.js':

'js/controllers/credits.js'

Ahora cuando hacemos clic en el botón de la aplicación, todo funciona como lo esperábamos. La vista aparece, tenemos datos, y podemos cerrarla haciendo clic en el botón de atrás. Lo que también es genial es que cuando enviamos la URL a otra persona (por ejemplo http://tu/url/index.html#/credits) van a la vista de los créditos por defecto. Esto se debe a que hacemos un manejo adecuado de estado de URLs por defecto.

Hablando con una fuente de datos de terceros

La aplicación actualmente sólo habla de datos estáticos, por lo que queremos conectarla a una fuente de datos real. En nuestro caso la lista de proyectos debe provenir de la página de GitHub con proyectos realizados por mozilla-b2g. Tienen una API en: https://api.github.com/users/mozilla-b2g/repos.

AngularJS tiene una idea de servicios, que abstrae esos datos fuera del controlador. Para esta aplicación tenemos un servidor de base de datos que actualmente devuelve datos de memoria. Podemos modificar el servidor para comunicar con un servidor web en su lugar. Despeja www/js/services/database.js y reemplaza el contenido con:

/*global define */
"use strict";
define(['app'], function(app) {
  /* Add a new factory called database, with a dependency on http */
  app.factory('database', ['http', function(http) {
    var getItems = function() {
      /* getItems makes a HTTP get call to github */
      return http.get('https://api.github.com/users/mozilla-b2g/repos', {
        // this is the cache configuration, we want to always cache requests
        // because it gives better UX. Plus when there is no internet, we can
        // get the data from cache and not break for the user...
        idbCache: {
          cacheKey: 'api.index',
          // expiration time in ms. from now (this is 5 minutes)
          // This is only obeyed if there is an internet connection!
          expiresInMs: 5 * 60 * 1000
        }
      }).then(function(res) {
        // Format it, sort it and map it to have the same format as our previous in mem dataset
        return res.data.sort(function(a, b) {
          return a.stargazers_count < b.stargazers_count;
        }).map(function(item) {
          return {
            title: item.name,
            description: item.description,
            id: item.name
          };
        });
      });
    };
 
    // Similar story but now for just one item
    var getItemById = function(id) {
      return http.get('https://api.github.com/repos/mozilla-b2g/device-flatfish', {
        idbCache: {
          cacheKey: 'api.detail.' + id,
          expiresInMs: 10 * 60 * 1000
        }
      }).then(function(res) {
        var repo = res.data;
        return {
          title: repo.name,
          description: repo.description,
          id: repo.name,
          date: new Date((repo.pushed_at || "").replace(/-/g,"/").replace(/[TZ]/g," "))
        };
      });
    };
 
    return {
      getItems: getItems,
      getItemById: getItemById
    };
  }]);
});

Esta API es ahora sin embargo asincrónica, pero eso no importa para Angular. Si enlazas tus datos a una promesa (Promise), Angular esperará hasta que la promesa se resuelva para hacer el enlace de datos.

Lo bueno de esto es que ahora cuando no hay conección de internet, los datos todavía cargan (siempre y cuando se hayan cargado una vez), y los datos están en caché automaticamente. El controlador no necesita preocuparse por esto.

Publicar la aplicación

Estas son dos maneras rápidas de añadir algunas funciones a esta aplicación. En primer lugar, la adición de un nuevo botón y una nueva vista; y segundo, mostrando enlace de datos y almacenamiento en caché sin conexión de datos al servidor. Teniendo en cuenta que esta plantilla de aplicación se puede utilizar para mucho más que solo aplicaciones de listas detalladas, ¡tienes todo el poder de AngularJS en tus manos!

Ahora, cuando queremos compartir esta aplicación con el resto del mundo, podemos ir en dos direcciones:

  • Crear una aplicación alojada. Esta es una aplicación que vive en su propio servidor, como cualquier sitio web para móviles. Las aplicaciones alojadas todavía se pueden publicar en el mercado, y trabajará fuera de línea, pero no pueden utilizar todas las APIs en Firefox OS, debido a las limitaciones de seguridad.
  • Crear una aplicación empaquetada. Este es un archivo ZIP, similares a los archivos APK en Android, que contienen todos los activos de su aplicación, y se distribuyen a través del Marketplace.

Ambas aplicaciones se pueden generar utilizando nuestro script de construcción. La secuencia de comandos creará una nueva carpeta dist/ que tiene todos los archivos que necesitan las aplicaciones. Si deseas publicar la aplicación para un servidor propio, es simplemente copiar el contenido de la carpeta. Si deseas publicar la aplicación como una aplicación empaquetada, comprime el contenido y publica en el Marketplace.

Para construir y ejecutar:

  • Unidades: node build.js
  • Alojado: node build.js appcache

¡Feliz codificación!

The following two tabs change content below.

jorgev

AMO Product Manager at Mozilla
Jorge trabaja para el equipo de complementos de Mozilla, y se dedica a Mozilla Hispano y Mozilla Costa Rica en su tiempo libre. Actualmente está encargado del blog de Mozilla Hispano Labs.

Compartir artículo:

  • ¡Participa!

    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa