Concrete Logo
Hamburger button

Como fazer Integração Contínua no Android – parte 1

  • Blog
  • 10 de Março de 2014
Share

Por que Integração Contínua?

O tempo de pedir para o sobrinho fazer o aplicativo mobile da sua empresa passou. Não dá mais para encarar o ambiente mobile como um “puxadinho” de TI. Mobile é um canal altamente visado pelos usuários e, consequentemente, pelas empresas. A chance de que os próximos prospects do seu produto cheguem a ele pelo canal mobile cresce a cada ano que passa.

Por todos estes motivos deve-se pensar em qualidade e, portanto, assim como não se pensa mais em software com qualidade sem Integração Contínua (IC) no backend e web, o mesmo tem que valer para o ambiente mobile levado a sério.

Primeiros passos, teoria: ciclo de compilação, testes e empacotamento do aplicativo

IC é a automatização do ciclo de compilação, testes, empacotamento, deploy e testes integrados com relatórios de cada fase. Conforme o desenvolvedor faz uma alteração e atualiza o repositório de código, um servidor irá disparar esse ciclo para garantir que nada foi quebrado e que temos um artefato pronto para ser distribuído (e aí temos entrega contínua…). Para aqueles que preferem um gráfico a mil palavras:

Topologia IC Mobile

Assim, precisamos nos desvencilhar da IDE (Eclipse, IntelliJ, etc) e automatizar tudo para que uma simples linha de comando possa fazer tudo. Claro que existem ferramentas que nos ajudam a conseguir este resultado mas, nesse assunto, o Android tem uma longa história…

Assim que o Android foi lançado, tínhamos apenas o ANT como ferramenta para scriptar os passos de compilação, testes e empacotamento. Depois de algum tempo a comunidade foi criando projetos para facilitar estas etapas. Assim, hoje o mundo está mais diversificado. Além do ANT temos também o Maven e o Gradle.

Todas estas ferramentas podem ser usadas no servidor de integração contínua. Delas, o ANT é talvez a mais verbosa. Nos círculos undergrounds Javísticos, o ANT é visto como uma DSL em XML, ou seja, uma linguagem de programação para um domínio específico em que sua sintaxe é inteiramente XML. Nada muito animador… Querem ver um pedaço de ANT?

[code language=”xml”]
<!– if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir –>

<property environment="env" />

<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
[/code]

Neste “código” ANT temos a definição de uma propriedade e um “if” que seta o valor de uma variável.

Tendo em vista este panorama, algumas pessoas criaram um plugin de MAVEN altamente configurável que permite trabalhar com Android. Trata-se do android-maven-plugin. Com ele temos todo o ciclo de vida do processo de build (geração do artefato) mapeado (também em XML) com um modelo pré-definido: o POM (Project Object Model). Neste descritor definimos as dependências, os plugins de execução, os repositórios nos quais vamos buscar estas dependências e plugins, definimos pasta de código fonte e etc. Segue um exemplo:

[code language=”xml”]
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.rg/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0"https://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>br.com.olinasc.improvavel</groupId>
<artifactId>Improvavel</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>apk</packaging>

<name>Improvavel</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!– Plugins –>
<android-maven-plugin.version>3.8.1</android-maven-plugin.version>
<maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version>
<api.platform>16</api.platform>
<!– Dependencies –>
<android.version>4.1.1.4</android.version>
</properties>

<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<scope>provided</scope>
<version>${android.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>${android-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<sdk>
<platform>${api.platform}</platform>
</sdk>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
[/code]

O Maven é uma ferramenta altamente complexa e muito utilizada pelos desenvolvedores Java. Falaremos com mais detalhes sobre o MAVEN a partir da parte 2 desta série. Fique tranquilo se este XML não significar muita coisa por enquanto 😀

No entanto, o Google decidiu não dar um suporte oficial ao Maven. Na verdade, ele o suporta parcialmente e paralelamente. Os artefatos do Android não estão no repositório central do MAVEN. Ao invés disso, o Google permite que seja baixado um repositório local pelo Android SDK Manager, forçando assim que o desenvolvedor aceite a licença do sistema antes de começar a desenvolver. Como veremos, isso será o suficiente para utilizarmos o MAVEN.

Mesmo que não esteja oficialmente suportado, a comunidade em volta deste plugin é altamente ativa. Muitas bibliotecas abertas de terceiros já estão disponíveis via MAVEN como a Universal Image Loader, todas as bibliotecas do portal da Square e muitas outras (ActionBarSherlock deve ser, talvez, a mais famosa).

Fora o ANT e o MAVEN temos ainda o Gradle, mais nova ferramenta de build suportada oficialmente pelo Google (apenas na IDE Android Studio, ainda em beta). Este suporte inicial ainda é recente, porém a ferramenta em si é também bastante tradicional no ambiente Java. Ela basicamente é uma mistura entre o ANT e o MAVEN sendo uma DSL (domain specific language) inteira como o ANT com a sintaxe Groovy (uma linguagem executada por sobre a JVM), porém possui as fases pré-definidas do MAVEN e também o sistema de repositório de dependências.

Finalmente, Integração Contínua!

Quando tivermos configurado todo aquele ciclo de compilação e etc, precisaremos de um servidor de integração contínua. Existem vários no mercado, mas nos concentraremos no Jenkins. Ele é um fork do Hudson, outro server de CI. Talvez hoje ele seja o servidor de CI mais famoso e utilizado no mundo Java.

Mas o que faz um servidor de CI? No nosso caso ele é um executor de Jobs, ou seja, passos que configuramos dentro dele. Um passo pode monitorar um repositório de código, disparar outro job, criar um pacote executável e qualquer outra coisa que seja possível executar da linha de comando. Falaremos muito mais sobre o Jenkins, seus tipos de Job e suas infinitas configurações nos próximos posts desta série.

Nosso fluxo de Jobs será:

  1. JOB_INSTALL: Verifica alterações no repositório de código a cada 5 minutos. Caso haja algo novo, executa a criação do pacote da aplicação e dispara o próximo job em caso de sucesso;
  2. JOB_CODE_COVERAGE: Executa os testes de instrumentação do Android em emuladores junto com a instrumentação que verifica a cobertura de código. Por fim, gera um relatório HTML;
  3. JOB_MULTI_EMULATORS: Executa os testes de instrumentação do Android em uma matriz de emuladores com diversas versões do Android OS em diversas configurações de telas.

Poderíamos ter outros jobs como geração da versão de release (assinado com a chave de release do Google Play), distribuição de pacotes por e-mail e etc. No entanto, tendo estes jobs já teremos a base da IC e fica de desafio a configuração dos outros jobs 😀