Aplicativos de assinatura
Os aplicativos Android precisam ser assinados digitalmente com um certificado antes da instalação
O Android identifica o autor do aplicativo usando este certificado,
Este certificado não precisa ser assinado por uma autoridade de certificação (você pode usar um certificado autoassinado)
Existem dois tipos de modos de assinatura
debug mode
erelease mode
No modo de depuração, você assina seu aplicativo com um certificado de depuração gerado pelas ferramentas do Android SDK. Este certificado tem uma chave privada com uma senha conhecida
Este certificado está localizado em
$HOME/.android/debug.keystore
No modo de liberação, você assina o aplicativo com seu próprio certificado (na verdade, você deve gerar seu próprio armazenamento de chaves)
Mais informações sobre como assinar o aplicativo Android
http://developer.android.com/tools/publishing/app-signing.html
Configuração de assinatura
Em
gradle
projetos baseados em Android, a configuração de assinatura deve ser especificada nos scripts de compilação do GradleA seguir estão os detalhes que precisam ser especificados no script de compilação do Gradle
- keystore (localização)
- senha do keystore
- nome de alias da chave
- senha chave
- O tipo de loja
Na versão de depuração, você não precisa especificar nenhum desses detalhes, ele obtém automaticamente os detalhes do certificado de depuração
Mas o sistema de construção não assina a versão de lançamento, a menos que você defina explicitamente uma configuração de assinatura para a construção, portanto, no tipo de lançamento, você deve especificar os detalhes acima no arquivo de construção do gradle
O restante deste artigo fornece informações detalhadas sobre como especificar a configuração de assinatura de versão
Estrutura de diretório
- A seguir está a estrutura do meu projeto
- Tenho um
senz
aplicativo emScore
projeto, estou definindo configurações de assinatura em arquivo no aplicativo (uma vez que é meu aplicativo principal)build.gradle
senz
Basta definir as configurações de assinatura de versão
- Lançamento da primeira cópia no aplicativo
key-store
senz
- Em seguida, defina os detalhes do armazenamento de chaves no arquivo (é necessário adicionar na seção no arquivo de compilação)
build.gradle
android
android {
...
signingConfigs {
release {
storeFile file("release-key.keystore")
storePassword 'passwotd'
keyAlias 'alias'
keyPassword 'password'
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
debug {
debuggable true
}
}
}
...
- Agora execute o seguinte comando na linha de comando
./gradlew assembleRelease
Ele irá gerar o apk de lançamento –
Score/senz/build/apk/senz-release.apk
Na configuração de assinatura acima, defini todos os armazenamentos de chaves e senhas de chaves em meu arquivo gradle, não é uma boa prática de segurança
Para resolver o problema de segurança, você pode especificar o prompt do processo de construção para essas senhas (se você estiver construindo a partir da linha de comando)
Senha de prompt com arquivo de compilação do Gradle
- Você pode obter as senhas de
System.console()
storePassword System.console().readLine("\nKeystore password: ")
keyPassword System.console().readLIne("\nKey password: ")
- Portanto, o arquivo de compilação seria semelhante a abaixo
android {
...
signingConfigs {
release {
storeFile file("release-key.keystore")
storePassword System.console().readLine("\nKeystore password: ")
keyAlias 'alias'
keyPassword System.console().readLIne("\nKey password: ")
}
}
...
}
...
- Quando você compila a partir da linha de comando, ele solicitará as senhas
- Existem vários problemas com esta abordagem também
Problema 1 – A senha será solicitada sempre
Esta senha será solicitada sempre,
Por exemplo, se você limpar o build , ele pedirá uma senha
./gradlew clean
Para resolver esse problema, podemos usar gradle
TaskExecutionGraph
http://www.gradle.org/docs/current/javadoc/org/gradle/api/execution/TaskExecutionGraph.htmlAo usar o taskGraph, podemos restringir o prompt de senha para tarefas de construção específicas
Portanto, podemos restringir a solicitação de senha quando apenas
assembleRelease
gradle.taskGraph.whenReady { taskGraph ->
if(taskGraph.hasTask(':senz:assembleRelease')) {
password = System.console().readPassword("\nEnter password: ")
password = new String(password)
if(password.size() <= 0) {
throw new InvalidUserDataException("Empty password")
}
// set signing config key passwords
android.signingConfigs.release.storePassword = password
android.signingConfigs.release.keyPassword = password
}
}
android {
...
signingConfigs {
release {
storeFile file("release-key.keystore")
storePassword ''
keyAlias 'alias'
keyPassword ''
}
}
...
}
- Isso pedirá apenas uma senha
assembleRelease
e atribuirá a senha em senhas de configuração de assinatura (estou usando uma senha para armazenamento de chaves e chave, então posso ter a mesma senha para ambos os valores)
Neste código que estamos usando em vez de , functions retorna uma matriz char. Portanto, é necessário convertê-lo em String, caso contrário, a construção falhará
System.console().readPassword()
readLine()
readPassword()
SignConfigs.release
senhas definidas como vazias, uma vez que as lemos viataskGraph
android {
...
signingConfigs {
release {
storeFile file("release-key.keystore")
storePassword ''
keyAlias 'alias'
keyPassword ''
}
}
...
}
Problema 2 – Sem console
Se você executar a compilação acima no Android Studio, não houver System.console (), ele retornará nulo
Portanto, a compilação falhará no AndroidStudio
Aqui, em vez de obter a senha do console, podemos solicitá-la na caixa de diálogo quando não tiver o console (na verdade, ao executar a versão do AndroidStudio)
O código a seguir fará isso por meio de
Groovy SwingBuilder
import groovy.swing.SwingBuilder
...
gradle.taskGraph.whenReady { taskGraph ->
if(taskGraph.hasTask(':senz:assembleRelease')) {
def password = ""
if (System.console() == null) {
new SwingBuilder().edt {
dialog(modal: true,
title: "Enter password",
alwaysOnTop: true,
resizable: false,
locationRelativeTo: null,
pack: true,
show: true
) {
vbox {
label(text: "Enter password: ")
input = passwordField()
button(defaultButton: true,
text: 'OK',
actionPerformed: {
password = input.password;
dispose();
})
}
}
}
} else {
password = System.console().readPassword("\nEnter password: ")
password = new String(password)
}
if (password.size() <= 0) {
throw new InvalidUserDataException("Empty password")
}
}
}
android {
...
}
Mais sobre Groovy SwingBuilder
http://groovy.codehaus.org/GUI+Programming+with+Groovy
http://groovy.codehaus.org/Swing+BuilderObserve que, no mac acima, o código pode gerar uma exceção
Error:(10) java.awt.AWTError: Toolkit not found: apple.awt.CToolkit
> Toolkit not found: apple.awt.CToolkit
- Fiz upload do meu arquivo completo para github https://github.com/erangaeb/dev-notes/blob/master/gradle/Score/senz/build.gradle
build.grade
Referência
- http://developer.android.com/sdk/installing/studio-build.html
- http://developer.android.com/tools/publishing/app-signing.html
- http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Signing-Configurations
- https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/
- https://www.timroes.de/2014/01/19/using-password-prompts-with-gradle-build-files/
- http://gmariotti.blogspot.com/2013/10/common-tips-about-gradle.html