Continuous Deployment no Android: como usar a Publishing API para automatizar seu release

Júlio Zynger
Android Dev BR
Published in
9 min readMay 10, 2016

Apesar de uma prática já bem estabelecida dos círculos de desenvolvimento de software, principalmente do lado back-end, a Entrega Contínua (Continuous Delivery, no inglês) e a Implantação Contínua (Continuous Deployment) ainda dão seus primeiros passos no desenvolvimento mobile.

Neste artigo, vou apresentar a Publishing API (que faz parte da Google Play Developer API), como interagir com seus recursos e eventualmente possibilitar a prática do Continuous Deployment para apps Android. Mas, antes:

Continuous Deployment?

Em linhas gerais, o que é a prática do Continuous Deployment, e por que eu devo me importar com isso?

Se o seu time utiliza metodologias ágeis para desenvolvimento, você já deve conhecer as vantagens de se ter pequenos ciclos de desenvolvimento. A ideia por detrás da entrega contínua é possibilitar que o software possa ser construído, testado, e que gere valor mais rapidamente e mais frequentemente.

A prática foi muito bem descrita e popularizada por Jez Humble e David Farley através de seu livro, e já são muitas as grandes empresas que a utilizam no dia-dia (exemplos são Google, Yahoo, Facebook, entre outras).

Note que usei o termo entrega contínua acima. E qual a diferença entre Continuous Delivery e Continuous Deployment? O autor do famoso livro sobre Refactoring, Martin Fowler, tweetou algo que clareia bastante as coisas, na minha opinião:

Continuous Delivery significa que você garantirá que todas as mudanças poderão ser implantadas em produção. Continuous Deployment significa que você implantará todas as mudanças.”

Então, basicamente, a ideia do Continuous Deployment é que você seja capaz de buildar, testar e fazer seus releases automaticamente, de forma que o processo se torne até mesmo transparente no dia-dia de desenvolvimento.

Mas Júlio, o que acontece se eu fizer um bad merge no meu projeto? Meu usuários vão receber esses updates sem meu controle!

A vantagem do Continuous Deployment é que a prática também favorece o controle desses riscos: fazer micro-releases de forma frequente é uma ótima forma de descobrir problemas tão cedo quanto aparecem e eventualmente corrigí-los. O próprio Jez Humble tem um tweet muito interessante respondendo a seguinte pergunta:

"Como você recomendaria Continuous Delivery para uma empresa que se vê inerentemente mais aversa a riscos do que os Spotifies por aí no mundo?"
"Eu acredito que Continuous Delivery se torna até mesmo mais importante quando se é averso a riscos. Big-bang releases são horrivelmente arriscados."

Uma vez apresentado o conceito do Continuous Delivery e do Continuous Deployment, vamos passar o foco para como implementá-las no Android. Se você ainda tem interesse no assunto, existe muito material para pesquisa por aí. Além dos links e livros citados acima, recomendo este aqui como um bom começo do aprendizado aprofundado no tema.

Configuração do projeto

Antes de escrever qualquer linha de código, serão necessários alguns passos de configuração do seu projeto para que o mesmo possa ser acessado e ter suas propriedades alteradas de forma automatizada.

Começaremos pelo Google Developer Console: uma vez logado no console de configuração, precisamos gerar credenciais para que o robô que vamos construir possa acessar as APIs do Google.

Crie um projeto no console se já não existir, e no painel Visão Geral, vamos procurar pela Google Play Android Developer API:

No painel de Credenciais, você deverá criar uma nova Chave da conta de serviço (em inglês, service account key):

O console gerará um arquivo JSON que contém as configurações de acesso da sua conta; dentre estas, são importantes para nossa motivação três delas: o private_key_id, private_key e o client_email:

Chave da conta de serviço gerada pelo console, em formato JSON

Mantenha este JSON salvo, pois o mesmo será usado como chave de acesso à API pelo seu robô.

Conteúdo do arquivo secret.pem

O conteúdo do campo private_key deverá ser extraído para um arquivo secret.pem que servirá como chave secreta das transações que serão executadas junto à API. Para isso, basta criar o arquivo como o exemplo ao lado (note que substituí todos os caracteres \n por quebras de linha).

