dcrocha 17:38, 12 November 2007 (EET)
Link para o projeto completo: http://wiki.forum.nokia.com/images/6/68/WidgetHelloWorld.zip
Contents |
No começo de 2007, a Nokia anunciou a tecnologia Web Run-Time (WRT), como uma das grandes novidades da plataforma S60. Esta tecnologia estará presente a partir dos dispositivos S60 3rd. Edition Feature Pack 2 permite o desenvolvimento de aplicações para smartphones Nokia utilizando tecnologias Web padrão, tais como: XHTML, CSS (Cascading Style Sheets) e JavaScript, além de possibilitar a construção de aplicações Web 2.0 com o uso do AJAX (Asynchronous JavaScript And XML), trazendo as mais recentes novidades da Web para o seu telefone celular.
Neste artigo introduziremos a tecnologia WRT, mostraremos o porquê da importância da mesma para a construção rápida e fácil de aplicações móveis, além de apresentar as ferramentas necessárias para o desenvolvimento utilizando Web Run-Time. Também mostraremos como construir uma aplicação básica e mostraremos complexos exemplos escritos por outros desenvolvedores.
O web browser dos aparelhos S60 é uma grande revolução no uso da Internet por dispositivos móveis. Ele permite navegar pelas mesmas páginas acessáveis pelos navegadores dos computadores convencionais. Com features como: thumbnails, histórico visual de páginas, mini-map (para navegação em páginas grandes) e busca de texto nas páginas, a experiência se tornou muito mais rica e interativa. Como exemplo, a Figura 1 mostra o navegador do N95 em uma página web normal, www.s60.com:

Figura 1: Navegador do N95 em ação
A nova funcionalidade do ambiente do browser da S60, WRT, permite que sejam desenvolvidas aplicações que utilizam tecnologias Web (XHTML, CSS e JavaScript), chamadas de widgets. Utilizando widgets, os desenvolvedores poderão fornecer aos usuários a experiência dos seus serviços web a partir de um único clique na área de aplicações de um aparelho S60. A seguir, vamos entrar com mais detalhes no mundo dos widgets para S60.
Os widgets são basicamente aplicações que podem ser desenvolvidas com tecnologias Web, empacotadas, instaladas no aparelho, ter um ícone e um nome associados a elas e portanto se comportar como aplicações nativas, permitindo ao usuário utiliza-las facilmente a partir do menu, além de permitir o ciclo de instalação, atualização e remoção comum às outras aplicações S60. Não é necessário que o usuário abra o browser, digite o endereço de sua página web, e espere todo o carregamento de páginas HTML, folhas de estilo e código JavaScript: tudo já vem pré-carregado, provendo uma experiência rápida e fluida no uso de aplicações Web.
Para construir um widget, o desenvolvedor precisa usar os seguintes componentes, mostrados na Figura 2:

Figura 2: Componentes de um widget para S60
Vamos agora entrar em detalhes sobre cada um dos componentes de um widget:
Além dos componentes mostrados na Figura 2, que correspondem ao núcleo de nossas aplicações web dinâmicas, mais dois elementos são necessários para que os widgets estejam completos e possam ser instalados nos dispositivos:

Figura 3: Ícones de widgets instalados em um dispositivo S60
Agora que temos todas as informações básicas sobre widgets e seus componentes, vamos desenvolver um pequeno exemplo para demonstrar como o processo de desenvolvimento, empacotamento e instalação funciona. A partir do mesmo, e da leitura dos documentos do site do Forum Nokia, você poderá criar complexas aplicações Web 2.0 para seu smartphone S60.
Como os widgets são compostos de recursos tecnológicos padrão da Web, você pode utilizar qualquer ferramenta de autoria para escrever seus códigos HTML, CSS e JavaScript. Entretanto, para os casos de:
É altamente recomendável o download do SDKs (Software Development Kits) no qual o ambiente WRT está habilitado. O SDK recomendável para tal tarefa é o:
Após baixar o arquivo S60_3rd_Ed_SDK_FP2_Beta_b.zip, descompacte-o e instale o SDK clicando em “setup.exe”.
Depois de instalado, você poderá executar o emulador clicando em “Programs -> S60 Developer Tools -> 3rd Edition FP2 SDK -> C++, Beta -> Emulator”. A Figura 3 mostra o emulador ao ser executado:

Figura 4. Emulador S60 3rd. Edition Feature Pack 2 for C++ sendo executado
Uma vez que tenhamos instalado o SDK que nos permitirá testar nossos widgets, vamos começar a criar os componentes de nossa aplicação.
Como já mencionamos anteriormente, os componentes de um widget são: (X)HTML, CSS, JavaScript, o arquivo Info.plist e um ícone. As versões suportadas de cada tecnologia são:
Para desenvolvermos, o primeiro passo será criar uma pasta no disco, chamada HelloWorld. Esta será a pasta-raiz de nosso projeto.
A seguir, vamos desenvolver a página HTML, que será a tela principal de nosso widget. Clique na pasta HelloWorld recém-criada, e dentro dela crie um arquivo chamado index.html. A Listagem 1 nos mostra o código a ser utilizado neste arquivo:
Listagem 1. Código de index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Hello World</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="helloworld.css" />
<script type="text/javascript" src="helloworld.js"></script>
</head>
<body id="body">
<div id="greeting">
<div id="greetingText">Hello World!<br/>
<a class="link" href="javascript:doAsking()">Click me</a>
</div>
</div>
<div id="asking">
<div id="askingText">How are you doing?<br/>
<a class="link" href="javascript:doGreeting()">Click me</a>
</div>
</div>
<div>
<input type="button" value="Asking" onClick="doAsking();" />
<input type="button" value="Greeting" onClick="doGreeting();" />
</div>
</body>
</html>
Alguns comentários importantes sobre o código HTML:
Tendo comentado o código HTML, vamos passar à parte dinâmica, interativa e excitante de nosso widget: o código JavaScript que realiza toda a interação com o usuário e atualização da interface. Para tal, crie um arquivo, chamado helloworld.js, dentro da pasta HelloWorld criada anteriormente, e digite o código constante da Listagem 2:
Listagem 2. Código JavaScript do arquivo helloworld.js
//Definição de constantes para os itens de menu
CMD_ASK = 10;
CMD_GREET = 11;
CMD_CURSOR = 12;
CMD_TAB = 13;
window.onload = setup;
// Creating a menu
function setup()
{
mItemAsk = new MenuItem("Asking", CMD_ASK);
mItemGreet = new MenuItem("Greeting", CMD_GREET);
mItemCursor = new MenuItem("Cursor mode", CMD_CURSOR);
mItemTab = new MenuItem("Tab mode", CMD_TAB);
mItemCursor.onSelect = menuItemSelected;
mItemTab.onSelect = menuItemSelected;
mItemAsk.onSelect = menuItemSelected;
mItemGreet.onSelect = menuItemSelected;
window.menu.append(mItemTab);
window.menu.append(mItemCursor);
window.menu.append(mItemGreet);
window.menu.append(mItemAsk);
}
// handling menu events
function menuItemSelected(id)
{
switch (id)
{
case CMD_ASK:
doAsking();
break;
case CMD_GREET:
doGreeting();
break;
case CMD_CURSOR:
widget.setNavigationEnabled(true);
break;
case CMD_TAB:
widget.setNavigationEnabled(false);
break;
default:
break;
}
}
// change view and display text
function doAsking()
{
var greeting = document.getElementById("greeting");
var asking = document.getElementById("asking");
if (window.widget)
// freezes the widget and prepares it for flipping
widget.prepareForTransition("fade");
greeting.style.display="none"; // hide the greeting view
asking.style.display="block"; // show the asking view
document.getElementById("body").style.
backgroundColor = document.defaultView.getComputedStyle(asking, null).
getPropertyValue('background-color');
if (window.widget)
setTimeout ('widget.performTransition();', 0); // flip the widget over
}
// change view and display text
function doGreeting()
{
var greeting = document.getElementById("greeting");
var asking = document.getElementById("asking");
if (window.widget)
// freezes the widget and prepares it for flipping
widget.prepareForTransition("fade");
asking.style.display="none"; // hide the asking view
greeting.style.display="block"; // show the greeting view
document.getElementById("body").style.
backgroundColor = document.defaultView.
getComputedStyle(greeting, null).getPropertyValue('background-color');
if (window.widget)
setTimeout ('widget.performTransition();', 0); // flip the widget over
}
O código JavaScript é o coração do nosso widget, portanto vamos comenta-lo em detalhes. Em primeiro lugar, há a função setup(), que realiza o trabalho de criar os itens de menu da aplicação, utilizando dois parâmetros: o texto que será usado no item de menu, mais um código numérico que será usado para identificar o item de menu clicado pelo usuário. Tais operações são realizadas no trecho abaixo:
mItemAsk = new MenuItem("Asking", CMD_ASK);
mItemGreet = new MenuItem("Greeting", CMD_GREET);
mItemCursor = new MenuItem("Cursor mode", CMD_CURSOR);
mItemTab = new MenuItem("Tab mode", CMD_TAB);
O resto do código da função se dedica a associar uma função a ser chamada quando um item for clicado (por exemplo, mItemCursor.onSelect = menuItemSelected) e a criar a estrutura a ser apresentada ao usuário. Todos os items são associados à mesma função, menuItemSelected(id), que através da checagem do valor do código do item de menu (definido acima: CMD_ASK, CMD_GREET, etc.) saberá qual item foi clicado e tomará a ação necessária. O resultado final do trabalho da função setup() e seu arranjo do menu do widget pode ser visto na Figura 5:

Figura 5: Menu da aplicação, criado via JavaScript
var greeting = document.getElementById("greeting");
var asking = document.getElementById("asking");
Todos os elementos de uma página HTML estão acessíveis ao JavaScript via DOM (Document Object Model), que é basicamente um modelo de objetos através do qual o JavaScript pode acessar todos os elementos HTML. O DOM é como o JavaScript “vê” o HTML.
Ao obtermos referências a ambas asPortanto o fluxo da alteração dos elementos gráficos é:
Traduzindo o fluxo em código JavaScript, temos:
if (window.widget)
// congela a UI do widget e prepara-o para a transição
widget.prepareForTransition("fade");
greeting.style.display="none"; // esconde a DIV “greeting”
asking.style.display="block"; // “mostra a DIV “asking”
document.getElementById("body").style.
backgroundColor = document.defaultView.getComputedStyle(asking, null).getPropertyValue('background-color'); //troca o valor da cor de fundo
if (window.widget)
//
setTimeout(‘widget.performTransition();’,0)
Esta função, doAsking(), é acionada quando um dos botões definidos na página HTML de nome “asking” é acionado. O mesmo acontece quando o botão “greeting” é acionado. A conexão entre o clique no botão e a chamada a uma função JavaScript acontece no evento “onClick()”, como vemos no trecho abaixo:
<div>
<input type="button" value="Asking" onClick="doAsking();" />
<input type="button" value="Greeting" onClick="doGreeting();" />
</div>
Como uma função pode ser reutilizada em várias partes de código, observe também que a função “callback” dos itens de menu (definidos em setup()), menuItemSelected, também responde às mesmas ações (“Asking” e “Greeting”) e portanto o menu também pode ser usado para trocar a interface gráfica do widget:
mItemAsk.onSelect = menuItemSelected;
mItemGreet.onSelect = menuItemSelected;
// handling menu events
function menuItemSelected(id)
{
switch (id)
{
case CMD_ASK:
doAsking();
break;
case CMD_GREET:
doGreeting();
break;
…
}
Tendo criado nossa página HTML, onde estão os dados do widget, e o código JavaScript, que os atualiza, precisamos agora formatar os elementos do nosso widget para que fiquem agradáveis visualmente. Como mencionado anteriormente, isso é feito através de folhas de estilo (Cascading Style Sheets – CSS). Para criar a folha de estilo, crie o arquivo helloworld.css dentro do diretório de projeto, HelloWorld, e digite o código mostrado na Listagem 3:
Listagem 3. Código CSS do arquivo helloworld.css
body {Como podemos notar, o código CSS claramente formata todos os objetos da página HTML, incluindo atributos como: cores de fundo, fontes, posicionamento, alinhamento de texto, etc. Porém, o mais importante a notar aqui é que apenas a div “greeting” tem seu atributo “display” definido como “block”. A outra div, “asking”, tem o mesmo atributo definido como “none”. Isto significa que, quando o widget for carregado, apenas uma das
margin: 0;
background-color: silver;
}
div#greetingText {
font: 20px "Lucida Grande";
font-weight: bold;
text-align: center;
color: #4D112A;
position: absolute;
top: 50px;
left: 10px;
width: 180px;
}
div#askingText {
font: 20px "Lucida Grande";
font-weight: bold;
text-align: center;
color: green;
position: absolute;
top: 50px;
left: 10px;
width: 180px;
}
div#greeting {
display: block;
background-color: silver;
}
div#asking {
display: none;
background-color: white;
}
.link {
font-size: 10px;
font-weight: normal;
text-align: center;
}
Já temos prontos a página HTML, o código JavaScript e a folha de estilo CSS, portanto o essencial de nosso widget está completo. Vamos agora criar o descritor do widget e seu ícone, para então criarmos um pacote instalável e testarmos no emulador.
Crie um novo arquivo, Info.plist, no diretório de projeto HelloWorld, e nele digite o seguinte conteúdo:
Listagem 4. Código descritor do widget, arquivo info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Nokia//DTD PLIST 1.0//EN" "http://www.nokia.com/NOKIA_COM_1/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DisplayName</key>
<string>Hello World</string>
<key>Identifier</key>
<string>com.nokia.helloworld</string>
<key>Version</key>
<string>1.00</string>
<key>MainHTML</key>
<string>index.html</string>
</dict>
</plist>
Nosso arquivo descritor contém alguns atributos do widget, os quais serão usados pelo instalador para uma série de propósitos. Os atributos e seus significados estão explicados na Tabela 1:
| Nome | Tipo | Status | Exemplo | Descrição |
|---|---|---|---|---|
| DisplayName | String | Requerido | “Hello World!” | O nome do widget, a ser mostrado na lista de aplicações. |
| Identifier | String | Requerido | com.nokia.helloworld | Uma string única identificando o widget. Será utilizada pelo instalador para atualizações e remoção. |
| MainHTML | String | Requerido | index.html | O nome da página HTML a ser carregada quando o widget é iniciado. |
| AllowNetworkAccess | Boolean | Opcional | true | false | Decide se o widget tem acesso à rede ou não. |
| Version | String | Opcional | 1.0 | A versão do widget. |
O arquivo info.plist é praticamente auto-explicativo, sendo os atributos tão simples quanto Nome, Identificador e MainHTML. Para completar nosso widget, basta agora apenas um ícone, o qual deve ser uma imagem em PNG (Portable Network Graphics) de tamanho recomendado 88x88 pixels. O ícone utilizado para nosso widget poderá ser baixado junto com o projeto do site da Web Mobile.
Já criamos todos os arquivos e pastas necessários ao nosso widget. Se tudo foi feito corretamente, nossa estrutura de diretórios será como a da Figura 6:

Figura 6: Diretório de projeto HelloWorld
Empacotar um widget para instalação é uma tarefa extremamente simples. Basta seguir os passos:

Figura 7: Criação de HelloWorld.zip

Figura 8: Criação de HelloWorld.wgz
Vamos agora testar nosso widget com o emulador.

Figura 9: Instalação do widget Hello World

Figura 10: Widget “Hello World” instalado junto às outras aplicações
Para testar nosso widget, basta posicionar o cursor sobre o seu ícone e clicar em “Open”. Você deverá ver a tela mostrada na Figura 11:

Figura 11: Widget “Hello World” sendo executado

Figura 12: Clique no botão “Asking” gera a troca da tela atual

Figura 13: Clique no item de menu “Greeting” gera volta à primeira tela

Com isso finalizamos nosso pequeno exemplo de widget para S60, mas o mesmo é apenas a ponta do iceberg. Com o suporte a JavaScript, DOM e CSS, podemos fazer aplicações Web 2.0 realmente sofisticadas utilizando os conhecimentos já obtidos com as tecnologias Web. Por exemplo, a Listagem 5 mostra o suporte ao objeto XMLHttpRequest, que é o objeto-base de todas as aplicações Ajax, além do uso do DOM para fazer o parsing de um feed RSS (Really Simple Syndication), utilizado pela maioria dos sites para exportar seu conteúdo em formato XML: Listagem 5. Exemplo de uso de Ajax com widgets
//Carregamento do feed
function loadRSSFeed(url) {
if (null == req) {
req = new XMLHttpRequest();
}
req.onreadystatechange = ReqStateChange;
req.open("GET", url, true);
req.send(null);
document.getElementById("content").innerHTML = "Updating" + url;
}
//Função chamada quando o request é retornado
function ReqStateChange() {
if (req.readyState == 4) {
if (req.status == 200) {
UpdateContent(req);
}
else {
alert("error");
}
}
}
//Interpretação do conteúdo e atualização do XML em formato RSS
function UpdateContent(reqst) {
var d = null;
var el = document.getElementById("content");
document.getElementById("content").innerHTML = "Updating!";
var rss = null;
var html = "";
rss = reqst.responseXML.documentElement;
if (rss != null) {
var itemTitleNodes = rss.getElementsByTagName("title");
var itemLinkNodes = rss.getElementsByTagName("link");
var itemDescNodes = rss.getElementsByTagName("description");
var c=itemTitleNodes.length;
el.innerHTML="Displaying " + c + " items...";
if (c<=0) {
return;
};
if (c>4) c=3; // limit to four stories
for (var i = 0; i < c; i++) {
var itemLink, itemTitle, itemDesc;
if ((itemTitleNodes[i+2].childNodes[0] != null) &&
(itemLinkNodes[i+2].childNodes[0] != null) &&
(itemDescNodes[i+1].childNodes[0] != null)) {
itemTitle = itemTitleNodes[i+2].childNodes[0].nodeValue;
itemLink = itemLinkNodes[i+2].childNodes[0].nodeValue;
itemDesc = itemDescNodes[i+1].childNodes[0].nodeValue;
}
else {
itemTitle = "RSS feed missing";
itemLink = "???";
itemDesc = "RSS broken";
}
html = html + "<div class='item'><div class='linking'
onClick='widget.openURL(\"" + itemLink +
"\");'>"+itemTitle+"</div></br><div
class='description'>"+itemDesc+"</div></div></br>";
}
}
el.innerHTML = html;
html = null;
el = null;
req = null;
d = document.getElementById("lastupdate");
}
Além do uso das tecnologias Web e Ajax, você poderá usar APIs exclusivas da plataforma S60: Widget, Menu e SysInfo. Todas permitem uma maior interação com as funcionalidades do próprio aparelho, e só estão disponíveisl para widgets, não para aplicações Web comuns. Você poderá obter mais detalhes na seção de links deste artigo. Lá você também poderá baixar o código de aplicações sofisticadas que demonstram todo o poder do uso dos widgets na plataforma S60.
Como dito no começo deste artigo, a tecnologia de Widgets e Web Run-Time estará disponível a partir dos aparelhos S60 3rd. Edition Feature Pack 2. Os mesmos ainda não estão disponíveis no mercado (os aparelhos mais recentes como Nokia N95 são Feature Pack 1) mas desde já você poderá desenvolver seus widgets usando ferramentas Web padrão, testa-los usando o emulador que usamos neste artigo, e como novidade, o Forum Nokia oferece um serviço de teste remoto de aplicações, chamado RDA (Remote Device Access), no qual você poderá testar suas aplicações Java e C++ (além de conteúdo multimídia) em aparelhos reais, via uma aplicação cliente instalada em seu computador. Os dispositivos estão localizados em nosso laboratório, e podem ser utilizados como um telefone normal em suas mãos, com todas as funções, incluindo acesso à rede. A boa notícia para desenvolvedores de widgets é que alguns dos modelos disponíveis no RDA estão atualizados com um firmware especial de desenvolvimento que já disponibiliza a Web Run-Time, ou seja, você poderá testar remotamente seus widgets em aparelhos reais, com acesso à rede e todos os outros benefícios. O acesso ao serviço RDA é gratuito a todos os membros do Forum Nokia. Para se tornar um membro, basta cadastrar-se gratuitamente em http://forum.nokia.com.
O uso dos widgets para desenvolvimento de serviços e aplicações móveis traz uma série de benefícios aos desenvolvedores:
Aqui vai uma coleção de links importantes para o desenvolvimento de widgets: