Desenvolvimento

22 nov, 2012

Criar aplicativos da Web Offline em dispositivos móveis com o HTML5

Publicidade

O uso do desenvolvimento da web em aplicativos remotos é uma tendência crescente. No entanto, a disponibilidade intermitente da rede é um grande obstáculo no uso da tecnologia da web como parte de uma infraestrutura em nuvem. Um aplicativo da web tradicional simplesmente não funciona sem uma rede. Uma solução para esse problema é utilizar dois recursos do Padrão HTML5 (consulte Recursos):

  • Aplicativos da web offline;
  • Armazenamento do banco de dados do lado do cliente.

O usuário pode utilizar funções em nuvem em um dispositivo móvel, trabalhar offline com um aplicativo implementado localmente em um banco de dados e compartilhar dados com o resto da nuvem quando voltar a ficar online.

Neste artigo, aprenda os detalhes técnicos para um cenário de uso típico. Um protótipo de um aplicativo de gerenciamento de inventário simples demonstra a tecnologia HTML5.

Faça o download do código fonte para o aplicativo de exemplo neste artigo a partir da tabela Download abaixo.

Visão geral

A Figura 1 mostra uma visão geral dos principais componentes da arquitetura do aplicativo de amostra.

  • Página HTML – A página HTML, o núcleo do aplicativo, possui a função do modelo. Ela contém os dados exibidos e as informações de renderização (padrão). Os elementos do HTML da página são organizados em uma hierarquia da árvore do Modelo de Objeto de Documento (DOM) do HTML. Eventos iniciados pelo usuário causam um ciclo de resposta à solicitação convencional, com o carregamento de uma página e a execução das funções JavaScript associadas.Notavelmente, esse aplicativo consiste em uma única página HTML sem a necessidade do carregamento de mais páginas HTML por meio de ciclos de resposta à solicitação. Toda a ação encontra-se em uma página.
  • JavaScript – O elemento JavaScript contém as funções do controlador do aplicativo. Os elementos HTML são ligados às funções JavaScript por meio de manipuladores de eventos. O JavaScript pode acessar a árvore do DOM do HTML do aplicativo com todos os elementos da interface com o usuário (IU) e utilizá-la como entrada de dados para cálculo. Os resultados do processamento podem ser apresentados ao usuário modificando a página HTML.
  • Folha de Estilo em Cascata – A Folha de Estilo em Cascata (CSS) descreve como a página HTML é renderizada. A tarefa de visualização é omitida para simplificar a solução. Nesse estágio da expansão, somente o comportamento de renderização padrão dos elementos HTML é utilizado.Para dispositivos móveis, há várias bibliotecas e estruturas JavaScript/CSS para fornecer uma experiência do usuário praticamente nativa com aplicativos da web (por exemplo, iUi para iPhone). Consulte Recursos para mais informações. Embora seja necessário aumentar a aceitação do usuário, essa abordagem possui a desvantagem da dependência da plataforma.
  • Banco de dados – O padrão HTML5 apresentou o armazenamento de banco de dados local. Ele é implementado em versões atuais do navegador Safari da Apple® . O navegador oferece um banco de dados integrado, com SQLite, que pode ser acessado a partir do JavaScript ao processar consultas de SQL. Os dados de negócios do modelo do aplicativo são armazenados aqui.
  • Manifesto – O arquivo de manifesto é o componente do descritor de implementação obrigatório para um aplicativo da web offline. Ele simplesmente lista todos os campos que precisam ser carregados.

Aplicativo de amostra

Esta seção oferece uma visão geral do aplicativo de amostra, denominado MyHomeStuff. É um simples aplicativo de gerenciamento de inventário que possibilita manter o controle dos itens de sua propriedade. A Figura 2 mostra o aplicativo no iPhone.

Para fins de simplicidade, a sincronização dos dados com o servidor é omitida. A Figura 3 mostra o aplicativo de gerenciamento de inventário MyHomeStuff no navegador da web do Palm Pre.

A lista da parte superior da tela oferece uma visão geral de todos os itens inseridos (livros, computador, entre outros).

Quando um usuário seleciona um item na lista, seus detalhes (Id, Qty, Name) são exibidos no meio do formulário. Eles podem ser alterados utilizando o botão update. O item selecionado também pode ser excluído do aplicativo utilizando o botão delete. Novos itens podem ser criados inserindo a quantidade e o nome do item no formulário e selecionando o botão create.

O Status do aplicativo é exibido na parte inferior da tela.

Detalhes do HTML

A página HTML contém declarações, meta tags para uma exibição móvel otimizada, referências a arquivos externos (manifesto, JavaScript, css) e elementos HTML fundamentais, que formam a estrutura básica do aplicativo. A Listagem 1 mostra o código.

