Trabalhando com o Worklight, Parte 2: Desenvolvendo módulos estruturados e usando o recurso Encrypted Offline Cache no IBM Worklight

Estratificando o seu aplicativo remoto com estrutura, funcionalidade e segurança

Esta série de artigos apresenta a plataforma IBM® Worklight® mostrando como é possível desenvolver aplicativos remotos que utilizam vários produtos de software IBM. A Parte 2 continua a descrever o processo de desenvolver um aplicativo Worklight, mostrando algumas das melhores práticas para desenvolver aplicativos híbridos e apresentando a funcionalidade Encrypted Offline Cache do Worklight.

Carlos Andreu , Software Developer, IBM

Carlos Andreu é um Software Developer no IBM Software Group. Atualmente, trabalha na criação de uma estrutura para desenvolver aplicativos Hybrid, Android e iOS. Seus interesses compreendem seguir as tendências e os blogs de tecnologia mais recentes, ler, ver televisão e curtir todos os tipos de música. Mais informações sobre ele em http://dev.yapr.org/carlosandreu.



Jeremy Nortey, Software Developer, IBM

Jeremy Nortey atua como Software Developer para a IBM Mobile Foundation dentro do Software Group. Desenvolve software e controle de qualidade para soluções remotas. É especialista em iOS e se interessa pelo desenvolvimento de aplicativos nativos para iPhone em seu tempo livre. Pratica futebol e corrida como hobby.



Raj Balasubramanian, Product Architect, IBM

Raj Balasubramanian é um Consulting IT Architect para o IBM Software Group. Trabalha com clientes na realização de projetos relacionados a aplicativos e infraestrutura. Seus interesses envolvem todos os assuntos técnicos, História e Física. Durante as suas muitas horas livres, gosta de sair com a esposa e conversar com os filhos sobre robôs. Mais sobre sua vida profissional e pessoal no blog Gurukulam.



16/Ago/2012

Introdução

O IBM Worklight, parte do IBM Mobile Foundation , fornece uma plataforma robusta para desenvolver aplicativos remotos rapidamente e, ao mesmo tempo, aproveitar tecnologias baseadas na web que podem executar em várias plataformas de dispositivos. Este artigo retoma o assunto onde a parte 1 parou — no processo de desenvolver um aplicativo remoto totalmente funcional e autocontido, chamado "Todo", que permite a um usuário remoto criar e manter uma lista de tarefas a fazer. Durante o processo, você aprenderá sobre o Encrypted Offline Cache, uma medida de segurança do tempo de execução do cliente do Worklight que protege informações sensíveis contra ataques de malware e furto de dispositivos.

Obtenha o Worklight agora

Faça o download do IBM Worklight Developer Edition 5.0 agora gratuitamente e sem data de expiração!

A esta altura, você já deve ter o IBM Worklight Studio configurado no seu IDE Eclipse e estar familiarizado com o processo para implementar um aplicativo simples do tipo "Hello World" no iOS e Android. Começaremos com o aplicativo Todo que você começou a desenvolver na parte 1. Faça o download do aplicativo inicial que você criou na Parte 1 e importe-o para o ambiente do Worklight Studio. (Como alternativa, é possível fazer o download dos arquivos de projeto do aplicativo Todo incluídos neste artigo.)


Desenvolvendo o aplicativo

O uso do aplicativo de amostra

O aplicativo de amostra descrito aqui é apresentado como um exercício, somente para fins de exemplo. Já que a maior parte da lógica de aplicativo estará em JavaScript™ (usando especificamente o JQuery), as melhores práticas de estruturação da lógica do aplicativo para conseguir melhor capacidade de leitura, confiabilidade e consistência serão destacadas, bem como as práticas sobre o uso do namespace e outras.

A Figura 1 ilustra o fluxo geral do usuário que executa o aplicativo remoto Todo. Para resumir, o usuário:

  1. Abriria o aplicativo.
  2. Inseriria uma senha para armazenar dados offline de forma segura e daria um toque em Start para passar ao segundo painel.
  3. Inseriria qualquer texto referente a um novo item de "coisa a fazer" no primeiro campo e, em seguida, o incluiria na lista dando um toque no botão Add Item .
  4. Marcaria o item como "done" dando um toque no item na lista para selecioná-lo. Daria um toque em Remove Done para excluir todos os itens marcados como prontos.
  5. Filtraria os itens exibidos no painel digitando total ou parcialmente o nome de um item dentro do segundo campo de texto e, em seguida, daria um toque em Filter Items....
