Configurando Jenkins para Apps Android
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.