<!DOCTYPE HTML>
<html manifest="MyHomeStuff.manifest">
<head>
<meta name="viewport" content="width=device-width;
initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<title>MyHomeStuff</title>
<script type="text/javascript" src="MyHomeStuff.js" ></script>
</head>
<body onload="onInit()">
<h3>Overview</h3>
<ul id="itemData" ></ul>
<h3>Details</h3>
<form name="itemForm">
<label for="id">Id: </label>
<input type="text" name="id" id="id" size=2 disabled="true"/>
<label for="amount">Amount: </label>
<input type="text" name="amount" id="amount" size = 3/>
<label for="name">Name: </label>
<input type="text" name="name" id="name" size=16 /> <br>
<br>
<input type="button" name="create" value="create"
onclick="onCreate()" />
<input type="button" name="update" value="update"
onclick="onUpdate()" />
<input type="button" name="delete" value="delete"
</form>
<h4>Status</h4>
<div id="status"></div>
</body>
</html>

Os atributos do manipulador de eventos dos elementos HTML especificam quais funções JavaScript são executadas quando a página é inicialmente carregada (onload) e os elementos do botão são clicados (onclick).

A página HTML de um aplicativo da web offline começa com a tag <!DOCTYPE HTML>. O manifesto é referenciado por meio do atributo do manifesto na tag <html manifest="MyHomeStuff.manifest">.

Como mencionado, o manifesto especifica os arquivos necessários que precisam ser carregados no cache. Esse aplicativo consiste em um arquivo HTML e um JavaScript. O arquivo HTML com a referência ao manifesto é automaticamente incluído no cache do aplicativo. O manifesto contém somente:

CACHE MANIFEST

MyHomeStuff.js

Detalhes do JavaScript

O código JavaScript consiste em três blocos principais:

  • Funções de inicialização
  • Funções db (crud) e de atualização da visualização
  • Algumas pequenas funções de utilitário

O primeiro bloco contém o manipulador de eventos para inicializar o aplicativo (onload) e a inicialização do banco de dados, como mostra a Listagem 3.

function onInit(){
try {
if (!window.openDatabase) {
updateStatus("Error: DB not supported");
}
else {
initDB();
createTables();
queryAndUpdateOverview();
}
}
catch (e) {
if (e == 2) {
updateStatus("Error: Invalid database version.");
}
else {
updateStatus("Error: Unknown error " + e + ".");
}
return;
}
}

function initDB(){
var shortName = 'stuffDB';
var version = '1.0';
var displayName = 'MyStuffDB';
var maxSize = 65536; // in bytes
localDB = window.openDatabase(shortName, version, displayName, maxSize);
}

No código acima:

  • A função onInit primeiro verifica a existência da função obrigatória openDatabase , cuja falta sinaliza que o navegador não suporta um banco de dados local;
  • A função initDB abre o banco de dados do navegador HTML5;
  • Depois da abertura bem-sucedida do banco de dados, a SQL DDL para criar a tabela de banco de dados é executada. Finalmente, as funções que consultam os registros existentes e preenchem a página HTML com os dados são chamadas.

Cada função do segundo bloco do JavaScript possui uma parte para acesso do DB e lógica de apresentação. Essa consolidação da lógica é característica de uma arquitetura Modelo 1 (consulte Recursos), que é a forma mais fácil de desenvolver aplicativos da web simples. Para um cenário real, uma arquitetura com uma separação clara das partes do Model View Controller (MVC) seria apropriada.

Para criar a lista de visão geral do exemplo, a função queryAndUpdate é chamada a partir das funções do manipulador de eventos. A Listagem 4 mostra o código.

function queryAndUpdateOverview(){

//remove old table rows
var dataRows = document.getElementById("itemData").getElementsByClassName("data");
while (dataRows.length > 0) {
row = dataRows[0];
document.getElementById("itemData").removeChild(row);
};

//read db data and create new table rows
var query = "SELECT * FROM items;";
try {
localDB.transaction(function(transaction){

transaction.executeSql(query, [], function(transaction, results){
for (var i = 0; i < results.rows.length; i++) {

var row = results.rows.item(i);
var li = document.createElement("li");
li.setAttribute("id", row['id']);
li.setAttribute("class", "data");
li.setAttribute("onclick", "onSelect(this)");

var liText =
document.createTextNode(row['amount'] + " x "+ row['name']);
li.appendChild(liText);

document.getElementById("itemData").appendChild(li);
}
}, function(transaction, error){
updateStatus("Error: " + error.code + "<br>Message: " + error.message);
});
});
}
catch (e) {
updateStatus("Error: Unable to select data from the db " + e + ".");
}
}

