Configurando Jenkins para Apps Android

Guilherme Conti
Serasa
Published in
12 min readJun 26, 2019

Se você trabalha em um aplicativo Android com uma grande equipe, eventualmente, verá problemas para testar e gerenciar todos os recursos que estão sendo desenvolvidos. Principalmente porque é comum que seu aplicativo seja composto de várias bibliotecas desenvolvidas por sua equipe. Assim, toda vez que você estiver trabalhando em algumas de suas bibliotecas, para testá-lo corretamente, você terá que montar o aar desta biblioteca e, em seguida, importá-la para o seu aplicativo principal. Isso já é ruim se você está trabalhando sozinho e se torna um pesadelo quando tem uma equipe inteira que está trabalhando no aplicativo que depende da atualização dessa biblioteca e precisa distribuir as versões do seu App para a equipe de controle de qualidade para que ele possa testá-la.

Para facilitar nossas vidas, construiremos um CI simples que visa tornar cada etapa o mais automatizada e integrada possível. Para conseguir isso, precisamos:

  • Um aplicativo para Android com ou sem bibliotecas. Neste tutorial, mostrarei como implantar bibliotecas também
  • Uma instância do Jenkins que será responsável por criar e implantar nossos Aplicativos / Bibliotecas
  • Um repositório git para manter nosso aplicativo / bibliotecas. Aqui estaremos usando o Bitbucket
  • Artifactory para implantar nossas bibliotecas
  • HockeyApp para realizar o deploy dos nossos Apps

Configurando o Jenkins

Vamos começar instalando alguns dos plugins que usaremos no Jenkins.

Todos os plugins do Bitbucket que usaremos para verificar nosso status de repositório, commits, branches e PRs. Há também plugins para o Github e se você estiver usando outro gerenciador de repositório Git você pode criar um pipeline Git genérico (eu falarei sobre isso depois), a principal desvantagem é que você não será capaz de verificar PRs / MRs com um pipeline de Git genérico.

Ok, com isso fora do caminho, é hora de adicionar o Android SDK ao nosso Jenkins. Para isso, você precisará ter acesso ao seu terminal de instância do Jenkins.

Primeiro, vamos instalar o Java JDK executando

sudo apt-get install java-8-openjdk

Então vamos instalar o unzip para que possamos usá-lo para instalar o android-sdk mais tarde

sudo apt-get install unzip

Agora baixe e unzipe o android-sdk executando

sudo wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zipmkdir android-sdkunzip sdk-tools-linux-3859397.zip -d android-sdk

A última coisa que precisamos fazer é aceitar os termos de licença para usarmos o SDK do Android

yes | android-sdk/tools/bin/sdkmanager --licenses

Ok, agora o Android SDK está instalado e pode ser usado apropriadamente pelo Jenkins. Apenas certifique-se de que o usuário do Jenkins tenha permissões de gravação na pasta android-sdk.

Para que o jenkins possa usar o SDK do Android, primeiro precisamos definir a variável global ANDROID_HOME com o caminho do nosso SDK. Para isso, vá para o seu Página inicial do Jenkins -> Gerenciar Jenkins -> Gerenciar sistema -> Desça até Propriedade globais e adicione:

Mude o valor para o caminho do seu Android SDK e salve

Ok, agora o Jenkins está configurado e pronto para começar a criar as nossas pipelines.

Criando Pipelines

Primeiro, certifique-se de reiniciar seu Jenkins para que todas as alterações entrem em vigor. Agora vamos vincular nosso repositório com um multibranch pipeline Jenkins. O multibranch pipeline é um recurso do Jenkins que permite que uma tarefa seja executada individualmente para várias branchs de um repositório. Vamos criar um novo job de multibranch pipeline clicando em Abrir Blue Ocean -> Novo pipeline -> Selecione o tipo de repositório que usa para os seus gits (selecione Git se não utilizar Bitbucket ou Github) -> Faça o login e selecione o seu repositório (se você está usando o modo de Git genérico cole a URL do seu repositório e as credencias do seu login). O resultado final irá se parecer mais ou menos assim

Ele vai reclamar que nosso repositório não tem um arquivo Jenkins, vamos configurar isso depois. Para enquanto vá para a página criada para o seu job do Jenkins e clique em Configure. Aqui vamos colocar algumas configurações para melhorar o nosso job. Primeiro certifique-se de que a opção Descoberta de branches tenha a estratégia Todas as branches selecionada.