Figura 1. Painéis do aplicativo de amostra
Painéis do aplicativo de amostra

A primeira etapa para incluir essa funcionalidade no seu aplicativo é dividir o código em módulos que têm responsabilidades específicas dentro do aplicativo. O Todo terá estes módulos (Figura 2):

  • Módulo Constant obtém e configura as várias constantes que serão utilizadas no aplicativo.
  • Módulo List é responsável por armazenar a lista da sessão atual e manipular eventos, como incluir um novo item na lista, marcar itens como concluídos e remover itens marcados como concluídos.
  • Módulo Vault tem a tarefa de criptografar e decriptografar a lista. É aqui que você utilizará o recurso Encrypted Offline Cache do Worklight.
Figura 2. Módulos e suas interações
Módulos e suas interações

Para estruturar o seu código, você aproveitará o comum e popular Padrão de Módulos, do mundo do JavaScript (consulte Recursos). A Listagem 1 mostra o esqueleto de um módulo. Você designa uma função autoexecutante (ou função imediata) a um objeto (Module1) que está contido no seu namespace (MYAPP). É uma boa ideia passar coisas como o objeto global (janela, na maior parte do Javascript no lado do cliente) e bibliotecas do fornecedor (como o jQuery, para que seja possível usar $ dentro do módulo, mesmo se alguma coisa o usa fora do módulo, como Prototype.js ou outra biblioteca). Também é uma boa prática listar dependências e designar variáveis locais às suas dependências, porque acessar variáveis locais é mais rápido do que procurar pares de valor de chave.

Por exemplo,

var eoc = WL.EncryptedCache; eoc.open()

é melhor do que fazer o JavaScript procurar o objeto de WL e, em seguida, procurar a chave EncryptedCache que aponta para outro objeto que contém a função aberta que você quer chamar sempre que for necessário chamá-la dentro de um dos seus módulos.

Listagem 1. Esqueleto do Padrão de Módulos
MYAPP.Module1 = (function (global, $) { 
//List dependencies: jQuery 1.7.2

//List private variables

//List private functions
var _init = function () {
console.log("I'm ready!");
}

//List one time initialization procedures 

//public API
return {
init : _init
};

}(window, jQuery)); //MYAPP.Module1

Este é um bom momento para mencionar algumas convenções de estilo inteligentes. Nessas amostras de código, são usados caracteres em maiúsculas para as constantes e caracteres de sublinhado são colocados na frente de funções privadas para diferenciá-las das variáveis privadas. É possível ampliar essa convenção para utilizar o "padrão de variável única", no qual se declara uma única variável na parte superior de cada função que requer variáveis. Isso é feito porque o JavaScript "puxa" as variáveis para a parte superior quando o código é executado (Listagem 2) e porque o esquecimento do uso de variáveis às vezes provoca resultados indesejáveis, como o de sobrescrever uma variável global com o mesmo nome.

Listagem 2. Exemplo de "puxada para cima"
//Example of Hoisting 
myname = "global";