Uma vez com sua chave de acesso do serviço e sua chave privada secret.pem, podemos fazer a vinculação do projeto no Google Play Store Console: na aba lateral Configurações, Acesso à API, precisamos Vincular o projeto criado no Google Developer Console à esta conta da Google Play Store (para isto basta encontrar o identificador do projeto na lista e clicar no botão “Vincular”):

Vinculando o projeto à conta da Google Play Store

Após este passo, na mesma tela, precisamos conceder acesso à conta de serviço que criamos anteriormente. Note que o identificador que deve aparecer nesta listagem é o valor do campo client_email da chave da conta de serviço que foi gerada.

Após estes passos de configuração do projeto e do acesso aos dados de conta da Google Play Store, estamos prontos para escrever a implementação que interagirá com a Google Play Android Developer API.

Android Publisher

A Google Play Android Developer API engloba dois conjuntos de recursos que podem ser acessados uma vez feita a configuração no console de desenvolvedor:

  • Subscriptions and In-App Purchases API
  • Publishing API

A primeira permite interação e configuração de dados de In-App products, leitura de status de produtos comprados pelos seus usuários, além de ajustes sobre produtos recorrentes e subscriptions. Essa API pode ter várias aplicações interessantes, desde a alteração dinâmica de preços dos itens de um jogo que você tenha desenvolvido, até a disponibilização dos dados de compras em um dashboard que você construiu. Todo o acesso é feito via REST.

Recursos acessíveis através da Publishing API

A Publishing API, por outro lado, é a que estamos realmente interessados para o escopo deste artigo. É através dela que vamos manipular os dados de publicação dos apps na Google Play Store, fazer o upload de APKs e screenshots, além da mesma possibilitar a manipulação dos pacotes entre Tracks de publicação (alpha, beta, staged rollout e production). Esta também é uma API REST, com limite de até 200 mil requisições gratuitas por dia, mas o Google disponibilizou clientes Java e Python para facilitar a comunicação e o desenvolvimento de robôs. Devido à familiriadade que todo desenvolvedor Android tem com a linguagem, vamos seguir a partir daqui usando o cliente Java.

Uma vez criado o seu projeto Java (lembrando que é Java puro, não precisamos do Android SDK para escrever nosso robô), vamos incluir o Android Publisher como dependência. Isso pode ser feito via Maven ou via gradle, como segue:

Para poder manipular o AndroidPublisher, primeiro precisamos instanciar como sua dependência um GoogleCredential. Isso será feito passando como parâmetros os valores da service account key que geramos anteriormente, mais especificamente a chave secret.pem, o client_email e o private_key_id, da seguinte forma:

Instanciando um GoogleCredential: os valores das constantes devem ser alteradas para os valores gerados para você pelo console de desenvolvedor do Google

Com isso poderemos finalmente instanciar o AndroidPublisher, que servirá como ponto de contato entre nosso robô e a API de configuração do Google Play:

Instanciando o AndroidPublisher: note que a constante PACKAGE define o pacote da aplicação que será alterada pelo robô. Se você precisar alterar mais de um app por vez, precisará instanciar vários AndroidPublishers.

Todas as interações que serão feitas com a API acontecerão através de sua instância do AndroidPublisher, e em sua maioria seguirão “uma mesma fórmula”:

Pense na coleção de edits do AndroidPublisher como uma árvore de commits do seu VCS favorito: você pode executar algumas operações sobre esta árvore, sendo a mais interessante o insert. Ao inserir uma alteração na árvore de edits, a API construirá um AppEdit cujo identificador serve como um id da transação atômica (mais sobre isso a seguir).

Após realizar as mudanças que você considerar (entre elas podem estar alterar a descrição do aplicativo, fazer upload de novas screenshots e de um novo APK, alterar o texto do “o que há de novo”, etc), será necessário validar e commitar estas alterações. Se por algum motivo o AppEdit não for capaz de ser validado (por exemplo, a descrição do app ultrapassa o número máximo de caracteres da Play Store) ou commitado (por exemplo, já foi feito um commit com o mesmo transactionId), todo o AppEdit será revertido, e não terá efeito (dessa forma, os AppEdits se comportam como transações atômicas).

