Android

28 out, 2015

Gerenciando suas chaves no Android de forma eficiente

Publicidade

Vamos considerar que você já desenvolveu seu aplicativo matador, que vai te gerar milhões de reais em 2 dias, e agora vai gerar a sua build de release para publicar no Google Play. Nesse caso, precisamos criar a nossa assinatura de release no arquivo build.gradle do nosso projeto. Alguma coisa mais ou menos assim:

signingConfigs {
    release {
        storeFile file('/home/rafael/minha_key.jks')
        storePassword 'senha secreta'
        keyAlias 'app_android'
        keyPassword 'senha mais secreta ainda'
    }
}

 

Mas… tem alguma coisa errada aí. Principalmente se estamos utilizando algum controle de versão, como o Git ou SVN, não é uma boa prática enviarmos dados sensíveis para eles (como senhas, keystores e coisas do tipo). Durante algum tempo, a saída utilizada por mim foi adicionar esses dados ao arquivo gradle.properties na raiz do projeto, e não enviá-lo para o controle de versão.

STORE_FILE=/home/rafael/minha_key.jks
STORE_PASSWORD=senha secreta
KEY_ALIAS=app_android
KEY_PASSWORD=senha mais secreta ainda

 

Dessa forma, a nossa configuração de assinatura ficaria algo assim:

signingConfigs {
    release {
        storeFile file(STORE_FILE)
        storePassword STORE_PASSWORD
        keyAlias KEY_ALIAS
        keyPassword KEY_PASSWORD
    }
}

 

Funciona bem, não temos dados sensíveis no nosso controle de versão. Mas… temos basicamente dois problemas principais nessa abordagem:

  • No clone do projeto, você terá um erro de build. Ou seja, se entrar alguém na equipe e clonar o projeto, baterá com a cara na porta logo de cara. Isso já vai atrasar um pouco o join no projeto. Esse problema também se aplica quando o código está em um servidor de CI (Jenkins, Travis, CircleCI etc.);
  • Tem o agravante humano, ou seja, sempre há o risco de, sem querer, você enviar o arquivo original por algum motivo. Obviamente que você pode adicionar esse arquivo ao .gitignore ou equivalente no SVN, mas nesse caso caímos no primeiro cenário problemático.

Então… qual a saída?

Depois de pensar um pouco, acabei encontrando a melhor saída com o uso de variáveis de ambiente! Como assim?

Vamos lá: o primeiro passo é criarmos uma assinatura default para o projeto. No meu caso, eu simplesmente copio a debug.keystore (que fica dentro da pasta .android do  usuário) e coloco, por exemplo, dentro de um diretório chamado distribution na raiz do meu projeto. Essa chave vai garantir que a build não vai quebrar quando alguém clonar o projeto ou em um servidor de CI, por exemplo, em um primeiro momento.

Agora, na configuração da minha assinatura, podemos fazer algo do tipo:

signingConfigs {
    release {
        storeFile file(System.getenv('STORE_FILE') != null ? System.getenv('STORE_FILE') : '../distribution/debug.keystore')
        storePassword System.getenv('STORE_PASSWORD') != null ? System.getenv('STORE_PASSWORD') : 'android'
        keyAlias System.getenv('KEY_ALIAS') != null ? System.getenv('KEY_ALIAS') : 'androiddebug'
        keyPassword System.getenv('KEY_PASSWORD') != null ? System.getenv('KEY_PASSWORD') : 'android'
    }
}

 

Nota: caso seu servidor de CI esteja gerando builds de release, você pode setar as variáveis de ambiente nele também para gerar builds assinadas corretamente.

E pronto! Agora, para gerar a build corretamente, você pode exportar as variáveis de ambiente ou, como eu faço, colocar os dados da chave no comando apenas na hora de gerar a build de release:

$ STORE_FILE='/home/rafael/minha_key.jks' STORE_PASSWORD='senha secreta' KEY_ALIAS='app_android' KEY_PASSWORD='senha mais secreta ainda' ./gradlew clean assembleRelease

 

E é isso! Espero que a dica seja útil para vocês e, caso tenham sugestões, podem postar aí nos comentários =). Até a próxima!

***

Artigo originalmente publicado no blog pessoal do autor. Veja aqui.