sexta-feira, 7 de janeiro de 2011

ANT + Antenna

Olá povo,

Esse post vai em homenagem a primeira turma de pós-graduação em Tecnologias para Desenvolvimento de Aplicações Movéis do CESAR.edu que aguentaram o mico que eu paguei quando o exemplo que eu vou mostrar nesse post não funcionou na sala. Então lá vai...

Vou demonstrar nesse post como utilizar o Ant e o Antenna. O Ant é uma ferramenta para automatização de scripts desenvolvida pela Apache Foundation. Baseia-se em tarefas a serem executadas e descritas em um arquivo XML (chamado de build file).

O Antenna é uma biblioteca que pode ser adicionada ao Ant para prover um conjunto de tarefas exclusivas para o desenvolvimento com Java ME. As tarefas realizadas pelo Antenna executam o trabalho que o WTK realiza, porém, com elas o processo de deploy (geração de um JAR/JAD) da aplicação fica mais flexível e independente de IDE.

Uma das grandes vantagens da utilização dessas ferramentas é auxiliar a prover portabilidade para a diversidade de fabricantes e modelos de aparelhos existentes no mercado, uma vez que tamanho de tela, quantidade e disponibilidade de teclas, formato de áudio e vídeo suportados são algumas das características que variam bastante de modelo para modelo.

Supondo que já temos o Eclipse configurado para Java ME, precisamos apenas baixar o JAR do Antenna que está disponível aqui. Depois, basta configurar no Eclipse o local onde você baixou o JAR. Para isso, acesso o menu Window > Preferences. No lado esquerdo, selecione Java ME, e preencha o campo Antenna JAR com o nome e local onde está o JAR do Antenna.

Vamos utilizar um projeto Java ME bem simples no Eclipse para demonstrar a utilização do Ant+Antenna. A estrutura final do projeto ficará como na imagem abaixo:


Vamos começar detalhando a classe PrincipalMIDlet.java:

public class PrincipalMIDlet extends MIDlet {

protected void startApp() {
Display.getDisplay(this).
setCurrent(new MeuCanvas());
}

protected void destroyApp(boolean uncond){
notifyDestroyed();
}

protected void pauseApp() {
}
}

class MeuCanvas extends Canvas {
//#ifdef operadora
//#expand private String OPERADORA = "%operadora%";
//#else
private String OPERADORA = "Indefinido";
//#endif

//#ifdef background
//#expand private int COR_BACKGROUND = %background%;
//#else
private int COR_BACKGROUND = 0;
//#endif

private static final int COR_TEXTO = 0xFFFFFF;

private Image icon;

public MeuCanvas() {
try {
icon = Image.createImage("/icon.png");
} catch (IOException e) {
}
}

protected void paint(Graphics g) {
int w = getWidth();
int h = getHeight();

g.setColor(COR_BACKGROUND);
g.fillRect(0, 0, w, h);

g.drawImage(icon, w/2, h/2,
Graphics.BOTTOM | Graphics.HCENTER);

g.setColor(COR_TEXTO);
g.drawString(OPERADORA, w/2, h/2,
Graphics.TOP | Graphics.HCENTER);
}
}

A parte bacana do código acima, está na definição das constantes OPERADORA e COR_BACKGROUND. Notem que elas estão envolvidas por trechos de código que aparentemente são comentários do Java, mas na verdade elas são diretivas de pré-processamento. Esse recurso é possível graças ao Antenna, que faz com que essas diretivas tenham funcionalidade similar as diretivas de compilação da linguagem C.

A instrução //#ifdef verifica se uma determinado símbolo foi definido, em caso positivo, o código-fonte que estiver dentro dessa diretiva é o que será compilado, caso contrário será compilado o código que está dentro da diretiva //#else. Toda diretiva //#ifdef deve ser fechada com a diretiva //#endif.

A diretiva //#expand substituirá qualquer símbolo que estiver entre "%" com seu respectivo valor. No nosso exemplo, definimos dois arquivos de símbolos que contêm os símbolos "operadora" e "background". Esses arquivos são mostrados abaixo:

#Claro.symbols
operadora='Claro'
background='0xFF0000'

#Vivo.symbols
operadora='Vivo'
background='0x0000FF'

Um outro detalhe a ser observado é que quando a imagem icon.png foi carregada, ela não foi carregada do diretório Vivo ou Claro. Isso porque, geraremos um JAR e um JAD da nossa aplicação para cada operadora, então os recursos de cada uma delas ficará na raiz do JAR.

Vamos agora ao script de deploy. A estrutura do build.xml, está conforme a imagem abaixo:


<?xml version="1.0" encoding="UTF-8"?>

<project name="ExemploAnt" basedir="." >

<!-- Carrega as tarefas do Antenna -->
<taskdef classpath="${antenna.lib}"
resource="antenna.properties"/>

<!-- Carrega o arquivo de propriedade -->
<property file="meubuild.properties"/>

<!-- Realiza o deploy para a Vivo -->
<target name="deployVivo">
<!-- Atribui a propriedade 'operadora' que
será utilizada no restante do script -->
<property name="operadora" value="Vivo"/>