Em Descubra pull requests pela origem você tem 3 opções. O primeiro, para cada PR aberto, executará o trabalho em uma branch mergeada “simulada”. O segundo executará o trabalho somente na branch que está sendo solicitada para ser mergeada. E o último vai rodar os dois. Para este exemplo, selecionaremos apenas a primeira opção, pois a execução da tarefa na branch mergeada simulada é a melhor maneira de garantir que o nosso merge esteja pronto para ser aceito se nosso job for bem-sucedido.

Agora, precisaremos adicionar um novo comportamento que informará a Jenkins em quais branchs ele deve executar o job. Clique em Adicionar e então selecione Filtre por nome (usando coringa) então digite quais branchs você quer rodar o seu job, lembre-se de adiciona PR-* para aceitar PRs. Para o nosso exemplo nós vamos rodar nas branchs develop, master e todas as PRs.

Para finalizar essa configuração, a última coisa que precisamos fazer é pedir ao Jenkins para examinar periodicamente nosso repositório para que ele possa executar novos jobs em toda nova atualização do repositório. Role para baixo até Scan Multibranch Pipeline Triggers e selecione Periodically if not otherwise run e selecione o intervalo o qual deseja examinar o seu repositório. Para esse exemplo eu selecionarei 1 minuto.

É importante mencionar que examinar periodicamente o repositório não é a melhor forma de verificar quando novos jobs devem ser executados. Nos podemos realizar isso enviando um webhook do nosso repositório toda a vez que um commit for realizado em uma das branchs que especificarmos, desta forma nós não examinamos o repositório atoa caso nenhuma atualização tenha sido feita. Você pode ler mais sobre webhook no Bitbucket aqui.

Criando Jenkinsfile

Agora que nosso Jenkins está pronto, a última coisa a se fazer é dizer a ele o que cada trabalho deve executar. Para fazer isso, criaremos um Jenkinsfile na raiz do nosso repositório, que informará exatamente quais etapas o Jenkins deve executar. Como nosso objetivo é construir um APK / AAR e enviá-lo para o Artifactory, a primeira coisa que devemos adicionar ao nosso arquivo Jenkins é o processo completo da build do Android.

A estrutura do nosso Jenkinsfile será a seguinte: Primeiro, escolhemos onde nosso pipeline será executado, definindo um agente em nosso arquivo Jenkins. Nós não entraremos em detalhes sobre agentes e você pode ler mais sobre toda a estrutura do Jenkinsfile aqui. Para este tutorial nós iremos usar o agente default, já que não nos importamos em qual agente o nosso Jenkins irá executar. Em seguida, criaremos nossos estágios para cada estágio do processo de build. Para o nosso pipeline, vamos criar 4 etapas:

  • Detect build type — Irá verificar se estamos executando o trabalho para develop ou master, para que possamos saber se estamos construindo com a variante de debug ou release.
  • Compile — Compila o nosso projeto usando as tarefas do Gradle
  • Build — Builda o APK/AAR do nosso projeto usando as tarefas do Gradle
  • Publish — Envia o nosso APK/AAR para o Artifactory

Antes de começarmos a criar os nossos estágios, primeiro precisamos criar a base em que osnossos estágios irão executar. Nós fazemos isso criando um arquivo chamado Jenkinsfile na raiz do app / library e incluindo o seguinte código.

