Participe da Maratona Behind the Code! Prêmios e desafios incríveis te esperam, não perca! Inscreva-se aqui

Criar Aplicativos da Web Offline em Dispositivos Móveis com o HTML5

Introdução

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.

Figura 1. Principais elementos de um aplicativo da web offline

alt

  • 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.

Figura 2. Visualização do iPhone

alt

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.

Figura 3. Visualização do Palm Pre

alt

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.

Listagem 1. Código HTML

<!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:

Listagem 2. Arquivo de manifesto

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.

Listagem 3. Código de inicialização JavaScript

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.

Listagem 4. Código de visão geral do JavaScript

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.)

Listagem 5. Código de atualização do JavaScript

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.

Listagem 6. Código de seleção do JavaScript

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.

Listagem 7. Código de manipulador do JavaScript

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.

Listagem 8. Código de utilitário do JavaScript

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

OfflineWebAppSrc.zip: Código fonte para este artigo

Aviso

O conteúdo aqui presente foi traduzido da página IBM Developer US. Caso haja qualquer divergência de texto e/ou versões, consulte o conteúdo original.