function func() {
alert(myname); //returns: "undefined" 
var myname = "local";
alert(myname); //returns: "local"

Há uma construção subjacente chamada SelectAll que faz os módulos funcionarem (consulte Recursos). No JavaScript, o encerramento faz referência a uma variável local para uma função que se mantém ativa após o retorno da função. Isso está estreitamente ligado à definição de escopo no JavaScript, que é definido por função. Por exemplo, a Listagem 1 mostra um exemplo de encerramento em ação. Aqui, _init é uma função privada que não é acessível fora da função autoexecutante designada para MYAPP.Module1, mas você retorna um objeto que tem uma referência a essa função privada. Dessa forma, é possível acessá-la facilmente como MYAPP.Module1.init(). É o encerramento que possibilita isso.

O JavaScript é uma linguagem de programação orientada a eventos, semelhante ao Padrão Observador descrito em praticamente todos os livros de padrões de programação. Nos scripts de Javascript, os eventos são disparados sempre que o usuário rola a tela, clica em uma tag de HTML ou passa o mouse sobre um link, para citar alguns exemplos. Os eventos podem ser recebidos, e é possível acionar os seus próprios eventos.

A separação de interesses é outra prática importante a ser seguida, o que significa manter a marcação, estilo e lógica de aplicativo separados. O seu código HTML deve descrever somente a estrutura do seu aplicativo; não é desejável usar funções sequenciais de JavaScript. É possível obter isso usando o estilo de codificação movido a eventos, no qual o elemento específico que precisaria ter a chamada sequencial é observado em relação ao evento específico que acionará a ação necessária. Isso permite ter a lógica do aplicativo em um único lugar — no JavaScript — e não em vários locais ao longo do HTML. Da mesma forma, deve-se evitar escrever HTML como parte do JavaScript e usar modelos em vez disso (consulte Recursos).


Módulo Constant

Comece definindo o seu namespace (Listagem 3). No aplicativo de amostra Todo, dê ao seu namespace o nome "TD". Basicamente, o namespace é um objeto que contém outros objetos, todos eles pertencentes ao seu aplicativo. É possível que, à medida que o aplicativo cresce, o TD já esteja definido no namespace global. Use o padrão de variável única para criar um objeto de TD caso não haja um disponível. Essa função de namespace garantirá a consistência na chamada de método: chamar TD.namespace(TD.module1) incluirá um objeto chamado module1 ao TD. Você verá como declarar o namespace do TD e usá-lo para realizar a cascata dos objetos sob o namespace do TD conforme a necessidade.

Listagem 3. Função Namespace
/**********************************************************************************
* TD NAMESPACE
**********************************************************************************/
var TD = TD || {};

TD.namespace = function (ns_string) { 
var parts = ns_string.split('.'),
parent = TD, 
i;

// strip redundant leading global 
if (parts[0] === "TD") {
parts = parts.slice(1); 
}

for (i = 0; i < parts.length; i += 1) {
// create a property if it doesn't exist
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {}; 
}
parent = parent[parts[i]]; 
}

return parent; 
};

Na Figura 3, é possível ver que o TD.Constant (seu módulo Constant) não tem nenhum membro privado. Ele só retornará valores por meio de algo que chamaremos de API Pública (é um par simples de chave/valor criado usando um literal de objeto). De forma semelhante, a chave de itens Todo é usada para o Encrypted Offline Cache. Os valores de encrypt e decrypt são valores booleanos simples que, no final, comunicarão ao módulo Vault se você deseja criptografar ou decriptografar.

Figure 3. Elementos dos módulos
Figure 3. Elementos dos módulos

Módulo List

Como mostram a Figura 1 e a Listagem 4, o segundo painel do aplicativo é basicamente a página principal do aplicativo. Ele contém:

  • Um logotipo no cabeçalho.
  • Um campo de texto (id="new-todo") que será usado para incluir novos itens.
  • Um botão para incluir novos itens (id="add").
  • Um botão para excluir todos os itens marcados como prontos (id="delete").
  • Uma lista não ordenada para anexar a lista de itens (id="todo-list").
  • Uma tag div (id="no_items") para exibir texto quando a lista estiver vazia.