No código acima:

  • Os dados antigos são removidos da árvore do DOM;
  • Uma consulta para selecionar todos os conjuntos de dados é executada;
  • Para cada conjunto de dados no resultado, um elemento da lista de HTML é criado e anexado a ela;
  • Um manipulador de eventos, onSelect, é incluído a cada elemento da lista para responder a um clique.

As funções desse bloco também contêm o manipulador de eventos para a barra de botões e a lista com onUpdate, onDelete, onCreate e onSelect. A Listagem 5 mostra o código para onUpdate. (onCreate e onDelete possuem uma estrutura semelhante, por isso, não são mostrados aqui; é possível fazer o download de todo o código fonte para o aplicativo de exemplo da tabela abaixo.)

function onUpdate(){
var id = document.itemForm.id.value;
var amount = document.itemForm.amount.value;
var name = document.itemForm.name.value;
if (amount == "" || name == "") {
updateStatus("'Amount' and 'Name' are required fields!");
}
else {
var query = "update items set amount=?, name=? where id=?;";
try {
localDB.transaction(function(transaction){
transaction.executeSql(query, [amount, name, id],
function(transaction, results){
if (!results.rowsAffected) {
updateStatus("Error: No rows affected");
}
else {
updateForm("", "", "");
updateStatus("Updated rows:"
+ results.rowsAffected);
queryAndUpdateOverview();
}
}, errorHandler);
});
}
catch (e) {
updateStatus("Error: Unable to perform an UPDATE " + e + ".");
}
}
}

No código acima:

  • Os valores do campo do formulário são lidos e validados;
  • Se os valores forem válidos, a consulta de atualização será executada;
  • O resultado da consulta é exibido na página HTML atualizada.

A função onSelect é executada quando o usuário seleciona um elemento da lista. O formulário de detalhes será preenchido com os dados desse elemento utilizando o código da Listagem 6.

function onSelect(htmlLIElement){
var id = htmlLIElement.getAttribute("id");
query = "SELECT * FROM items where id=?;";
try {
localDB.transaction(function(transaction){

transaction.executeSql(query, [id], function(transaction, results){

var row = results.rows.item(0);

updateForm(row['id'], row['amount'], row['name']);

}, function(transaction, error){
updateStatus("Error: " + error.code + "<br>Message: " + error.message);
});
});
}
catch (e) {
updateStatus("Error: Unable to select data from the db " + e + ".");
}
}

No código acima:

  • O ID do elemento selecionado é determinado;
  • Uma consulta de seleção é executada;
  • Uma função para atualizar o formulário de detalhes com o conjunto de dados de leitura é chamada.

O último bloco JavaScript com funções de utilitário começa com manipuladores de dados, necessários como parâmetros para as consultas.

errorHandler = function(transaction, error){
updateStatus("Error: " + error.message);
return true;
}

nullDataHandler = function(transaction, results){
}

Para evitar redundância, as funções de utilitário preenchem os campos do formulário de detalhes (updateForm) e da mensagem de status (updateStatus), como mostra abaixo.

function updateForm(id, amount, name){
document.itemForm.id.value = id;
document.itemForm.amount.value = amount;
document.itemForm.name.value = name;
}

function updateStatus(status){
document.getElementById('status').innerHTML = status;
}

Implementação

Um iPhone 3GS e um Palm Pre foram utilizados para executar o exemplo em um dispositivo móvel HTML5 real. Um navegador Safari atual em um computador também funciona.

É possível fazer o download e implementar os arquivos para o aplicativo em um servidor HTTP a partir da tabela Downloads abaixo. O arquivo de manifesto deve ser atendido pelo servidor HTTP com o tipo Mime text/cache-manifest . Depois de abrir o aplicativo no iPhone, salve o Marcador e fique no modo offline Avião. O aplicativo será aberto quando o marcador for selecionado e funciona sem uma rede.

Resumo

O foco deste artigo foi o ponto de vista técnico para aplicativos da web offline. Um protótipo de um aplicativo de gerenciamento de inventário simples demonstrou a tecnologia HTML5 com um aplicativo implementado localmente e um banco de dados local.

Download

Descrição Nome Tamanho Método de download
Source code for this article OfflineWebAppSrc.zip 3KB HTTP

Informações sobre métodos de download

Recursos

Aprender

Obter produtos e tecnologias

Discutir

  • My developerWorks: Comunique-se com outros usuários do developerWorks e explore os blogs, fóruns, grupos e wikis voltados para desenvolvedores.

***

Sobre o autor: Dietmar Krueger trabalha para o Application Innovation Services, uma Linha de Serviço do IBM Global Business Services. Ele desenvolveu softwares orientados a objetos por 17 anos. Dietmar é apaixonado pelo desenvolvimento de software ágil, arquiteturas leves e linguagens de programação de tipo dinâmico.

***

Artigo original disponível em: http://www.ibm.com/developerworks/br/library/wa-offlineweb/index.html