pipeline {agent anyenvironment {APP_NAME = 'test'}options {// Stop the build early in case of compile or test failuresskipStagesAfterUnstable()}
stages {

// Put your stages here
}}

Basicamente, o que estamos fazendo aqui é criar uma pipeline que irá rodar nossas etapas com algum agente. Em seguida, criamos uma variável de ambiente que irá conter o nome do nosso aplicativo. Usaremos isso mais tarde quando arquivarmos nossa compilação. E, finalmente, nas opções, definimos que, quando um estágio falha, queremos abortar o trabalho e ignorar os estágios restantes. Com o nosso pipeline criado, agora podemos configurar nossos estágios de trabalho.

Então vamos começar a criá-los. Primeiro, para o Detect build type, verificaremos se a branch da tarefa ou a branch que recebe a pull request é develop ou master e então definimos uma variável de ambiente que usaremos em nossas etapas posteriores.

stage('Detect build type') {steps {script {if (env.BRANCH_NAME == 'develop' || env.CHANGE_TARGET == 'develop') {env.BUILD_TYPE = 'debug'} else if (env.BRANCH_NAME == 'master' || env.CHANGE_TARGET == 'master') {env.BUILD_TYPE = 'release'}}}
}

Em seguida, vamos criar o estágio Compile. Podemos fazer isso apenas executando a tarefa gradle para a variante de build correta e selecionamos nossa variante de construção com o BUILD_TYPE que criamos no último estágio.

stage('Compile') {
steps {
// Compile the app and its dependenciessh './gradlew compile${BUILD_TYPE}Sources'}}

Com nosso aplicativo compilado, estamos prontos para ir para o estágio Build. Igual à compilação, basta executar a tarefa gradle para a variante de construção correta usando o BUILD_TYPE env que criamos anteriormente.

stage('Build') {steps {// Compile the app and its dependenciessh './gradlew assemble${BUILD_TYPE}'sh './gradlew generatePomFileForLibraryPublication'}
}

Eu também inclui a tarefa generatePomFile para gerar o arquivo pom caso estejamos trabalhando com uma biblioteca.

Depois de buildarmos nosso aplicativo, o último passo é publicá-lo no HockeyApp ou no Artifactory, mas vamos segurar esse estágio por enquanto, já que ele requer mais algumas configurações. Por enquanto, vamos fazer com que nosso estágio Publish arquive somente o artefato para que possamos baixá-lo em nosso trabalho no Jenkins.

stage('Publish') {steps {// Archive the APKs so that they can be downloaded from JenkinsarchiveArtifacts "**/${APP_NAME}-${BUILD_TYPE}.apk"// Archive the ARR and POM so that they can be downloaded from Jenkins
// archiveArtifacts "**/${APP_NAME}-${BUILD_TYPE}.aar, **/*pom- default.xml*"
}
}

Agora você pode esperar 1 minuto ou clicar em Build now dentro do seu job e você deverá ver seu job rodando na sua branch. Devemos ter algo parecido com isto

E se você clica no número do job deveria ver os artefatos arquivados

Publicando nosso App

Tudo bem, agora que nosso job está buildando adequadamente nossos aplicativos, tudo o que resta é publicá-lo no HockeyApp, no Artifactory ou em um tipo diferente de repositório. Você pode até mesmo configurar seu pipeline para publicá-lo na Play Store, se quiser, você pode ler mais sobre isso aqui.

Primeiro, vamos cobrir a publicação no Artifactory. Se você não tiver uma conta Artifactory para testar isso, crie uma conta de avaliação gratuita de 14 dias aqui. Para se comunicar com o Artifactory em nosso pipeline, primeiro precisamos instalar o plugin dele no Jenkins. Vá para seus plugins e instale o Artifactory Plugin

Ok, em seguida, precisamos incluir a nossa URL e credenciais do Artifactory. Você tem duas opções para fazer isso, você pode adicioná-lo ao seu Jenkinsfile ou você pode adicioná-lo às configurações globais. Aqui vamos adicionar nossas credenciais dentro das configurações globais, se você quiser colocá-lo dentro do pipeline, você pode ver como aqui.

Na sua página de Jenkins, vá em Gerenciar Jenkins > Configurar sistema > Role para baixo até Artifactory > Clique em Adicionar Artifactory Server > Insira suas credenciais do Artifactory, você deve ter algo assim:

No ID do servidor, você pode fornecer qualquer nome que desejar. Você pode clicar em testar a conexão para ter certeza de que tudo está funcionando. Com nossa conexão Artifactory pronta, tudo o que precisamos fazer é adicionar a ação para enviar nossos artefatos. Podemos conseguir isso com o seguinte código no Pipeline

rtUpload (serverId: “Artifactory_1”,spec:“””{“files”: [{“pattern”: “*.aar”,“target”: “example-repo-local/teste-app/”}]}”””)

Adicione-o ao estágio Publish e altere o destino e execute sua build. Agora você deve ter seus arquivos enviados para o Artifactory

Ótimo, agora podemos enviar nossas bibliotecas diretamente no Artifactory sempre que quisermos. A última coisa a fazer é implantar o nosso .apk no HockeyApp.

Como no Artifactory, a primeira coisa que precisamos fazer é adicionar o plugin Hockeyapp ao nosso Jenkins.

Antes de usarmos o plug-in para enviar nossos APKs em nosso pipeline precisamos obter um token de API que será usado para autenticar nossos envios e nosso ID de aplicativo para fazer upload de nossos APKs. Primeiro para obter nosso Token de API faça login no HockeyApp> Clique na foto do seu perfil > Clique em Configurações da conta> À esquerda, vá para Tokens da API > Crie um novo token de upload para ser usado no seu aplicativo ou em todos os seus aplicativos. Salve este token, nós o usaremos em breve. Agora precisamos pegar nosso ID de aplicativo que conterá nossos apks para obtê-lo Vá para a página principal do HockeyApp > Clique no seu aplicativo (se você não tiver um, basta criar um) > No início, pegue seu ID de aplicativo. Nosso token de API pode ser adicionado diretamente no plug-in HockeyApp em Gerenciar Jenkins > Configurar Sistema> Configuração Padrão do HockeyApp > Token de API Padrão. Como o nosso token de aplicativo será alterado para cada aplicativo, nós o incluiremos no pipeline, então vamos direto para eele.

A primeira coisa que faremos é criar uma variável que mantenha o ID do aplicativo. Você pode incluí-lo dentro do environment.

environment {APP_NAME = 'test'APP_ID = 'YOUR_APP_ID'}

E agora nós só temos que adicionar a chamada Hockeyapp dentro do nosso estágio de Publish, vai ficar assim

hockeyApp (applications: [[downloadAllowed: true,filePath: “**/*.apk”,mandatory: false,notifyTeam: true,releaseNotesMethod: none(),uploadMethod: versionCreation(appId: ${APP_ID}, versionCode: '1.0.0')]],baseUrl: ‘’,debugMode: false,failGracefully: false)

Podemos agora executar o nosso job novamente (ou commitar para uma das nossas branchs) e no final, se olharmos para o nosso hockeyapp, devemos ter o APK devidamente enviado.

Versionamento

Com tudo o que fizemos até agora, nossos aplicativos estão sendo carregados para o Artifactory e o HockeyApp sem problemas. Mas no momento toda vez que implantamos uma nova versão de nosso aplicativo / biblioteca, ela substituirá a antiga. Para evitar isso, podemos implantar novas versões do nosso aplicativo usando o versionName que temos em nosso gradle dentro do nosso aplicativo. Para obter o versionName de dentro de nosso gradle, adicionaremos uma nova variável ao ambiente com um script de shell que fará isso para nós. Eu não vou mergulhar fundo em seu funcionamento, e pode ser otimizado com certeza, mas faz o trabalho.

environment {APP_NAME = ‘test’BUILD_VERSION = sh(script: ‘cat app/build.gradle | egrep -o \’versionName “(.*?)”\’ | cut -d \’ \’ -f 2- | tr -d \’”\’’, , returnStdout: true).trim()BUILD_TYPE = ‘debug’}

E para realmente usá-lo no Artifactory e no HockeyApp, nós o adicionamos aos nossos pipelines da seguinte maneira

rtUpload (serverId: “Artifactory_1”,spec:“””{“files”: [{“pattern”: “*.aar”,“target”: “example-repo-local/teste-app/${BUILD_VERSION}/”}]}”””)

E no HockeyApp

hockeyApp (applications: [[downloadAllowed: true,filePath: “**/*.apk”,mandatory: false,notifyTeam: true,releaseNotesMethod: none(),uploadMethod: versionCreation(appId: ${APP_ID}, versionCode: ${BUILD_VERSION})]],baseUrl: ‘’,debugMode: false,failGracefully: false)

E isso envolve tudo para este tutorial. Para melhorar sua CI, você pode adicionar mais estágios, como execução de testes, análise de código estático, enviar o App diretamente para a loja e muito mais. Espero que isso ajude você a entender um pouco sobre como você pode integrar seus projetos Android com o Jenkins e melhorar o ciclo de desenvolvimento da sua equipe.

Abraço!

Quer saber mais ?

Queremos estreitar relações com as comunidades e profissionais de tecnologia que queiram trocar figurinhas.

Por enquanto, os comentários aqui do Medium são nosso canal de comunicação oficial. Deixa sua mensagem para que possamos interagir ou mande um e-mail para ecs_it@br.experian.com.

--

--