Atualizando um app

Vamos supor então que após configurar o seu projeto com o AndroidPublisher, você preparou uma nova versão do seu app e está pronto para atualizá-lo na Google Play Store.

Para realizar essa atualização, seguiremos a “fórmula” acima e faremos três interações com a API antes de commitar a edição:

  • Upload do novo APK
  • Atribuição deste APK enviado a uma Track de publicação
  • Atualização do campo de texto “o que há de novo”

O processo é bem simples: vamos carregar o APK através da API nativa de arquivos do Java, instanciar um FileContent com ele, e chamar o método upload do recurso apks do AndroidPublisher:

Uma vez enviado para a Play Store, vamos reutilizar o versionCode gerado para atribuir o novo release à uma Track de publicação, que pode ser alpha, beta, staged rollout ou production. Isso será definido pelo parâmetro trackId, uma String cujos valores são os nomes das Tracks (a exceção é a trilha de staged rollout, cuja chave é somente ‘rollout’, e que permite utilizar o método setUserFraction para determinar a porcentagem da base de usuários que receberá a atualização).

O passo final é atualizar o texto de mudanças da atualização do app, também conhecido como recent changes. Fazer isso é muito simples através da API de ApkListings, basta atribuir a propriedade através de um setter.

Note porém, o parâmetro language: um mesmo APK (definido através do versionCode) pode ter múltiplos textos de recent changes baseados na linguagem da Store (por exemplo ‘en-US’ para inglês americano, ‘pt-BR’ para português brasileiro e assim por diante).

O código completo da rotina ficaria da seguinte forma:

Da mesma forma que interagimos com os resources Apks, Tracks, e ApkListings, a API do AndroidPublisher fornece acesso a vários outros recursos que podem ser editados, desde descrições do aplicativo, comunidades do Google+ e Google Groups registradas como beta testers até informações de contato do desenvolvedor. Toda a documentação e os atributos de cada classe de modelo estão descritas na página de referência da API do publisher.

Alternativas

É sempre bom conhecer como funcionam as APIs sobre as quais seu projeto pode depender, principalmente quando se trata de alterar configurações em produção, mas se o seu caso de uso para a Publishing API não precisa ser tão específico, existem dois excelentes plug-ins que encapsulam a lógica de interação com a API e facilitam o trabalho de integração.

Ambos são projetos open-source, já bem testados e com ampla utilização pela comunidade. Se necessário para sua aplicação, seria simples fazer um fork do plugin escolhido e alterar o código, mas em geral, ambos os plugins já atendem os requisitos da maioria dos projetos que implantam o continuous deployment em Android.

Note que…

Ao contrário dos ambientes de entrega e implantação Web, quando se trata de desenvolvimento mobile, entretanto, é importantíssimo lembrar a forma como seu aplicativo vai ser distribuído para seus usuários.

Ao implantar um pipeline de distribuição integrado ao Google Play, vale lembrar que a cada novo release da sua aplicação, os usuários precisarão fazer o download do novo APK. Em países onde o custo de banda móvel é alto (como é o caso dos países emergentes), isso pode ser problemático, especialmente se seu aplicativo for pesado (>6 MB).

Além disso, se sua nova aplicação alterou o conjunto de permissões do pacote e não dá suporte ao novo sistema de permissões do Android Marshmallow, estas atualizações precisarão da autorização do usuário para serem baixadas, o que aumenta o número de passos necessários para se ter o app atualizado.

Entretanto, vale lembrar que o Google Play oferece trilhas de distribuição diferentes para conjuntos de usuários. Os beta-testers do seu app estarão dispostos a receber tantas atualizações quanto possíveis ao longo do ciclo de desenvolvimento do seu time, e portanto, é menos provável que estes usuários se sintam desconfortáveis com o processo de deployment contínuo.

Todo o código do projeto de exemplo (e do aplicativo-teste que desenvolvi para colocar no pipeline de deployment contínuo) estão disponíveis aqui. Também fiz apresentações sobre este assunto, com alguns detalhes a mais, em alguns eventos no Brasil, seguem os slides:

--

--