Observe também que se pode obter filtragem de dados grátis incluindo uma propriedade data-filter=’true’ na sua tag <ul> (consulte Recursos). (http://jquerymobile.com/demos/1.1.0/docs/lists/index.html).

Listagem 4. HTML do painel principal
<!-------------------------- MAIN PAGE  -------------------------->
<div data-role="page" id="main" >

<!-- <div data-role="header"><h1>Todo App</h1></div> -->
<img class="centerimg" src="images/logonobg.png"/>

<div data-role="content" >

<input type="text" name="new-todo" id="new-todo" 
placeholder="Write your tasks here..." />

<div class="controls" data-role="controlgroup" data-type="horizontal">
<a href="#" id="add" data-role="button" data-icon="plus">Add New</a> 
<a href="#" id="delete" data-role="button" data-icon="delete">Delete Done</a>
</div>

<ul id="todo-list" data-role="listview" data-filter="true" data-inset="true" >
</ul><!-- /todo-list -->

<div class="center" id="no_items"></div>

</div>
<!-- /content -->
</div>
<!-- /page -->

Para a sua lista de tarefas, você armazenará itens em um array de lista. Por exemplo,

[{content: “myTodo Item 1", done: false},
{content: “myTodo Item 2", done: true}].

É só um array simples com pares de valor de chave (objetos de JavaScript) que têm uma cadeia de caracteres como nome do item e um valor booleano para controlar se um item está pronto ou não.

Como mostra a Figura 3, TD.List (o módulo List) contém um método privado definido (_encrypt) que criptografará a lista (um array privado chamada "list") chamando o método de criptografia do módulo Vault a partir da API pública. Existe também _item_template, uma função gerada a partir de um modelo para exibir itens definidos dentro do seu documento HTML. É necessário passar um objeto que tenha "item" como chave e o array de lista.

Um exercício

Como exercício, convém realizar uma verificação de tipo mais elaborada (por exemplo, verificar se item.done retorna um operador booleano, verificar se há null, etc.).

A função privada _add irá verificar se item.content não está vazio ou indefinido e se algo é retornado quando você chama item.done. Lembre-se de que as variáveis que não tiveram um valor designado por padrão retornarão "undefined."

Listagem 5. Função _add
_add =  function (item) {
if (item.content !== 'undefined' && item.done !== 'undefined' && item.content.length > 0)
{
list.push(item);
}
},// add item

A função _refresh_list executa dinamicamente uma função de mapa no array de lista e inclui um novo elemento em todos os objetos armazenados no array. O restante da função limpa a lista, anexa à lista não ordenada (ul) no HTML o resultado do modelo gerado com base na lista e atualiza a visualização. Essa última chamada de método é específica do jQuery Mobile para atualizar o estilo da lista.

Listagem 6. Função _refresh_list
_refresh_list = function () {

$.map(list, function (item, i) {
item.index = i;
});

list_ul.empty();
list_ul.append(_item_template({item : list}));
list_ul.listview('refresh');

if (list.length < 1) {
no_items.text('No items.');
} else {
no_items.text('');
}

}; // refresh list

Outro exercício

É conveniente mudar essa abordagem usando outra estrutura de dados e um algoritmo diferente para gerar e controlar os IDs. O objetivo é não precisar usar a função de mapa para iterar na lista inteira e gerar IDs, além de não precisar limpar ou anexar novamente a lista inteira sempre que você incluir ou remover um item.

Em seguida, você anexará ações aos eventos. Se você está familiarizado com o jQuery, talvez esteja acostumado a usar ou ver chamadas como bind(), live() e delegate(). Nesse exemplo, on() é usada de forma exclusiva porque, depois do jQuery 1.7.0, esses métodos bind, live e delegate são somente wrappers para on(). Além disso, $(this) é "armazenado em cache" em uma variável local chamada $this porque, idealmente, convém usar essa função do jQuery o menos possível e limitar a quantidade de vezes que você "mergulha" no DOM (Document Object Module), pois se trata de uma operação de custo muito alto. Observe que foi alterado o valor booleano que descreve se o item está pronto ou não e inclui ou remove uma classe chamada "done" definida na folha de estilo (arquivo .css). Finalmente, você criptografa (encrypt()) a lista para persistir, mesmo se você fechar imediatamente o aplicativo depois de clicar em um item para marcá-lo como pronto.

Listagem 7. Anexações de eventos dentro de TD.List
add_btn.on('click', function () {

_add({content : new_item.val(), 
done: false });

new_item.val('');
_refresh_list();

_encrypt();

}); // add btn

list_ul.on('click', 'li', function () {

var $this = $(this),
$item = $this.find('a'),
index = $item.attr('id'), 
current_item = list[index];

current_item.done = !(current_item.done);

if (current_item.done) {
$item.addClass('done');
} else {
$item.removeClass('done');
}

_encrypt();

}); // list item

delete_btn.on('click', function () { 
var i = list.length;

while (i--) {
if (list[i].done) {
list.remove(i);
}
}

_refresh_list();

_encrypt();

});// delete btn

Aplica-se um tratamento semelhante ao botão de excluir, cujo código é possível ver no Worklight Studio.

A API pública do módulo List é muito simples: é possível obter a lista atual com a qual você está trabalhando, configurar uma nova lista e trabalhar com ela e atualizar a lista configurada no momento. Você chama esses métodos chamando o namespace do TD, seguido pelo nome do módulo e, finalmente, uma das chaves do objeto retornado pelo seu modelo.

Por exemplo,

TD.List.get(), TD.List.set([]), TD.List.refresh()

seria válido, ao passo que:

TD.List._refresh_list(), TD.List._add()

não são, porque essas funções só podem ser chamadas dentro do módulo (lembre-se: as funções criam escopo) ou por membros privilegiados (como o objeto que é retornado dentro do seu módulo).

Listagem 8. API pública de TD.List
//public API
return {
get : function () {
return list;
},
set : function (new_list) {
list = new_list;
},
refresh : function () {
_refresh_list();
}
};

Módulo Vault

O módulo TD.Vault é um wrapper para a funcionalidade Encrypted Offline Cache (EOC) do Worklight. Baseado no armazenamento local em HTML5, o EOC é uma forma de armazenar dados persistentes sem usar cookies. O EOC fornece métodos para abrir e fechar e, em seguida, para ler e escrever valores quando estiver aberto. Os detalhes de segurança do EOC estão fora do escopo deste artigo mas, resumidamente, o EOC utiliza uma senha de usuário para criptografar os dados. Por conseguinte, o código HTML relevante para esse módulo específico é uma página (o primeiro painel da Figura 1) que contém:

  • Uma imagem de cabeçalho com o logotipo ou nome do aplicativo.
  • Um campo para a senha (id=’passcode’).
  • Um botão (id=’send_passcode’) para enviar a senha.
Listagem 9. HTML para a página de senha
<!-------------------------- PASSCODE PAGE  -------------------------->
<div data-role="page">

<img class="centerimg" src="images/logonobg.png"/>

<div data-role="content">

<div class="center" id="invalid_passcode"></div>

<ul data-role="listview" data-inset="true">
<li data-role="fieldcontain">
<label for="passcode">Enter Passcode:</label> 
<input type="text" name="passcode" id="passcode" value="" placeholder="Your passcode" />
</li>
</ul>

<a id="send_passcode" href="#" data-role="button" data-theme="a">Start</a>
</div>
<!-- /content -->

</div>
<!-- /page -->

Inicie o código do JavaScript passando algumas variáveis globais para a sua função autoexecutante, como o jQuery (redefinido como $) e WL (namespace do Worklight, redefinido como WL). Em seguida, você "armazena em cache" as suas dependências designando variáveis locais para elas. Isso garante que seja possível chamar facilmente wl.EncryptedCache.open (em vez de passar o namespace do WL como parâmetro para o módulo) e, em seguida, armazenar em cache wl.EncryptedCache em uma variável local chamada eoc. Em seguida, variáveis privadas como KEY armazenam a passphrase que o usuário insere, e algumas chamadas do DOM são salvas para o botão da senha, o campo da senha e um div que exibe uma mensagem de erro se a senha é inválida (Listagem 10).

Listagem 10. Módulo TD.Vault, dependências e variáveis privadas
TD.namespace('TD.Vault');
TD.Vault = (function ($, wl) { 
//dependencies
var eoc = wl.EncryptedCache,
log = wl.Logger,
list_obj = TD.List,
CONST = TD.Constant,

//private variables
KEY = "",
send_passcode_btn = $('#send_passcode'),
passcode_fld = $('#passcode'),
invalid_passcode_div = $('#invalid_passcode'),

Um último exercício

Convém verificar a documentação do Worklight e implementar uma manipulação específica para os erros, baseada no código de status retornado pela função de retorno de chamada onErrorHandler.

Em seguida, você tem algumas variáveis privadas, como _error, que simplesmente registram quando você recebe um retorno de chamada. Os métodos _setData e _getData especificam como você obtém e configura os dados que irão criptografar e decriptografar (Listagem 11).

Listagem 11. Funções _error, _setData e _getData
//private functions
_error = function () {
log.debug("error");
},

_setData = function (new_list) {
if (new_list) {
list_obj.set(new_list);
list_obj.refresh();
} 
},

_getData = function () {
return list_obj.get();
},

A definição de evento é semelhante à de TD.List, na qual você anexa send_passcode_btn on click, que simplesmente designa a senha que o usuário inseriu quando iniciou o aplicativo à variável privada KEY, caso o comprimento da entrada seja de pelo menos um caractere (Listagem 12).

Listagem 12. Anexação de evento do botão de enviar senha
send_passcode_btn.on('click', function () {

var passcode = passcode_fld.val();

if (passcode.length > 0) {
KEY = passcode;

_decrypt();

$.mobile.changePage("#main", { transition: CONST.DEFAULT_TRANSITION });

} else {
passcode_fld.val('');
invalid_passcode_div.text('Invalid Passcode.');
}

});

Em seguida, você decriptografa o conteúdo do EOC chamando a variável privada _decrypt(). Essa ação chama _open com uma constante (CONST.DECRYPT) que indica que você irá decriptografar depois de abrir o cache criptografado. A função _open aciona o evento eoc-open e envia a ação (decrypt) para _read(). Em seguida, você tentará ler o cache criptografado com a chave que o usuário forneceu. Neste ponto, _setData é chamado com os dados que você recebeu analisados em um array de Javascript com parseJSON (esse array contém um par de valores de chave que descreve um único item em todos os índices do array). Se você obteve algo de volta do cache, você chama set no módulo List para configurar a lista recebida como nova lista. Finalmente, o elemento HTML da lista é atualizado ao chamar refresh a partir da API pública de TD.List.

Listagem 13. Funções _close, _write, _read, _encrypt e _decrypt functions e um listener de eventos "eoc-open"
_close = function () {
var onCompleteHandler = function () { 
$.publish('eoc-closed'); 
};

//function(onCompleteHandler, onErrorHandler)
eoc.close(onCompleteHandler, _error);
},

_write = function () {
var data = JSON.stringify(_getData());

//function(key, data, onCompleteHandler, onErrorHandler)
eoc.write(CONST.TODO_ITEMS_KEY, data, _close, _error); 
},

_read = function () {
var onCompleteHandler = function (data) {
_setData($.parseJSON(data)); 
_close(); 
};

//function(key, onCompleteHandler, onErrorHandler)
eoc.read(CONST.TODO_ITEMS_KEY, onCompleteHandler, _error);
},

_encrypt = function () {
_open(CONST.ENCRYPT);
},

_decrypt = function () {
_open(CONST.DECRYPT);
};

$.subscribe("eoc-open", function (e, action) {
if (action) { // == CONST.ENCRYPT
_write();
} else { // == CONST.DECRYPT
_read();
}
});

A criptografia segue basicamente os mesmos passos — a diferença é que a ação executada depois da abertura do cache chamará _write em vez de _read. Em seguida, você executa _getData para obter a lista atual, convertê-la para uma cadeia de caracteres com JSON.stringify e armazená-la no cache. Feche o cache depois de cada criptografia e decriptografia.

As Figuras 4 e 5 mostram o aplicativo concluído executando no simulador de iPhone.

Figura 4. O aplicativo concluído executando no simulador de iPhone (página da senha)
O aplicativo concluído executando no simulador de iPhone (página da senha)
Figura 5. O aplicativo concluído executando no simulador de iPhone (página principal)
O aplicativo concluído executando no simulador de iPhone (página principal)

Conclusão

A Parte 2 dessa série introdutória sobre o IBM Worklight continuou a utilizar a configuração do ambiente de desenvolvimento do Worklight da Parte 1 e a incluir funcionalidade para desenvolver o aplicativo de amostra Todo. No decorrer do artigo, você viu que a estruturação do código pode beneficiar o desenvolvimento, a apresentação e a manutenção do aplicativo. Você também aprendeu sobre a persistência dos dados (lista de tarefas) no dispositivo por meio da funcionalidade Encrypted Offline Cache do Worklight. A conclusão desta série incluirá a conectividade no lado do servidor com adaptadores para concluir o aplicativo de amostra.


Download

DescriçãoNomeTamanho
Sample application project filestodo-app-part2.zip18.5MB

Recursos

Aprender

Obter produtos e tecnologias

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Desenvolvimento móvel, WebSphere
ArticleID=830568
ArticleTitle=Trabalhando com o Worklight, Parte 2: Desenvolvendo módulos estruturados e usando o recurso Encrypted Offline Cache no IBM Worklight
publish-date=08162012