<!-- Chama a tarefa fazerDeploy -->
<antcall target="gerarJAR" />

<!-- Chama a tarefa fazerDeploy -->
<antcall target="executarMIDlet" />
</target>

<!-- Realiza o deploy para a Claro -->
<target name="deployClaro">
<property name="operadora" value="Claro" />
<antcall target="gerarJAR" />
<antcall target="executarMIDlet" />
</target>

<!-- Gera o JAR -->
<target name="gerarJAR" depends="compilar" >
<wtkpackage
autoversion="${do-autoversion}"
bootclasspath="${wtk.libs}"
jadfile="${work.dir}/deployed/${project.name}.jad"
jarfile="${work.dir}/deployed/${project.name}.jar"
libclasspath=""
obfuscate="${do-obfuscate}"
preverify="true">

<fileset dir="${work.dir}/bin/"/>
<fileset dir="${work.dir}/resources/"/>
</wtkpackage>
</target>

<!-- Compila os arquivos *,java-->
<target name="compilar" depends="preverificar" >
<wtkbuild
bootclasspath="${wtk.libs}"
destdir="${work.dir}/bin/"
encoding="UTF-8"
preverify="false"
source="1.3"
sourcepath=""
srcdir="${work.dir}/preverified/"/>
</target>

<!-- Efetua o pré-processamento dos arquivos
*.java utilizando as diretivas -->
<target name="preverificar"
depends="copiarCodigoFonte" >

<wtkpreprocess
debuglevel="info"
destdir="${work.dir}/preverified/"
printsymbols="true"
srcdir="${work.dir}/classes"
verbose="true">

<!--Carrega o arquivo de
símbolos da operadora-->
<symbols_file name="${operadora}.symbols/"/>
</wtkpreprocess>
</target>

<!-- Copia os arquivos *.java para
o diretório de build -->
<target name="copiarCodigoFonte"
depends="copiarRecursos" >

<copy overwrite="true" todir="${work.dir}/classes/">
<fileset dir="src" includes="**/**.java"/>
</copy>
</target>

<!-- Copia os arquivos de recurso para o diretório de build -->
<target name="copiarRecursos"
depends="criarDiretorios">

<copy file="Application Descriptor"
tofile="${work.dir}/deployed/${project.name}.jad"/>

<copy todir="${work.dir}/resources/">
<fileset dir="res/${operadora}"
excludes="**/**.java"/>
</copy>
</target>

<!-- Cria os sub-diretórios do diretório de build -->
<target name="criarDiretorios" depends="limparTudo" >
<!-- Dir onde ficarão JAR e JAD -->
<mkdir dir="${work.dir}/deployed/"/>
<!-- Dir onde *.java pré-processados ficarão -->
<mkdir dir="${work.dir}/preverified/"/>
<!-- Dir onde *.java serão copiados de /src -->
<mkdir dir="${work.dir}/classes/"/>
<!-- Dir dos recursos (imagens, áudio, etc) -->
<mkdir dir="${work.dir}/resources/"/>
<!-- Dir onde os *.class serão compilados -->
<mkdir dir="${work.dir}/bin/"/>
</target>

<!-- Apaga todo o diretório de build -->
<target name="limparTudo">
<delete dir="${work.dir}" failonerror="false"/>
</target>

<!-- Executa o JAR/JAD no emulador -->
<target depends="" name="executarMIDlet">
<wtkrun
jadfile="${work.dir}/deployed/${project.name}.jad" />
</target>

</project>


Como vocês puderam notar, diversas linhas do scrpit utilizam a notação ${variavel}. Isso representa uma propriedade ou um símbolo. Os símbolos estão definidos nos arquivos *.symbols e são usados para o pré-processamento. Já as propriedades são definidas no arquivo meubuild.properties (ou individualmente como é feito com a propriedade "operadora". O arquivo meubuild.propreties ficou da seguinte forma:

# Diretório raiz do WTK
wtk.home=C\:\\WTK2.5.2_01
# Deve obfuscar?
do-obfuscate=false
# Versão do MIDP e do CLDC
wtk.midp.version=2.0
wtk.cldc.version=1.1
# MIDlet deve ser auto versionado?
do-autoversion=false
# JAR do Antenna
antenna.lib=C\:\\nglauber\\J2ME\\antenna-bin-1.2.1-beta.jar
# JARs necessários na compilação
wtk.libs=C\:\\WTK2.5.2_01\\lib\\midpapi20.jar:C\:\\WTK2.5.2_01\\lib\\cldcapi11.jar:
# Nome do projeto
project.name=ExemploAnt
# Diretório de build
work.dir=output

Para executar o script de build, arraste esse arquivo para a view Ant do Eclipse. Se não estiver visível, acesse o menu Window > Show View > Other..., na janela que for exibida escolha Ant. Feito isso, basta dar um duplo-clique sobre a tarefa deployVivo ou deployClaro.

O resultado será similar a figura abaixo:



Quem quiser mais detalhes pode dar uma olhada no artigo que escrevi pra Web Mobile 29.

4br4ç05,
nglauber

Um comentário:

CortezGuitar disse...

Parabens pelo post kra!