PhoneGap e Cordova
Com a expansão tecnológica nos últimos anos, precisamente em meados do ano de 2007 com o surgimento do iPhone da Apple e logo em seguida o Android da Google, o mundo conheceu uma nova maneira de se comunicar, interagir, trabalhar, ensinar, pesquisar e divertir através de aplicativos mobile presentes em smartphones, tablets entre outros dispositivos que são compatíveis com essa tecnologia. Hoje mais de um bilhão de pessoas já utilizam. Isso também repercutiu no que se refere a novas visões estratégicas de negócios em diversos setores.
Mas o que vem chamando atenção é que a maioria dos aplicativos móveis desenvolvidos e publicados nas lojas (Google Play, Apple Store ou Windows Market Place) segue a mesma premissa: desenvolvido em plataforma nativa com necessidade de conexão com a internet para funcionar.
Essa é uma forma muito tendenciosa em propor soluções, tornando-se na maioria das vezes um ciclo vicioso no desenvolvimento de aplicativos móveis. E que muitas vezes não seria a melhor forma para inovar ou solucionar a necessidade do negócio em si.
Esse artigo apresenta uma solução que foge do habitual. Será apresentada uma solução mobile offline e híbrida. Offline para atender negócios que não têm a possibilidade de acessar a internet, e híbrido para que seja codificado uma vez e disponibilizado em qualquer dispositivo, independentemente de seu sistema (Android, iOS ou Windows Phone).
Isso é possível codificando a aplicação com HTML5, JavaScript em conjunto com a API Cordova PhoneGap a qual é capaz de tornar esse código (HTML5 e JavaScript) híbrido. O Cordova PhoneGap constrói o projeto na plataforma nativa que desenvolvedor escolher.
Apps híbridos
O conceito clássico de híbrido refere-se no ato de misturar. Na mistura de dois ou mais elementos diferentes o resultado é a oposição da ordem natural das coisas. Os aplicativos mobile híbridos surgiram a partir desse conceito, entre a junção do nativo e da web.
A utilização das linguagens de programação da web, como HTML5 e Java Script, e o empacotamento no formato nativo resulta em um aplicativo que vai funcionar em plataformas diferentes. Hoje em dia uma grande quantidade de soluções mobile gira em torno de aplicativos híbridos, pois o conceito de escrever uma vez e rodar em qualquer plataforma torna esse modelo bastante utilizado no desenvolvimento.
Aplicativos híbridos vão funcionar da mesma maneira como os aplicativos nativos, contudo:
- São baseados em HTML5, CSS3 e JavaScript, sendo essas as principais tecnologias;
- Exige um menor custo no desenvolvimento comparado com os nativos, isso por manter um código fonte apenas não precisando desenvolver um código para cada plataforma;
- Para aplicar atualizações periódicas nos aplicativos, há uma enorme vantagem sobre as nativas, aplicando a atualização uma única vez.
Outro ponto fundamental é que existe uma enorme gama de frameworks que seguem a filosofia híbrida: jQuery Mobile com PhoneGap, Sencha Touch, Titanium, ZeptoJS, etc. Esses frameworks oferecem uma suíte de componentes prontos os quais agilizam o desenvolvimento do aplicativo.
HTML5
O HTML5 chegou com intuito de suprir as necessidades do desenvolvimento web moderno. Os aplicativos mobile são os principais protagonistas que utilizam essa linguagem. Ele que permite as apps se portarem como apps nativa.
O principal recurso para esse fim é o armazenamento de variáveis e de bases de dados embarcados no dispositivo através do Local Storage e do WebSQL:
- Local Storage: o armazenamento é temporário, formado por par (chave / valor), permanecendo até que a sessão esteja ativa;
- WebSQL: a forma de armazenamento segue as especificações web de banco de dados SQL, o qual oferece toda estrutura já conhecida pela maioria dos desenvolvedores como tabelas, chaves primarias, e chaves estrangeiras.
O Web SQL permite que o aplicativo mantenha os dados armazenados dentro do dispositivo sem necessidade de acesso à internet.
JavaScript
É uma linguagem de scripts (trechos de códigos) para web, totalmente dependente de um browser. É integrada nas páginas HTML do lado cliente sendo utilizada principalmente para manipular informações e objetos de uma página HTML.
Ela é carregada junto com a página web, sendo uma linguagem interpretada que não tem a necessidade de nenhum compilador e também é de fraca tipagem (a declaração de variáveis não necessita informar um tipo como String, int, double, etc.).
Nos primórdios de sua existência foi uma linguagem duramente criticada pela falta de segurança, ausência de logs de erros e por sua baixa produtividade no desenvolvimento. Mas hoje o JavaScript tornou-se uma linguagem imprescindível e de extrema utilidade no desenvolvimento web. Ela pode ser considerada a principal linguagem para o desenvolvimento de apps mobile híbridos.
Não existe outra maneira de tornar seu aplicativo móvel híbrido sem pensar em JavaScript, sendo esta a única tecnologia que todas as plataformas nativas suportam. Além disso, existe hoje no mercado inúmeros frameworks que facilitam o desenvolvimento em JavaScript como jQuery, Angular, XTJS, Backbone, etc.
Cordova PhoneGap
É um framework para o desenvolvimento mobile que permite construir aplicativos para dispositivos móveis usando JavaScript, HTML5 e CSS3. Ele torna possível realizar a transferência do código para a sua plataforma nativa (Android, iOS e Windows Phone), ou seja, o resultado de seu uso é um aplicativo mobile híbrido.
O núcleo do PhoneGap é composto por HTML5 e CSS para renderização e JavaScript para a lógica de negócio e programação. O HTML5 provê todo acesso aos hardwares nativos do dispositivo usando uma interface de função externa (FFI - Foreign Function Interface), sendo este um mecanismo que permite chamar funções e serviços escritos em outra linguagem de programação.
O PhoneGap também pode ser estendido com plugins nativos, o que permite ao desenvolvedor acessar as funções nativas dos dispositivos. Um plug-in são trechos de código que fornecem uma interface para componentes nativos do dispositivo móvel. Ao projetar um aplicativo híbrido que tem a necessidade de acessar recursos como câmera, coordenadas geográficas, tipo de conexão com a internet, informações sobre o dispositivo móvel (modelo, fabricante, uuid, etc.), base de dados (storage), deverá ser adicionado um plugin Cordova no projeto para isso. Hoje o Cordova Phonegap conta com aproximadamente 642 plugins disponíveis para uso que podem ser encontrados na documentação oficial do PhoneGap.
Segurança do Cordova Phonegap (Security)
Este tópico apresenta informações sobre algumas características e recursos que o desenvolvedor deve utilizar para se prevenir de possíveis ataques maliciosos que podem prejudicar o desempenho do aplicativo e vazamento de informações:
- WhiteList (lista branca): é um modelo de segurança que controla o acesso a domínios externos sobre os quais sua aplicação não tem controle. Por padrão, o Whitelist em um aplicativo recém criado vai permitir o acesso a todos os domínios através da <access> tag: <origem access = "*">;
- iFrames: Se o conteúdo é apresentado em um iframe de um domínio lista branca, esse domínio terá acesso à ponte nativa Cordova. Isto significa que uma rede de publicidade de terceiros será apresentada de um iframe, sendo possível que um anúncio malicioso rompa o iframe e realize ações maliciosas. Devido a isso, geralmente não se deve usar iframe a menos que o desenvolvedor tenha controle do servidor que hospeda o conteúdo iframe;
- Certificate Pinning (Certificados fixos): Cordova não suporta certificados fixos. O principal obstáculo para isso é a falta de APIs nativas em Android para interceptar as conexões SSL para realizar a verificação do certificado do servidor. O mais próximo que o desenvolvedor pode fazer para simular esse recurso é verificar se a chave pública do servidor (impressão digital) é o valor esperado quando seu aplicativo for iniciado ou em outros momentos durante o ciclo de vida da aplicação;
- Self-signed Certificates (Certificados auto assinados): Não é recomendado o uso de certificados auto assinados em seu servidor. É altamente recomendável que o servidor tenha um certificado que tenha sido devidamente assinado por um CA conhecido (autoridade de certificação). A razão para isso é que aceitar certificados auto assinados ignora a validação da cadeia de certificados, o que permite que qualquer certificado de servidor pode ser considerado válida pelo dispositivo;
- Validar todas as entradas do usuário: Sempre validar toda e qualquer entrada que o aplicativo aceita. Isso inclui nomes de usuários, senhas, datas, mídia carregado, etc. Essa validação deve ser feita também do lado do servidor;
- Evite armazenar dados importantes em Cache: Se nomes de usuário, senhas, informações de geolocalização, e outros dados sensíveis são armazenados em cache, os mesmos podem ser recuperados posteriormente por um usuário ou aplicativo não autorizado;
- Armazenar dados importantes criptografados: Se o app faz o armazenamento de informações confidenciais como senhas e documentos importantes, mantenha essas informações criptografadas. Existe inúmeros algoritmos e frameworks em JS disponíveis para fazer essa criptografia.
Criando ambiente para desenvolvimento do app mobile híbrido
Esse tópico é o marco inicial para o desenvolvimento do aplicativo móvel híbrido offline. E para isso será necessário realizar a instalação e configuração do Red Hat JBoss Developer Studio 7. Ele é um ambiente de desenvolvimento desenvolvido pela JBoss que provê suporte completo ao desenvolvimento do ciclo de um software, incluindo um conjunto de ferramentas e recursos para diversos modelos e estruturas de programação, como Java Enterprise Edition 6, RichFaces, JavaServer Faces (JSF), Enterprise JavaBeans (EJB), Java Persistence API (JPA e Hibernate, JAX-RS com RESTEasy, Contexts Dependency Injection (CDI), HTML5, Maven e muitas outras ferramentas. A versão 7 do JBoss Developer Studio está estável, certificada e testada por completa. Além disso, é uma ferramenta gratuita disponibilizada nos sistemas operacionais Windows, Linux e Mac OS X.
Instalando o Cordova PhoneGap
O JBoss Developer Studio 7 possui uma interface similar à do Eclipse. Para instalá-lo, basta fazer seu download no site da Red Hat e executar o arquivo de instalação. Após sua instalação, é possível realizar a instalação do Cordova Phonegap indo na aba “Software/Update” e preenchendo o campo Find com o título “JBoss Hybrid Mobile Tools + Cordova Sim”. Feito isso, será apresentado o plugin de instalação Cordova Tools, conforme a Figura 1. A partir daí, basta confirmar sua instalação.
Criação do aplicativo mobile híbrido off-line no JDBS
Nesse tópico será apresentada toda a parte prática do desenvolvimento do aplicativo móvel híbrido e off-line para o controle de gastos do usuário. O requisito funcional desse aplicativo parte de uma premissa básica de que o usuário possa inserir seus gastos diários (gastos com alimentação, transporte, cinema, etc.) e consulta-los. O alvo principal são pessoas que tenham a necessidade de um aplicativo offline para controlar suas finanças.
De início será criado um projeto Mobile Hybrid (Cordova) Application Project pela ferramenta JBoss Developer Studio. Para isso, acesse o menu File > New > Project. Logo em seguida, será necessário inserir as informações necessárias para o projeto, como demonstra a Figura 2.
Os dados da configuração inicial do projeto se referem a informações básicas para o desenvolvimento do aplicativo e a informações de uso exclusivo da plataforma nativa em questão. Essa é uma forma automatizada que o JBoss Developer Studio oferece para a criação de aplicativos moveis híbridos.
Observe que os dados referentes à Aplicação Móvel que está sendo criada são: Name é o nome de apresentação do aplicativo móvel e o ID é o pacote que será referenciado internamente no device (essa é uma informação que será utilizada por cada uma das plataformas que o aplicativo estiver sendo executado). Com a finalização dessa etapa, foi criada uma estrutura de diretórios para o desenvolvimento do aplicativo conforme pode ser observado na Figura 3.
A pasta www é o local onde estará todo o código fonte do aplicativo: páginas HTML5, JavaScript, imagens e o CSS. A pasta plugin é o local onde ficarão todos os programas (códigos) utilizados para acessar as funcionalidades nativas do device como câmera, localização geográfica, informações da rede, etc. A página index.html é a visão e funcionalidade de todo aplicativo que o usuário vai interagir.
O JBoss Developer Studio também disponibiliza uma paleta de componentes prontos como botões, listas, combos, painéis, tabelas, feitos em jQuery Mobile para ajudar no desenvolvimento do aplicativo.
jQuery Mobile é uma estrutura otimizada que foi desenvolvida para explorar a interação do usuário através do touch (toque em tela). Ele é um famoso framework mobile (uma biblioteca JavaScript) que é compatível com uma grande variedade de smartphones e computadores. A paleta de componentes disponível no jQuery Mobile é apresentada na Figura 4.
Cada componente disponibilizado pela paleta poderá ser adicionado na página index.html do aplicativo. Lembrando que o desenvolvedor não é obrigado a utilizar os componentes da paleta para a criação do aplicativo, a paleta é apenas um facilitador para adicionar um componente na página.
Seguindo com a análise do código fonte do index.html, é possível observar que na primeira linha do código existe a tag <!DOCTYPE html>, sendo esta a representação de página HTML5. O <body> é o local onde fica toda a página do aplicativo. As páginas são referenciadas pela tag <page> e que ficam dentro do <body>.
O arquivo index.js é carregado por um import que está dentro da página index.html (veja o código na Listagem 1), e assim que o aplicativo for iniciado a primeira chamada é a função intialize() do arquivo index.js, sendo essa a responsável por carregar todas as funcionalidades do aplicativo.
Listagem 1. Código da página index.html.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name = "format-detection" content = "telephone=no"/>
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<title>Hello Cordova</title>
</head>
<body>
<div class="app">
<h1>Apache Cordova application powered by JBoss</h1>
<div id="deviceready">
<p class="status pending blink">Connecting to Device</p>
<p class="status complete blink hide">Device is Ready</p>
</div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>
As funcionalidades do aplicativo que serão carregadas são basicamente as funções principais que ficam dentro do arquivo js/index.js. Essas funções são executadas através de chamadas em sequência com o objetivo de preparar e carregar as funcionalidades do aplicativo que está iniciando sua execução. Após as chamadas dessas funções, será apresentada a página principal do aplicativo.
Outro ponto importante é que para qualquer componente da paleta que for utilizado, automaticamente serão inseridos dois imports, jQuery e jQuery Mobile e o style CSS, como demonstra a Listagem 2.
Listagem 2. Lista de imports do jQuery e jQuery Mobile.
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
Agora iremos partir para a explicação de toda a estrutura de um projeto Cordova PhoneGap. Será criada a página principal do projeto, a qual apresentará todas as funcionalidades do aplicativo. Para criação dessa tela principal, basta acessar o componente “Page” e a Paleta de componentes da Figura 5 será apresentada.
Uma forma automatizada e intuitiva para a criação de uma <page> é apresentada para o desenvolvedor, o qual deverá preencher os campos obrigatórios para informar o Header e Footer. O ID deverá ser único por página. Essa unicidade é necessária para tornar a navegação entre páginas possível.
O Theme refere-se ao layout que o desenvolvedor irá utilizar. Normalmente, o jQueryMobile oferece quatro temas (a,b,c, d), sendo que cada um deles possui uma cor diferente. Nesse exemplo foi utilizado o theme b (tema baseado na cor azul e cinza).
Ao finalizar será inserido automaticamente o código fonte na página index.html.
Também será substituído o parágrafo <p> Page Content goes here </p>, por dois botões que servirão de menu para o usuário acessar às funcionalidades Inserir Gasto e Consultar (veja a Listagem 3).
Listagem 3. Código fonte do menu do aplicativo.
<div data-role="content">
<a href="#page-inserir" id="button-1" data-role="button" data-theme="b">Inserir Gasto</a>
<a href="#page-consultar" id="button-2" data-role="button" data-theme="b" onclick="app.fnActionTransaction(GastoController.consultar);">Consultar</a>
</div>
Executando o aplicativo com o CordovaSim (Emulador)
O JBoss Developer Studio oferece um emulador chamado Cordova Sim que é muito útil para simular o aplicativo que está sendo desenvolvido em para algum dispositivo móvel. Em suas configurações o desenvolvedor pode escolher vários modelos de smartphones, tablets, etc.
Uma grande vantagem é a facilidade em utilizá-lo. Além disso, por não necessitar de SDK nativa instalada em seu sistema, proporciona melhor desempenho em sua execução ao contrário de emuladores que utilizam SDK nativo.
Para a emulação ele possui um Painel de Controle, o qual permite o desenvolvedor configurar variáveis nativas como acelerômetros, câmeras, coordenadas geográficas, etc.
A simulação do aplicativo é apresentada pela Figura 6.
Ao iniciar a execução do emulador CordovaSim, desenvolvedores que já utilizaram algum emulador nativo vão se surpreender com a velocidade de sua execução. Em poucos segundos a aplicação é carregada por completa e é apresentada a página inicial do aplicativo.
Outro ponto interessante é que o emulador utiliza as configurações reais de cada dispositivo. Nesse exemplo está sendo utilizado o modelo iPhone 4 da Apple.
O resultado dessa simulação é a apresentação da tela inicial (menu) do aplicativo desenvolvido. O menu principal do aplicativo permite que o usuário acesse as duas funcionalidades do sistema: Inserir Gasto e Consultar, conforme a Figura 7.
A funcionalidade Inserir Gastos, cujo código é exposto na Listagem 4, permitirá que o usuário informe os gastos realizados no momento, tendo como campos de entrada de dados a Data, Valor e Descrição (Figura 8):
• O campo data é para informar a data que da compra;
• O campo valor é o valor monetário gasto;
• O campo descrição é onde ou com o que foi gasto.
O código fonte apresentado na Listagem 4 possui a <div data-role=”page”> a qual tem o identificador único representado pela propriedade id=“page-inserir”. Este deverá ser único no aplicativo para a navegação funcionar sem problemas.
Temos também as <div> para representar cabeçalho (header) e o rodapé (footer). O conteúdo da page fica entre o header e o footer a qual está sendo representada pela <div data-role=”content” > que possui todos os campos e botões da funcionalidade Inserir gasto.
Listagem 4. Código fonte da página inserir gasto.
<div data-role="page" id="page-inserir" data-theme="b">
<div data-role="header" data-theme="b">
<h1>Inserir</h1>
</div>
<div data-role="content">
<label for="date-1">Data</label>
<input name="date-1" id="pageInserir_data" data-clear-btn="true" value="" data-theme="b" type="date"/>
<label for="number-1">Valor</label>
<input name="number-1" id="pageInserir_valor" data-clear-btn="true" value="" data-theme="b" />
<label for="text-1">Descrição</label>
<input name="text-1" id="pageInserir_descricao" data-clear-btn="true" value="" type="text"/>
<a href="#page-inserir" id="button-2" data-role="button" data-theme="b"
onclick="app.fnActionTransaction(GastoController.inserir);" >Confirmar</a>
</div>
<div data-role="footer" data-theme="b">
<h4>www.devmedia.com</h4>
</div>
</div>
Estrutura Cordova SQLite
Por se tratar de um aplicativo offline, as informações deverão ser armazenadas dentro do device (smartphone ou tablet). Para realizar a persistência desses dados será necessária a criação de toda a estrutura e modelo de dados (tabelas) do aplicativo.
Isso é possível pelo fato do Cordova prover acesso ao Storage. Antes de colocar a mão na massa para criar a base de dados do aplicativo é necessário ter o conhecimento dos principais métodos disponíveis pelo Cordova SQLite e suas características:
Método openDataBase()
Utilizado para criação de uma nova SQLite Database que permite a manipulação dos dados. Esse método retorna um objeto do tipo DataBase:
var db = window.openDatabase("test", "1.0", "Test DB", 1000000);
Objeto DataBase
É um objeto que provê acesso ao Database. Esse objeto possui dois importantes métodos: transaction() e changeVersion(). O método transaction() abre uma transação em um determinado Database. O método changeVersion() é utilizado para alterar apenas a versão do database:
var db = window.openDatabase("Database", "1.0", "Devmedia Demo", 200000);
db.changeVersion("1.0", "1.1");
db.transaction(popularDB, fnErro, fnSuccess);
Objeto SQLTransaction
É um método utilizado para execução de instruções SQL no Database. Esse objeto possui um método: executeSql(). Esse método que vai executar a instrução SQL (veja um exemplo na Listagem 5).
Listagem 5. Uso do método executeSql().
function popularDB (tx) {
tx.executeSql(""DROP TABLE IF EXISTS CLIENTE);
tx.executeSql(""CREATE TABLE IF NOT EXISTS CLIENTE (id unique, nome)"");
tx.executeSql(""INSERT INTO CLIENTE (id, nome) VALUES (1, "Joao")"");
tx.executeSql(""INSERT INTO CLIENTE (id, nome) VALUES (2, "Paulo")"");
}
function fnError (erro) {
alert("Erro SQL: "+ err);
}
function fnSuccess () {
alert("Sucesso!");
}
Objeto SQLResultSet
É um objeto que é criado a partir da execução do método executeSql() de um objeto SQLTransaction. No callback do método executeSql() é passado um objeto SQLResultSet como parâmetro (veja o código da Listagem 6). Esse objeto possui três propriedades:
O insertId: retorna o número da linha de uma instrução de inserção SQL. Caso o SQL não insira todas as linhas, o insertId não é definido;
O rowsAffected: é sempre 0 para uma instrução SQL “SELECT”. Já para INSERT ou UPDATE retorna o número de linhas modificadas;
O SQLResultSetList: é um objeto final que contém os dados retornados de uma instrução SQL SELECT.
Listagem 6. Código com o objeto SQLResultSet
function queryDB(tx) {
tx.executeSql(""SELECT * FROM CLIENTE, [], fnSuccesso, fnError);
}
function querySuccess(tx, results) {
console.log("Retornado = " + results.rows.length);
if (!results.rowsAffected) {
console.log(""Nenhuma linha afetada!"");
return false;
}
console.log("ID da última linha inserida = " + results.insertId);
}
function fnError (erro) {
alert("Erro SQL: "+ erro.code);
}
var db = window.openDatabase("Database", "1.0", " Devmedia Demo", 200000);
db.transaction(queryDB, fnError);
Objeto SQLResultSetRowList
O SQLResultSetRowList contém os dados retornados de uma instrução SQL select. O objeto contém uma propriedade de comprimento, indicando quantas linhas a instrução SELECT retorna. Para obter uma linha de dados, chame o método item para especificar um índice. Ele retorna um objeto JavaScript cujas propriedades são as colunas de banco de dados da instrução SELECT executada (veja um exemplo na Listagem 7);
Listagem 7. Código com o Objeto SQLResultSetRowList
function queryDB(tx) {
tx.executeSql(""SELECT * FROM CLIENTE, [], fnSuccess, fnError);
}
function fnSuccess (tx, results) {
var len = results.rows.length;
console.log("Tabela CLIENTE: " + len + " linhas encontradas.");
for (var i=0; i<len; i++){
console.log("Linha = " + i );
console.log(" ID = " + results.rows.item(i).id);
console.log(" NOME = " + results.rows.item(i).nome);
}
}
Objeto SQLError
É um objeto lançado (throw) quando uma exceção acontecer. Possui duas propriedades:
o Code: Código do erro;
o Message: Descrição do erro.
Criação do Database e modelo de dados do aplicativo
Para a continuação do desenvolvimento do aplicativo, neste tópico será criada toda a estrutura da base de dados. A mesma deve ser criada no momento em que o aplicativo estiver sendo carregado pela primeira vez.
E para que isso aconteça, deverá ser criado o database dentro do index.js com o código exposto na Listagem 8.
O nome escolhido para o Database do aplicativo será DevmediaDB, a versão será 1.0 e com um espaço considerável de 1000000 (1Gb) para o armazenamento. Esses parâmetros podem ser configurados de acordo com a necessidade do aplicativo.
Listagem 8. Código de criação do banco de dados.
createDataBase: function()
{
var persistence = new Persistence();
db = window.openDatabase("DevmediaDB", "1.0", "devmedia-db", 1000000);
db.transaction(DataBase.createDB, persistence.errorCB, persistence.successCB);
}
Para melhor organizar o projeto, será adotada uma estrutura orientada a objetos feita inteiramente em JavaScript. Tudo isso para garantir a organização e reutilização de código no decorrer do desenvolvimento do sistema. A Figura 9 mostra a estrutura criada para representar essa ideia.
Para uma grande parte dos desenvolvedores, falar de padrão MVC é muito comum. Portanto, esse projeto é baseado nesse padrão. MVC é um padrão de projeto de software que separa a representação da informação da interação do usuário com ele. Esta separação é feita em camadas:
- Model: O modelo consiste nos dados da aplicação, regras de negócios, lógica e funções;
- View: Visão pode ser qualquer saída de representação dos dados;
- controller: Controlador que faz a mediação da entrada, convertendo-a em comandos para o modelo ou visão.
Note que foram criadas as pastas dao, dataBase, entidade e persistence. A primeira pasta a ser apresentada será a pasta dataBase, utilizada para organizar os arquivos .js (JavaScript) que representam o Database do sistema. Note que ela tem um arquivo chamado dataBase.js cujo conteúdo é apresentado na Listagem 9.
Listagem 9. Código fonte do arquivo dataBase.js.
var DataBaseApp = {
createDB: function(tx)
{
tx.executeSql(""CREATE TABLE IF NOT EXISTS DEV_GASTO
(id INTEGER PRIMARY KEY AUTOINCREMENT,
data SYSDATE, valor NUMERIC, descricao VARCHAR )"");
// Adicionar novas tabelas se necessário
},
destroyDB: function(tx)
{
tx.executeSql(""DROP TABLE DEV_GASTO"");
}
};
O arquivo dataBase.js é utilizado para representar um objeto DataBaseApp, sendo este o responsável por todo gerenciamento do Database do sistema (as tabelas e dados).
Esse objeto contém dois métodos, o primeiro é método createDB() utilizado para a criação das tabelas do sistema. Esse método será chamado quando o aplicativo for iniciado. O segundo método é o destroyDB(), que nesse exemplo, quando for invocado apagará a tabela DEV_GASTO.
A segunda pasta a ser apresentada é a pasta entidade, que será utilizada para organizar os arquivos .js (JavaScript) que representam as entidades do sistema. Note que nela foi criado um arquivo denominado gasto.js, que tem seu código apresentado na Listagem 10.
Listagem 10. Código fonte do arquivo gasto.js.
var Gasto = function (){
var self = this;
self.id;
self.data;
self.valor;
self.descricao;
};
O arquivo gasto.js é utilizado para representar um objeto Gasto, sendo este uma entidade do sistema. Note que ele é uma representação da tabela DEV_GASTO (criada pelo objeto DataBaseApp). Esse objeto contém os atributos id, data, valor e descricao que referenciam os campos da tabela DEV_GASTO. Cada tabela que existir no sistema deverá possuir um objeto (entidade) para representá-la.
A terceira pasta a ser apresentada é a pasta persistence, que terá apenas o arquivo persistence.js, sendo este o responsável pelo controle da persistência dos dados no sistema. O arquivo persistence.js, que tem seu código apresentado na Listagem 11, será utilizado para controlar as transações no banco de dados. Será o responsável pelo controle de exceções ou sucesso a cada transação realizada no banco de dados.
Listagem 11. Código fonte do arquivo persistence.js.
var Persistence = function (){
var self = this;
self.error = function (err)
{
console.log("Persistence.errorCB");
alert (“Cod: ” + err.code + “ ” + err.message);
};
self.success = function ()
{
console.log("Persistence.successCB");
};
};
O método success() será invocado quando a transação for concluída com sucesso e o método error() quando alguma exceção ou erro ocorrer na transação, lançando um alerta no sistema informando o código e a mensagem do erro ocorrido.
A quarta e última pasta é a pasta dao. Esta é a pasta responsável por organizar todos os arquivos .js que vão realizar acessos às tabelas do banco de dados criadas no sistema. Para cada entidade ou tabela que existir no sistema, será criado um arquivo.js. Note que o arquivo denominado gastoDAO.js representa isso.
O arquivo gastoDAO.js, cujo código pode ser verificado na Listagem 12, é a representação das regras de acesso ao banco de dados e instruções SQL para manipular a tabela DEV_GASTO do sistema. O código dessa listagem possui o método inserir que recebe como parâmetro o objeto SQLTransaction (tx) e um objeto Gasto (gasto).
Listagem 12. Código fonte do arquivo gastoDAO.js.
var GastoDAO = function() {
var self = this;
self.inserir = function(tx, gasto) {
console.log("GastoDAO.inserir");
var sql = ""INSERT INTO DEV_GASTO (data, valor, descricao) VALUES ("";
sql += gasto.data + "","" + gasto.valor + "",""" + gasto.descricao + """"" + "")"";
tx.executeSql(sql);
};
};
Novamente foi utilizado mais um pattern denominado DAO para esse projeto. Este padrão de projeto também é bastante familiar para desenvolvedores web. DAO significa Data Acess Object, o qual tem a responsabilidade manter separadas as regras de negócio das regras de acesso ao banco de dados.
A variável sql é uma String cujo conteúdo é a representação da instrução SQL INSERT INTO DEV_GASTO que no momento em que for executada pelo tx.executeSql() será inserido um registro na tabela DEV_GASTO do sistema.
Para completar toda a estrutura do sistema Controle de Gastos, foi criada uma pasta chamada viewController conforme apresentado na Figura 10.
Nessa pasta estarão todos os arquivos .js que representarão a manipulação dos objetos presentes nas páginas <div data-role="page"> do arquivo index.js. Essa classe, apresentada na Listagem 13, tem um método chamado de inserir. Esse método será o responsável por obter os campos da página Inserir Gastos e persisti-los na tabela DEV_GASTOS do banco de dados do aplicativo.
Note que foram criadas três variáveis para receber o valor dos campos inputText, data, valor e descrição. Esses valores estão sendo recuperados por jQuery pelo comando$(“#idElementoDaPage”). E para realizar a persistência desses valores, um objeto do tipo Gasto - new Gasto()- foi criado e populado com os valores informado na tela.
Para concluir, um objeto gastoDAO (new GastoDAO) foi criado para realizar o acesso ao banco de dados e persistir o objeto Gasto na tabela DEV_GASTO.
Listagem 13. Código fonte do arquivo tgastoController.js.
var GastoController = {
inserir:function(tx) {
var data = $("#pageInserir_data").val();
var valor = $("#pageInserir_valor").val();
var descricao = $("#pageInserir_descricao").val();
var gasto = new Gasto();
gasto.data = data;
gasto.valor = valor;
gasto.descricao = descricao;
var gastoDAO = new GastoDAO();
gastoDAO.inserir(tx, gasto);
alert(""Inserido com sucesso!"");
}
};
Interação entre a página e o controller
Agora vem a parte mais interessante, que é onde será realizada a interação da page Inserir Gastos com tGastoController.
É nesse momento que o design pattern MVC se completa, sendo apresentada a camada de controller da aplicação. Essa é uma forma de funcionamento bem prática para uma aplicação onde a visão é um documento HTML (ou derivado) que vai invocar o controlador recebendo um objeto de entrada o qual vai decidir como processá-la, invocando objetos para tratar a lógica de negócio.
Para melhor visualizar como essa camada funciona nesse aplicativo, o método inserir da classe tGastoController recebe como parâmetro um objeto do tipo SQLTransaction (tx). E para passar um objeto SQLTransaction para qualquer classe do tipo controller devemos realizar a criação desse método no arquivo index.js conforme Listagem 14.
Listagem 14. Interação entre a página e controller.
fnActionTransaction: function(method)
{
// Abre uma transaction e chama o método callback informado no parâmetro
var persistence = new Persistence();
db.transaction(method, persistence.erroPersistencia, persistence.successPersistencia);
}
Esse método receberá como parâmetro o nome do método de callback, ou seja, o nome do método que será invocado quando uma transação com banco de dados for criada. Para concluir, na page Inserir Gasto do arquivo index.html, será adicionado um evento onclick no botão Inserir, conforme o exemplo:
onclick="app.fnActionTransaction(GastoController.inserir);"
Ao pressionar o botão inserir, o evento onclick será invocado e a função fnActionTransaction() será chamada passando o nome do método callback que será invocado quando a transação for aberta. Que no caso é a função inserir da classe tGastoController.
Uma observação importante é que todas essas classes JavaScript criadas deverão de alguma maneira serem inicializadas e por isso será adicionado no arquivo index.html os seguintes imports:
<!-- Gasto -->
<script type="text/javascript" src="src/entidade/gasto.js"></script>
<script type="text/javascript" src="src/dao/gastoDAO.js"></script>
<script type="text/javascript" src="viewController/gastoController.js"></script>
Essa inicialização é extremante necessária, pois é assim que os objetos e funcionalidades do aplicativo organizadas em diferentes camadas vão interagir.
A tag <script> informa ao HTML que será importado um arquivo do tipo JavaScript que está disponível no caminho informado pela propriedade src.
Agora a funcionalidade inserir gasto está concluída e pronta para ser emulada pelo Cordova Sim, como mostra a Figura 11.
Nesse momento o usuário está prestes a inserir o seu primeiro registro no banco de dados interno (SQLite) do device. Lembrando que não há necessidade de conexão com a internet para que essa tarefa seja realizada com êxito. Isso por que o aplicativo já possui toda estrutura de base de dados interna.
Ao preencher os campos e pressionar o botão confirmar, será inserida essa informação no banco de dados. Para aprimorar essa funcionalidade, foram adicionadas validações de preenchimento dos campos obrigatórios e uma mensagem de sucesso quando os dados forem persistidos no banco, como demonstra o código da Listagem 15.
Listagem 15. Código que efetua as validações.
if (data == """"){
alert(""O campo data deve ser preenchido."");
return false;
}
if (valor == """"){
alert(""O campo valor deve ser preenchido."");
return false;
}
if (descricao == """"){
alert(""O campo descricao deve ser preenchido."");
return false;
}
alert(""Inserido com sucesso!"");
$("#pageInserir_data").val("""");
$("#pageInserir_valor").val("""");
$("#pageInserir_descricao").val("""");
Com isso, a funcionalidade Inserir Gastos está concluída. E para ver que essas informações foram persistidas no banco de dados, a próxima funcionalidade a ser criada é a Consulta dos Gastos. A mesma já possui um botão de acesso na página principal do sistema.
Para começar a desenvolver essa funcionalidade, será criado um método consultar no objeto tGastoController:
consultar:function(tx) {
var gastoDAO = new GastoDAO();
gastoDAO.consultar(tx, null, GastoController.preencherTableResults);}
Até o momento o usuário não tem como saber se realmente foi realizada a persistência do registro no banco de dados interno. E é com essa finalidade que essa funcionalidade será criada. Note que não há nenhuma regra de negócio específica para realizar essa consulta. A necessidade do negócio é apenas realizar uma consulta simples dos gastos que estão armazenados no banco de dados.
Esse método realiza uma chamada ao método consultar do objeto GastoDAO, o qual executa uma consulta na tabela DEV_GASTO. Note que o callback dessa consulta é um método denominado preencherTableResults. Mas antes de explicar esse método, será criada a página consultar no index.html, conforme o código da Listagem 16.
Listagem 16. Código para criação da página de consulta.
<div data-role="page" id="page-consultar" data-theme="b">
<div data-role="header" data-theme="b">
<h1> Consultar </h1>
</div>
<div data-role="content">
<table data-role="table" id="pageConsultar-tableResults"
data-mode="columntoggle" class="ui-body-b ui-responsive table-stripe">
</table>
</div>
<div data-role="footer" data-theme="b">
<h4>www.devmedia.com</h4>
</div>
</div>
A page consultar-gastos possui em seu conteúdo apenas uma <table id=”pageConsultar-tableResults”> sem nenhuma linha <tr> e coluna <td>. As linhas e colunas da tabela serão criadas e adicionadas na tabela após a recuperação dos registros da tabela DEV_GASTO. Para cada registro retornado do banco de dados, uma linha <tr> e suas colunas <td> serão adicionadas na tabela.
Portanto, para realizar tudo isso, será criada a função montaTabelaConsultar (ver Listagem 17). Esse método é o responsável por preencher com os resultados da consulta de gastos a tabela da página page-consultar.
Esse método recebe como parâmetro um objeto SQLTransaction (tx) e um objetoSQLResultSet (results) sendo este o resultado da consulta. Caso o tamanho desse objeto seja maior que zero, será montada a tabela HTML com o resultado da consulta (vide Figura 12). Para realizar a chamada ao método consultar, foi adicionado no evento onclick do botão Consultar o seguinte código:
onclick="app.fnActionTransaction(GastoController.consultar);"
Listagem 17. Código da função mostraTabelaConsultar.
montaTabelaConsultar: function(tx, results) {
var len = results.rows.length;
$("#pageConsultar-tableResults").html("");
if (len == 0) {
$("#pageConsultar-tableResults").html("<p><h3> Nenhum gasto registrado </h3></p>");
} else {
$("#pageConsultar-tableResults").html(
<thead>"
+ "<tr class=ui-bar-b>"
+ " <th data-priority=1 data-colstart=2 class=ui-table-priority-1>Data</th>"
+ " <th data-priority=2 data-colstart=3 class=ui-table-priority-2>Valor</th>"
+ " <th data-priority=3 data-colstart=3 class=ui-table-priority-2>
Descrição</th>"
+ " </tr>"
+ "</thead>"
+ "<tbody>"
+ "</tbody>");
for (var i = 0; i < len; i++) {
$("#pageConsultar-tableResults").append(
"<tr>"
+ " <td>" + results.rows.item(i).data
+ "</td>"
+ " <td>" + results.rows.item(i).valor + "</td>"
+ "<td>" + results.rows.item(i).descricao + "</td>"
+ "</tr>"
);
}
}
}
Exportação do aplicativo para a plataforma nativa usando Cordova
Com a conclusão do desenvolvimento do sistema vem o desafio de torná-lo híbrido. Neste tópico será apresentado como o Cordova transforma o sistema desenvolvido em HTML5 e JavaScript na plataforma nativa.
Na exportação do sistema para plataforma nativa Android ou iOS Apple, não existe nenhuma diferença. Fica a critério do desenvolvedor escolher a plataforma para a qual vai exportá-lo. Para este artigo foi escolhido a plataforma Android.
Para realizar essa exportação, o desenvolvedor deve acessar o Menu principal do JBoss Developer Studio e escolher a opção Export. Na pasta Mobile escolha Export Native Platform Projec. Em seguida, o desenvolvedor deve escolher a plataforma nativa que o projeto será exportado, conforme demonstra a Figura 13.
Neste exemplo aparece apenas a opção Android, pois para o desenvolvimento do sistema foi utilizado ambiente Microsoft Windows. Caso o desenvolvedor estivesse usando o ambiente Apple Mac OS, apareceriam as duas opções de exportação “Android e iOS”.
Para que essa exportação ocorra com sucesso, é necessário ter o Android SDK instalado no Sistema Operacional (Windows nesse exemplo) e uma AVD criada (Android Virtual Device) no Android SDK Manager (Figura 14).
Ao finalizar essa etapa será gerada a estrutura de um projeto Java Android no diretório informado.
Criação do .apk
Neste momento toda a estrutura de um projeto Java Android foi criada. E a partir dela será gerado o .apk para instalação em qualquer dispositivo Android.
APK (Android Package) é um arquivo compilado, que é usado para se instalar programas nos dispositivos Android ou publicá-los na Google Play. Para iniciá-lo é necessário abrir o Android Developer Tools e importar o projeto criado no tópico anterior. Pressionando o botão direito do mouse sobre o projeto escolha Android Export Tools, como indica a Figura 15.
Assim é concluído todo o processo de geração do .apk e para realizar a instalação desse aplicativo em um dispositivo Android, basta enviá-lo (via USB) para o dispositivo e realizar a instalação.
Neste momento o leitor está apto a começar o desenvolvimento de aplicativos mobile híbridos com qualidade, segurança e padronização. Aplicativos híbridos são uma solução que chama a atenção de investidores e departamentos de desenvolvimento de softwares. Isso pelo fato de manter um código fonte, o qual reduz o custo e tempo de desenvolvimento. A possibilidade de instalar esse aplicativo em qualquer plataforma aumenta a gama de usuários que podem utilizar e se interessar por ele.
Links Úteis
- Modelagem de dados: 1:N ou N:N?:
Você sabe quando usar um relacionamento do tipo 1:N ou N:N? Optar pelo tipo incorreto pode impactar diretamente no negócio. - Como criar minha primeira classe em PHP:
Neste conteúdo você aprenderá a criar sua primeira classe na linguagem PHP. Aprenda também a usar herança e interfaces, bem como métodos, atributos e propriedades.
Saiba mais sobre Cordova e PhoneGap ;)
- Alô mundo em Cordova:
Neste DevCast conversamos um pouco mais sobre o Cordova no Visual Studio e vimos o que é necessário para iniciar um projeto de aplicativo multiplataforma usando essa ferramenta. - Curso de Introdução ao PhoneGap:
Veja neste curso de Phonegap (Desenvolvimento Mobile com PhoneGap) como criar aplicativos móveis baseados em HTML5 que podem ser vendidos na App Store da Apple, Google Play Store ou outros mercados móveis.
JBoss
Developer Studio 7
http://www.redhat.com/en/technologies/jboss-middleware/developer-studio
Publicação
de aplicativos na Google Play Store
http://developer.android.com/distribute/googleplay/index.html