Como criar um arquivo apk assinado de liberação usando o Gradle?

514

Gostaria que meu Gradle fosse criado para criar um arquivo apk assinado de liberação usando o Gradle.

Não tenho certeza se o código está correto ou se estou perdendo um parâmetro ao fazer isso gradle build?

Este é um pouco do código no meu arquivo gradle:

android {
    ...
    signingConfigs {
          release {
              storeFile file("release.keystore")
              storePassword "******"
              keyAlias "******"
              keyPassword "******"
         }
     }
}

A compilação gradle termina com SUCESSO e, na minha build/apkpasta, só vejo os arquivos ...-release-unsigned.apke ...-debug-unaligned.apk.

Alguma sugestão sobre como resolver isso?

Jan-Terje Sørensen
fonte
assinar com a versão v1 (assinatura jar) ou v2 (assinatura apk completa) do arquivo gradle? solução aqui: stackoverflow.com/questions/57943259/…
user1506104

Respostas:

430

Maneira mais fácil do que as respostas anteriores:

Coloque isso em ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Modifique o seu app/build.gradlee adicione-o dentro do android {bloco de código:

...    
signingConfigs {

   release {
       storeFile file(RELEASE_STORE_FILE)
       storePassword RELEASE_STORE_PASSWORD
       keyAlias RELEASE_KEY_ALIAS
       keyPassword RELEASE_KEY_PASSWORD

       // Optional, specify signing versions used
       v1SigningEnabled true
       v2SigningEnabled true
   }
}

buildTypes {
        release {
            signingConfig signingConfigs.release
        }
}
....

Então você pode correr gradle assembleRelease


Veja também a referência para o signingConfigsGradle DSL

David Vávra
fonte
12
Melhor método se você me perguntar. Não salva nada na minha pasta do projeto / SVN e posso fazer o check-out de 10 versões dos meus projetos sem precisar me preocupar com as chaves.
Frank
8
Se você estiver usando gradlew no Windows, precisará garantir que GRADLE_USER_HOME esteja definido como uma variável de ambiente para fazer isso funcionar. Eu o defini como um diretório acima do diretório do meu projeto e coloquei meu keystore lá. O caminho para o keystore em gradle.properties deve usar barras (/) ou barras invertidas duplas (\\), não barras invertidas únicas do Windows. Para criar um keystore no prompt de comando do Windows, consulte stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
Anachronist
3
O caminho é relativo ao local onde o arquivo build.gradle está localizado ou é relativo ao diretório raiz das máquinas?
Prem
1
@Prem, file()sempre assume caminhos relativos. Use new File(path)se você quiser que seja tratado como absoluto.
Ars-longa-vita-brevis
4
Isso funcionou para mim e para os mais simples. No gradle.properties, especifique storeFile em relação ao seu módulo build.gradle como RELEASE_STORE_FILE = .. / mykeystore. Dont adicionar aspas else mangles Gradle o caminho
Lakshman Chilukuri
263

Consegui resolvê-lo adicionando este código e construindo com gradle build:

android {
    ...
    signingConfigs {
        release {
            storeFile file("release.keystore")
            storePassword "******"
            keyAlias "******"
            keyPassword "******"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

Isso gera um arquivo apk de versão assinada.

Jan-Terje Sørensen
fonte
33
Existe uma maneira de fazê-lo solicitar as senhas? Ou outras sugestões para manter as senhas fora dos meus repositórios git?
user672009
3
Eu edito meu build.gradle para se parecer com o seu, mas executar "Construído> Gerar APK assinado ..." ainda exibe a minha caixa de diálogo ("Consulte o Guia do usuário do Gradle para obter mais informações." Etc.) e nenhum APK.
Semanticer
3
@Semanticer Execute gradle buildor gradlew buildin Terminal / Prompt command
Phillip Kamikaze
12
@ user672009, você pode colocar senhas em um arquivo de propriedades e excluí-lo dos repositórios com .gitignore. Você pode ver este link. gist.github.com/gabrielemariotti/6856974
Gabriele Mariotti
1
@GabrieleMariotti Isso ainda deixa um repositório incompleto. Uma maneira melhor seria criar um esqueleto signature.properties e depois de emitir "git update-index --assume-inalterado signature.properties". No entanto, isso impede que futuras edições sejam confirmadas. Algo como a primeira opção sugerida pelo sdqali parece ainda melhor.
user672009
67

Observe que o script do @ sdqali solicitará (pelo menos ao usar o Gradle 1.6) a senha sempre que você invocar qualquer tarefa do gradle. Como você só precisa disso gradle assembleRelease(ou semelhante), pode usar o seguinte truque:

android {
    ...
    signingConfigs {
        release {
            // We can leave these in environment variables
            storeFile file(System.getenv("KEYSTORE"))
            keyAlias System.getenv("KEY_ALIAS")

            // These two lines make gradle believe that the signingConfigs
            // section is complete. Without them, tasks like installRelease
            // will not be available!
            storePassword "notYourRealPassword"
            keyPassword "notYourRealPassword"
        }
    }
    ...
}

task askForPasswords << {
    // Must create String because System.readPassword() returns char[]
    // (and assigning that below fails silently)
    def storePw = new String(System.console().readPassword("Keystore password: "))
    def keyPw  = new String(System.console().readPassword("Key password: "))

    android.signingConfigs.release.storePassword = storePw
    android.signingConfigs.release.keyPassword = keyPw
}

tasks.whenTaskAdded { theTask -> 
    if (theTask.name.equals("packageRelease")) {
        theTask.dependsOn "askForPasswords"
    }
}

Observe que eu também precisei adicionar o seguinte (no Android) para fazê-lo funcionar:

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}
jclehner
fonte
Depois de implementar isso, installReleasedesapareceu da lista de tarefas ... Por quê?
21413 Kaarel
1
@caspase Gostaria de ter levado o seu comentário sobre essa "storePassword" e "keyPassword" mais a sério. Sem inicializar essas propriedades ("" por exemplo), o * -release.apk assinado não é criado, nenhum erro é exibido e você fica completamente confuso com apenas o * -release-unsigned.apk no diretório PROJECT_NAME / build / apk / . Man ...: /
vizZ
Obrigado pela observação sobre a adição de signatureConfig em buildTypes -> Release. Isso resolveu a assinatura automática para mim!
precisa
1
Eu criei um plugin gradle simples que solicita senhas ao criar o apk de lançamento (usando o mathod descrito neste post, mas você não precisará definir storePassword e keyPassword falsos). Também está disponível no maven central. github.com/alexvasilkov/AndroidGradleSignPlugin
Alex Vasilkov
Isso é ótimo. Lembre-se de que a variável de ambiente KEYSTOREprecisa ser definida mesmo para compilações de depuração e para "gradle sync" no Android Studio; caso contrário, ocorrerá um erro sobre o caminho ser nulo.
Jerry101
63

Se você quiser evitar codificar seu keystore e senha em build.gradle , poderá usar um arquivo de propriedades conforme explicado aqui: MANUSEANDO A ASSINATURA DE CONFIGURAÇÕES COM GRADLE

Basicamente:

1) crie um arquivo myproject.properties em / home /[ usernameername//assinando com esse conteúdo:

keystore=[path to]\release.keystore
keystore.password=*********
keyAlias=***********
keyPassword=********

2) crie um arquivo gradle.properties (talvez na raiz do diretório do seu projeto) com o conteúdo:

MyProject.properties=/home/[username]/.signing/myproject.properties

3) consulte-o em seu build.gradle assim:

    if(project.hasProperty("MyProject.properties")
        && new File(project.property("MyProject.properties")).exists()) {

    Properties props = new Properties()
    props.load(new FileInputStream(file(project.property("MyProject.properties"))))

    signingConfigs {
        release {
            storeFile file(props['keystore'])
            storePassword props['keystore.password']
            keyAlias props['keyAlias']
            keyPassword props['keyPassword']
        }
    }
}
IgorGanapolsky
fonte
1
Funciona bem! Obrigado. Este código deve ser adicionado antes da seção buildTypes {} e a seção deve declarar o releaseControlConfiguraçãoConfigs.release como normal.
theczechsensation
Finalmente encontrei uma solução para esse problema. A única coisa que realmente me ajudou! Este sould ser a resposta aceita ...
devnull69
39

Assinatura automática de aplicativo com Gradle ao usar git

É incrível quantas maneiras complicadas existem para fazer isso. Aqui está o meu próprio caminho, em que tento seguir a própria recomendação do Google . No entanto, a explicação deles não é totalmente clara, portanto descreverei o procedimento para o Linux em detalhes.


Descrição:

As instruções padrão do Google para assinar automaticamente um aplicativo durante a compilação, sem manter as senhas e os arquivos de assinatura no caminho de desenvolvimento de aplicativos (GIT), são bastante obscuras. Aqui estão as instruções passo a passo esclarecidas sobre como fazer isso.

Premissas iniciais:

Você tem um aplicativo chamado "MyApp" em um diretório dado pelo seguinte caminho: $HOME/projects/mydev/MyApp. No entanto, o diretório MyApp é usado e controlado com o GIT.

insira a descrição da imagem aqui

Problema

Obviamente, não queremos ter nossos arquivos de assinatura ou senha em nenhum lugar do diretório controlado pelo GIT, mesmo que sejamos capazes de usar .gitignoreetc, ainda é muito arriscado e fácil cometer um erro. Portanto, queremos nossos arquivos de keystore e assinatura fora.

Solução

Precisamos fazer três (3) coisas:

  1. Crie um arquivo de senha para ser usado pelo Android Studio
  2. Criar arquivo de chave de assinatura
  3. Edite o build.gradlearquivo do módulo para usar (1) e (2).

Neste exemplo, nomeamos os dois arquivos:

  1. keystore.properties
  2. MyApp-release-key.jks

Podemos colocar esses dois arquivos aqui:

cd $HOME/projects/mydev/

(1) Crie o arquivo de senha do keystore

O primeiro arquivo contém as senhas de texto não criptografado usadas no; e caminhos para o arquivo da chave de liberação em (2). Comece preenchendo isso, pois facilitará a operação de copiar e colar para a próxima etapa.

cd $HOME/projects/mydev/

Edite keystore.propertiespara que seu conteúdo seja:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation

A única parte complicada aqui, é o myStoreFileLocation. Este é o caminho, conforme visto no build.gradlearquivo do módulo durante a construção. Isto significa geralmente um caminho semelhante e em relação a: $HOME/projects/mydev/MyApp/app/build.gradle. Portanto, para apontar para o MyApp-release-key.jks arquivo, o que precisamos colocar aqui é:

../../../MyApp-release-key.jks

Aqui, também escolhemos o alias "myapp" para a chave. Em seguida, o arquivo final deve parecer:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myapp
storeFile=../../../MyApp-release-key.jks

(2) Crie o arquivo de assinatura

O segundo arquivo é gerado automaticamente quando você cria a chave de assinatura. Se você não tiver outros aplicativos e este for seu único keystore, crie o arquivo com:

cd $HOME/projects/mydev/
keytool -genkeypair -v -keystore MyApp-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myapp

Isso solicitará duas senhas e várias informações. (O mesmo material do Android Studio.) Agora copie / cole as senhas escolhidas anteriormente.

(3) Edite seu gradle.buildarquivo de módulo para usar o acima

As seguintes partes precisam estar presentes no arquivo de construção Gradle do seu aplicativo / módulo. Primeiro, adicione as seguintes linhas fora e antes do seu android {}bloqueio.

//def keystorePropertiesFile = rootProject.file("$HOME/.android/keystore.properties")
def keystorePropertiesFile = rootProject.file("../../keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

Em seguida, dentro do android {}bloco, adicione:

android {
    ...
    defaultConfig { ... }
    signingConfigs {
            release {
                keyAlias keystoreProperties['keyAlias']
                keyPassword keystoreProperties['keyPassword']
                storeFile file(keystoreProperties['storeFile'])
                storePassword keystoreProperties['storePassword']
            }
        }
    // Tell Gradle to sign your APK
    buildTypes {
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

Agora, a partir do shell, você pode recriar seu aplicativo com:

cd $HOME/projects/mydev/MyApp/app/
./gradlew clean build

Isso deve gerar um aplicativo assinado corretamente que possa ser usado no Google Play.


ATUALIZAÇÃO: 2019-04-02

Versões mais recentes keytoole algo está lhe dizendo que você deve usar um arquivo de chaves baseado no PKCS12 em vez do original / padrão, como eu uso acima. Eles continuam dizendo que você deve converter para o novo formato aberto PKCS12. No entanto, parece que as ferramentas de desenvolvimento do Android ainda não estão prontas para isso, porque se você o fizer, receberá os seguintes erros estranhos:

com.android.ide.common.signing.KeytoolException:Falha ao ler a chave XXX da loja "F: \ XXX \ XXX.jks": Falha na obtenção da chave: dado que o bloco final não foi preenchido corretamente. Tais problemas podem surgir se uma chave incorreta for usada durante a descriptografia.

Portanto, não use uma chave convertida!

not2qubit
fonte
O signatureConfigs é salvo dentro do apk e, em seguida, pode ser descompilado por qualquer usuário para obter senhas ou ele não aparece no apk?
JavierSegoviaCordoba
2
Funciona como charme. Obrigado, esta deve ser a resposta aceita
pratham kesarkar 5/17/17
E se você quiser apenas o keystore e as senhas em um servidor de construção? Com a solução acima, todo desenvolvedor da equipe precisa ter o armazenamento de chaves em sua máquina local. Caso contrário, a sincronização do projeto Gradle falhará: keystore.properties (Esse arquivo ou diretório não existe).
Diana Farin
1
Você pode confirmar um keystore.propertiesarquivo fictício no controle de origem, para criar trabalhos em máquinas de desenvolvimento. Eu descrevi uma configuração do servidor de compilação aqui .
dskrvk
1
Uma observação em sua última atualização sobre a keytoolgeração de um keystore PKCS12: você pode transmitir -storetype JKSo keytoolcomando para definir o tipo de keystore como JKS, o que é necessário pelas ferramentas do Android.
Trevor Halvorson
35

Como o @Destil disse, mas permita que outras pessoas que não têm a chave para criar: Maneira mais fácil do que as respostas anteriores:

Coloque isso em ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Modifique o seu build.gradlecomo este:

...    
if(project.hasProperty("RELEASE_STORE_FILE")) {
    signingConfigs {    
       release {
           storeFile file(RELEASE_STORE_FILE)
           storePassword RELEASE_STORE_PASSWORD
           keyAlias RELEASE_KEY_ALIAS
           keyPassword RELEASE_KEY_PASSWORD
       }
    }
}

buildTypes {
    if(project.hasProperty("RELEASE_STORE_FILE")) {
        release {
            signingConfig signingConfigs.release
        }
    }
}
....

Então você pode executar gradle assembleRelease OU gradle build

Gal Bracha
fonte
Como definir o caminho no Windows: caminho para o seu keystore
reza_khalafi
O arquivo storeFile ("C: \\ Usuários \\ xxxx \\ Documents \\ yyyy \\ mykey.jks") está certo?
reza_khalafi 11/04
28

(Em resposta ao usuário672009 acima.)

Uma solução ainda mais fácil, se você quiser manter suas senhas fora de um repositório git; No entanto, desejar incluir o build.gradle nele, que funciona muito bem com os sabores do produto, é criar um arquivo gradle separado. Vamos chamá-lo de 'signature.gradle' (inclua-o no seu .gitignore). Como se fosse o seu arquivo build.gradle menos tudo relacionado à sua entrada.

android {
    signingConfigs { 
        flavor1 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
        flavor2 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
    }
}

Em seguida, no seu arquivo build.gradle, inclua esta linha logo abaixo de "apply plugin: 'android'"

 apply from: 'signing.gradle'

Se você não tiver ou usar vários sabores, renomeie "flavor1" para "release" acima e você deverá concluir. Se você estiver usando sabores, continue.

Por fim, vincule seus sabores a sua assinatura corretaConfig no arquivo build.gradle e você deverá concluir.

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...
jonbo
fonte
Você pode ser um pouco mais específico. Não consigo executar: "não é possível resolver o símbolo signatureConfig".
Amio.io 6/09/14
Se eu incluir 'signature.gradle' no build.gradle - sou forçado a ter um no repositório git (caso contrário, recebo o erro 'signature.gradle não existe'). E se eu colocar o 'signature.gradle' no git, isso derrota o propósito. Como posso tornar opcional a inclusão de signature.gradle?
Jaguar
21

Se você já possui o arquivo keystore, pode ser tão simples quanto adicionar alguns parâmetros ao seu comando build:

./gradlew assembleRelease \
 -Pandroid.injected.signing.store.file=$KEYFILE \
 -Pandroid.injected.signing.store.password=$STORE_PASSWORD \
 -Pandroid.injected.signing.key.alias=$KEY_ALIAS \
 -Pandroid.injected.signing.key.password=$KEY_PASSWORD

Não são necessárias alterações permanentes no seu projeto Android.

Fonte: http://www.tinmith.net/wayne/blog/2014/08/gradle-sign-command-line.htm

janpio
fonte
18

Esta é uma resposta ao user672009 e uma adição à postagem do sdqali (seu código falhará na criação da versão de depuração pelo botão "Executar" do IDE):

Você pode usar o seguinte código:

final Console console = System.console();
if (console != null) {

    // Building from console 
    signingConfigs {
        release {
            storeFile file(console.readLine("Enter keystore path: "))
            storePassword console.readLine("Enter keystore password: ")
            keyAlias console.readLine("Enter alias key: ")
            keyPassword console.readLine("Enter key password: ")
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}
AChep
fonte
Existe uma maneira de ter alguns valores padrão? Meu keystore geralmente é o mesmo. O storePassword geralmente é o mesmo que keyPassword e o keyAlias ​​geralmente o nome do projeto em letras minúsculas.
user672009
@ user672009 você sempre pode usar o código Java dentro do script.
AChep
1
você pode querer usar algo como isto: keyPassword new String(console.readPassword("Enter key password: "))se certificar que sua senha não é exibida durante a entrada
Alex Semeniuk
Isso não funciona mais, consulte github.com/gradle/gradle/issues/1251
SqAR.org
16

No Android Studio mais recente, existe uma maneira de GUI muito fácil e que também preenche os arquivos Gradle.

  1. File -> Project Structure

  2. Module -> Escolha o módulo principal ('app' ou outro nome personalizado)

  3. Signing guia -> imagem Plus para adicionar nova configuração

  4. Preencher dados no lado direito

  5. O arquivo OK e Gradle é criado automaticamente

  6. Você precisará adicionar manualmente uma linha signingConfig signingConfigs.NameOfYourConfigdentrobuiltTypes{release{}}

Imagens:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Duas notas importantes (!):

(EDIT 12/15)

  1. Para criar APK assinado, é necessário abrir a guia Terminal do Android Studio (parte inferior da interface principal) e emitir um comando ./gradlew assembleRelease

  2. Se você esqueceu keyAlias(o que acontece frequentemente comigo), terá que iniciar Build -> Generate Signed APKpara iniciar o processo e ver o nome da chave Alias.

sandalone
fonte
2
Isso codifica suas senhas no build.gradlearquivo, não é?
Joshua Pinter
16

Se você criar o apk via linha de comando como eu, poderá fornecer a configuração de assinatura como argumentos.

Adicione isto ao seu build.gradle

def getStore = { ->
    def result = project.hasProperty('storeFile') ? storeFile : "null"
    return result
}

def getStorePassword = { ->
    def result = project.hasProperty('storePassword') ? storePassword : ""
    return result
}

def getKeyAlias = { ->
    def result = project.hasProperty('keyAlias') ? keyAlias : ""
    return result
}

def getKeyPassword = { ->
    def result = project.hasProperty('keyPassword') ? keyPassword : ""
    return result
}

Faça o seu signingConfigsassim

signingConfigs {
    release {
        storeFile file(getStore())
        storePassword getStorePassword()
        keyAlias getKeyAlias()
        keyPassword getKeyPassword()
    }
}

Então você executa gradlewassim

./gradlew assembleRelease -PstoreFile="keystore.jks" -PstorePassword="password" -PkeyAlias="alias" -PkeyPassword="password"
Egis
fonte
Qual é build.gradle? Nível superior? Por favor, adicione mais código
Vlad
Para esclarecer, é sobre esse app/build.gradlearquivo que estou falando.
Egis
11
android {
    compileSdkVersion 17
    buildToolsVersion "19.0.3"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 18
    }

    File signFile = rootProject.file('sign/keystore.properties')
    if (signFile.exists()) {
        Properties properties = new Properties()
        properties.load(new FileInputStream(signFile))
        signingConfigs {
            release {
                storeFile rootProject.file(properties['keystore'])
                storePassword properties['storePassword']
                keyAlias properties['keyAlias']
                keyPassword properties['keyPassword']
            }
        }
    }

    buildTypes {
        release {
            runProguard true
            zipAlign true
            proguardFile rootProject.file('proguard-rules.cfg')
            signingConfig signingConfigs.release
        }
        debug {
            runProguard false
            zipAlign true
        }
    }
}
JP Ventura
fonte
Usando o Android Studio 0.5.1, Gradle 1.11 e o plugin Gradle 0.9.
JP Ventura
1
A criação de propriedades sob demanda (também conhecidas como propriedades dinâmicas) foi descontinuada e está programada para ser removida no Gradle 2.0
JP Ventura
10

Você também pode usar a opção de linha de comando -P da gradle para ajudar na assinatura. Em seu build.gradle, adicione o cantoConfigs como este:

signingConfigs {
   release {
       storeFile file("path/to/your/keystore")
       storePassword RELEASE_STORE_PASSWORD
       keyAlias "your.key.alias"
       keyPassword RELEASE_KEY_PASSWORD
   }
}

Em seguida, chame gradle build assim:

gradle -PRELEASE_KEYSTORE_PASSWORD=******* -PRELEASE_KEY_PASSWORD=****** build

Você pode usar -P para definir storeFile e keyAlias, se preferir.

Esta é basicamente a solução da Destil, mas com as opções de linha de comando.

Para obter mais detalhes sobre as propriedades da gradle, consulte o guia do usuário da gradle .

Andy Shiue
fonte
7

A resposta do @ Destil é boa se você puder reutilizar a mesma configuração em todos os projetos. Como alternativa, o Android Studio vem com um local.propertiesarquivo que talvez possa ser usado, mas é supostamente gerado por IDE e não consigo encontrar uma maneira de estendê-lo no Android Studio.

Esta é uma variação da resposta de @ jonbo . Essa resposta permite configurações específicas do projeto, mas vem com um pouco de sobrecarga do desenvolvedor. Especificamente, um clichê significativo é necessário para mover a signingConfigsdefinição para um arquivo separado - especialmente se você precisar fazer isso para vários projetos, o que é um dos principais motivos para escolher essa solução em detrimento da Destil. Isso pode ser um pouco aliviado, incluindo também a linha

apply plugin: 'com.android.application'

no arquivo de credenciais, pois isso permitirá a conclusão do IDE.

Finalmente, a maioria das soluções aqui não permite a construção do projeto no modo de depuração - que lida com a assinatura de depuração automaticamente - sem fornecer uma signingConfigsdefinição válida sintaticamente, se não semanticamente válida . Se você não precisar produzir uma versão compilada a partir de uma determinada máquina, essa etapa extra poderá ser vista como um obstáculo desnecessário. Por outro lado, pode ser uma ajuda contra colegas ignorantes ou preguiçosos que executam compilações de depuração na produção.

Essa solução permitirá compilações de depuração sem se preocupar com credenciais, mas exigirá credenciais válidas para produzir compilações de versão e requer muito pouco clichê. No entanto, como desvantagem, isso pode incentivar outras pessoas a substituir valores ilegais por credenciais reais e não há como se proteger contra isso.

// app/build.gradle
// Define this structure in signing.gradle to enable release builds.
ext.signing = [
        storeFilePath : 'path/to/keystore',
        storePassword : 'keystore password',
        keyAlias      : 'key alias',
        keyPassword   : 'key password',
]

if (file('signing.gradle').exists()) {
    apply from: 'signing.gradle'
}

android {
    ...
    signingConfigs {
        release {
            storeFile file(project.signing.storeFilePath)
            storePassword project.signing.storePassword
            keyAlias project.signing.keyAlias
            keyPassword project.signing.keyPassword
        }
    }
    buildTypes {
        debug { ... }
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

Isso cria uma propriedade fictícia que serve apenas para produzir um arquivo de compilação sintaticamente válido. Os valores atribuídos às ext.signingpropriedades de são irrelevantes na medida em que as compilações de depuração vão. Para ativar compilações, cópia ext.signingem signing.gradlee substituir os valores fictícios com credenciais válidas.

// signing.gradle
ext.signing = [
        storeFilePath : 'real/keystore',
        storePassword : 'real keystore password',
        keyAlias : 'real key alias',
        keyPassword : 'real key password',
]

Obviamente, signing.gradledeve ser ignorado pelo VCS.

mkjeldsen
fonte
6

Agora, quase todas as plataformas oferecem algum tipo de chaveiro; portanto, não há motivo para deixar senhas de texto não criptografado.

Proponho uma solução simples que use o módulo Python Keyring (principalmente o script do console complementar keyring) e um wrapper mínimo em torno do ['do', 'something'].execute() recurso Groovy :

def execOutput= { args ->
    def proc = args.execute()
    proc.waitFor()
    def stdout = proc.in.text
    return stdout.trim()
}

Usando esta função, a signingConfigsseção se torna:

signingConfigs {
    release {
        storeFile file("android.keystore")
        storePassword execOutput(["keyring", "get", "google-play", storeFile.name])
        keyAlias "com.example.app"
        keyPassword execOutput(["keyring", "get", "google-play", keyAlias])
    }
}

Antes de executar, gradle assembleReleasevocê deve definir as senhas no seu chaveiro, apenas uma vez:

$ keyring set google-play android.keystore # will be prompted for the passwords
$ keyring set google-play com.example.app

Happy releases!

naufraghi
fonte
5

Estendendo a resposta de David Vavra, crie um arquivo ~ / .gradle / gradle.properties e inclua

RELEASE_STORE_FILE=/path/to/.keystore
RELEASE_KEY_ALIAS=XXXXX
RELEASE_STORE_PASSWORD=XXXXXXXXX
RELEASE_KEY_PASSWORD=XXXXXXXXX

Em seguida, no build.gradle

  signingConfigs {
    release {
    }
  }

  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true

    }
  }

  // make this optional
  if ( project.hasProperty("RELEASE_KEY_ALIAS") ) {
    signingConfigs {
      release {
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
      }
    }
    buildTypes {
      release {
        signingConfig signingConfigs.release
      }
    }
  }
SRC
fonte
5

Eu me diverti bastante tentando entender isso. Aqui está o meu passo a passo.

Instruções passo a passo de A a Z sobre como criar um arquivo de construção da classificação no IntelliJ (v.13.1.4) Esta explicação pressupõe que você sabe como criar um arquivo keystore. Para que este tutorial funcione, você precisará que o arquivo keystore esteja localizado na pasta do aplicativo e que o arquivo zipalign.exe esteja localizado em 'SDK-ROOT \ tools'. Esse arquivo geralmente é encontrado em 'SDK-ROOT \ build-tools' e, nesta pasta, ele estará na pasta api mais alta (alfa ou beta, recomendo a versão alfa).

Para aqueles de vocês que desejam pular direto aqui, está o arquivo de construção do gradle.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}
android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        playstore {
            keyAlias 'developers4u'
            keyPassword 'thisIsNotMyRealPassword'
            storeFile file('developers4u.keystore')
            storePassword 'realyItIsNot'
        }
    }
    buildTypes {
        assembleRelease {
            debuggable false
            jniDebugBuild false
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            zipAlign true
            signingConfig signingConfigs.playstore
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

Você pode criar parte desse arquivo de compilação (acima) na opção de menu: Estrutura de arquivo / projeto A partir daqui, selecione Facetas e clique em 'Android-Gradle (App). A partir daqui, você verá as guias: 'Propriedades', 'Assinatura', 'Sabores', 'Tipos de compilação' e 'Dependências' para este passo a passo. Apenas usaremos 'Assinatura' e 'Tipos de compilação'. Em 'Tipos de compilação' (na seção nome), insira qualquer nome que você deseja identificar sua configuração de tipo de compilação e nos outros 4 campos insira suas informações de armazenamento de chaves (definindo o caminho do armazenamento de chaves como aquele na pasta de aplicativos).

Sob os 'Tipos de compilação', digite o valor 'assembleRelease' no campo de nome, 'Debuggable' deve ser definido como falso, 'Jni Debug Build' deve ser falso, defina 'Run Proguard' como true e 'Zip Align' como true. Isso irá gerar o arquivo de construção, mas não como descrito acima, você precisará adicionar algumas coisas ao arquivo de construção posteriormente. O local do arquivo ProGuard aqui será definido manualmente no arquivo de compilação gradle. (como mostrado acima)

Os contêineres DSL que você precisará adicionar posteriormente são os seguintes:

android {
    ....
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    ....
}

Você também terá que adicionar:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

observe que esse contêiner DSL acima ('dependências') deve estar na parte inferior do arquivo de configuração, mas não dentro do contêiner DSL do Android. Para criar o contêiner de dependências no menu IntelliJ, selecione: Estrutura de Arquivo / Projeto. A partir daí, selecione Facetas novamente e, em seguida, Android-Gradle (aplicativo). Você verá as mesmas 5 guias mencionadas acima. Selecione a guia 'Dependências' e adicione as dependências necessárias.

Depois de tudo isso, você verá um arquivo de compilação Gradle semelhante ao arquivo na parte superior deste guia. Para criar sua versão com alinhamento zip assinado, você precisará abrir as tarefas Gradle. Você pode acessar essa janela selecionando Exibir / Janelas de ferramentas / Gradle. A partir daqui, você pode clicar duas vezes em 'assembleAssembleRelease. Isso deve gerar seu APK implantável.

Os possíveis problemas que podem ocorrer ao compilar sua versão são (mas não limitados a): O arquivo de construção do Gradle está no lugar errado. Existem dois arquivos de construção Gradle; um na pasta raiz do aplicativo e outro na pasta do aplicativo, na raiz do aplicativo. Você deve usar o último.

Você também pode ter problemas com fiapos. (Nota: o Android Developer Studio é muito melhor para detectar problemas de cotão do que o IntelliJ; você perceberá isso ao tentar gerar um APK assinado nas opções do menu)

Para contornar problemas com fiapos, você precisará colocar o seguinte contêiner DSL dentro do contêiner Android (na parte superior):

android {
        ....
    lintOptions {
        abortOnError false
    }
    ....
}

colocar isso dentro do contêiner DSL do Android fará com que um arquivo de erro seja gerado na pasta de construção (diretamente abaixo da pasta do aplicativo), o nome do arquivo deve ser algo como 'lint-results-release-fatal.html'. a classe em que o erro ocorreu. Outro arquivo que será gerado é um arquivo XML que contém o 'ID do problema' associado ao erro de cotão. O nome do arquivo deve ser algo como 'lint-results-release-fatal.xml'. Em algum lugar próximo à parte superior do arquivo, você verá um nó 'issue' dentro do qual verá algo semelhante a 'id = "IDOfYourLintProblem"'

Para corrigir esse problema, abra o arquivo em seu projeto listado no arquivo 'lint-results-assembleRelease-fatal.html' e digite a seguinte linha de código no arquivo Java Class logo acima do nome da classe: @SuppressLint ("IDOfYourLintProblem "). Pode ser necessário importar 'android.annotation.SuppressLint;'

Portanto, seu arquivo de classe java deve aparecer como:

package com.WarwickWestonWright.developers4u.app.CandidateArea;

import android.annotation.SuppressLint;
... other imports

@SuppressLint("IDOfYourLintProblem")
public class SearchForJobsFragment extends Fragment {... rest of your class definition}

Observe que suprimir erros de cotão nem sempre é a melhor IDEA; é melhor alterar seu código que causou os erros de cotão.

Outro problema que pode ocorrer é se você não tiver definido a variável de ambiente para a variável de ambiente Gradle HOME. Essa variável é denominada 'GRADLE_HOME' e deve ser definida como o caminho do diretório inicial da gradle, algo como 'C: \ gradle-1.12' Às vezes, você também pode querer definir a variável de ambiente para 'ANDROID_HOME' e definir como 'SUA- Raiz do SDK \ sdk '

Depois disso, retorne à janela de tarefas Gradle e clique duas vezes no assembleAssembleRelease.

Se tudo der certo, você poderá acessar a pasta app \ build \ apk e encontrar o arquivo APK implementável.

user2288580
fonte
+1 para o esforço e: 'lintOptions {abortOnError false}'
Raz Tourgman
4

Mais uma abordagem para o mesmo problema. Como não é recomendável armazenar qualquer tipo de credencial no código-fonte, decidimos definir as senhas para o armazenamento de chaves e o alias de chave em um arquivo de propriedades separado da seguinte maneira:

key.store.password=[STORE PASSWORD]
key.alias.password=[KEY PASSWORD]

Se você usar git, poderá criar um arquivo de texto chamado, por exemplo, secure.properties. Você deve excluí-lo do seu repositório (se estiver usando git, adicione-o ao arquivo .gitignore). Em seguida, você precisaria criar uma configuração de assinatura, como indicam algumas das outras respostas. A única diferença está em como você carregaria as credenciais:

android {
    ...
    signingConfigs {
        ...
        release {
            storeFile file('[PATH TO]/your_keystore_file.jks')
            keyAlias "your_key_alias"

            File propsFile = file("[PATH TO]/secure.properties");
            if (propsFile.exists()) {
                Properties props = new Properties();
                props.load(new FileInputStream(propsFile))
                storePassword props.getProperty('key.store.password')
                keyPassword props.getProperty('key.alias.password')
            }
        }
        ...
    }

    buildTypes {
        ...
        release {
            signingConfig signingConfigs.release
            runProguard true
            proguardFile file('proguard-rules.txt')
        }
        ...
    }
}

Nunca se esqueça de atribuir o signatureConfig ao tipo de compilação do release manualmente (por algum motivo, às vezes, assumo que ele será usado automaticamente). Além disso, não é obrigatório ativar o proguard, mas é recomendável.

Gostamos dessa abordagem melhor do que usar variáveis ​​de ambiente ou solicitar entrada do usuário, porque isso pode ser feito a partir do IDE, alternando para o tipo de construção realease e executando o aplicativo, em vez de precisar usar a linha de comando.

argenkiwi
fonte
1
Gradle não compila usando isso: props = new Properties (); Não é possível definir o valor da propriedade somente leitura 'props'
cesards
Você está certo @ m3n0R. Editei uma linha da minha resposta para refletir a correção que tivemos que introduzir em nosso aplicativo para que ele ainda fosse compilado usando as versões mais recentes do Gradle. Basicamente, props deve ser declarado como uma variável local.
Argenkiwi 22/10
como isso seria adotável usando as ferramentas de CI / CD da nuvem .... o / path / to / keystore e /path/to/secure.props está me impressionando .... obrigado por isso.
sirvon
4

Android Studio Vá para Arquivo -> Estrutura do projeto ou pressione Ctrl + Alt + Shift + S

Veja a imagem

insira a descrição da imagem aqui

Clique OK

Em seguida, o signatureConfigs será gerado no seu arquivo build.gradle.

insira a descrição da imagem aqui

Ahamadullah Saikat
fonte
E é exatamente isso que você não quer fazer. Dessa forma, todas as suas senhas estão em texto não criptografado e fazem parte do seu projeto , e são muito fáceis de incluir acidentalmente, mesmo em sua versão distribuída.
not2qubit
2

Eu tive vários problemas que coloquei a seguinte linha em um lugar errado:

signingConfigs {
    release {
        // We can leave these in environment variables
        storeFile file("d:\\Fejlesztés\\******.keystore")
        keyAlias "mykey"

        // These two lines make gradle believe that the signingConfigs
        // section is complete. Without them, tasks like installRelease
        // will not be available!
        storePassword "*****"
        keyPassword "******"
    }
}

Certifique-se de colocar as peças de assinaturaConfigs na seção android:

android
{
    ....
    signingConfigs {
        release {
          ...
        }
    }
}

ao invés de

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

É fácil cometer esse erro.

Botond Kopacz
fonte
2

É 2019 e preciso assinar o APK com V1 (assinatura jar) ou V2 (assinatura APK completa). Eu pesquisei no Google "gerar um apk assinado" e isso me trouxe aqui. Então, eu estou adicionando minha solução original aqui.

signingConfigs {
    release {
        ...
        v1SigningEnabled true
        v2SigningEnabled true
    }
}

Minha pergunta original: Como usar V1 (assinatura Jar) ou V2 (assinatura APK completa) do arquivo build.gradle

user1506104
fonte
Não é necessário ponto e vírgula; isso lhe dará um erro.
Takeshi Kaga
Isso está certo. Obrigado. Eu editei a resposta.
user1506104
1

Para complementar as outras respostas, você também pode colocar seu arquivo gradle.properties em sua própria pasta de módulo, junto com build.gradle, caso seu keystore seja específico para um projeto.

cprcrack
fonte
1

Estou trabalhando no Ubuntu14.04. vim ~ / .bashrc e inclua export ANDROID_KEYSTORE = export ANDROID_KEYALIAS =

e depois no conjunto build.gradle.

    final Console console = System.console();
if (console != null) {

    // Building from console
    signingConfigs {
        release {
            storeFile file(System.getenv("KEYSTORE"))
            storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
            keyAlias System.getenv("KEY_ALIAS")
            keyPassword new String(System.console().readPassword("\n\$ Enter key password: "))
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}
ayyb1988
fonte
IMHO que parece ser a melhor solução, mas infelizmente parou de funcionar em versões mais recentes do Gradle : System.console()retorna null.
Antonio Vinicius Menezes Medei
1

Uma alternativa é definir uma tarefa que é executada apenas nas versões do release.

android {
  ...
  signingConfigs {
     release {
        // We can leave these in environment variables
        storeFile file('nameOfKeystore.keystore')
        keyAlias 'nameOfKeyAlias'

        // These two lines make gradle believe that the signingConfigs
        // section is complete. Without them, tasks like installRelease
        // will not be available!
        storePassword "notYourRealPassword"
        keyPassword "notYourRealPassword"

     }
  }
  buildTypes {
     ...
     release {
        signingConfig signingConfigs.release
        ...
     }
  }
  ...
}

task setupKeystore << {
final Console console = System.console();
if (console != null) {
    //def keyFile = console.readLine(“\nProject: “ + project.name + “Enter keystore path: "))
    //def keyAlias = console.readLine(“Project: “ + project.name + “Enter key alias: ")
        def storePw = new String(console.readPassword(“Project:  + project.name + “. Enter keystore password: "))
        def keyPw  = new String(console.readPassword(“Project: “ + project.name + “.Enter keystore password: "))

    //android.signingConfigs.release.storeFile = file(keyFile);
    //android.signingConfigs.release.keyAlias = keyAlias
        android.signingConfigs.release.storePassword = storePw
        android.signingConfigs.release.keyPassword = keyPw
}
}

//Validate t
def isReleaseConfig = gradle.startParameter.taskNames.any {it.contains('Release') }
if (isReleaseConfig) {
    setupKeystore.execute();
}
davidpetter
fonte
O seguinte me parece preferível: stackoverflow.com/a/19130098/3664487 Como as duas abordagens se comparam?
user2768
1

Você pode solicitar senhas na linha de comando:

...

signingConfigs {
  if (gradle.startParameter.taskNames.any {it.contains('Release') }) {
    release {
      storeFile file("your.keystore")
      storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
      keyAlias "key-alias"
      keyPassword new String(System.console().readPassword("\n\$ Enter keys password: "))
    } 
  } else {
    //Here be dragons: unreachable else-branch forces Gradle to create
    //install...Release tasks.
    release {
      keyAlias 'dummy'
      keyPassword 'dummy'
      storeFile file('dummy')
      storePassword 'dummy'
    } 
  }
}

...

buildTypes {
  release {

    ...

    signingConfig signingConfigs.release
  }

  ...
}

...

O if-then-elsebloqueio evita solicitações de senhas quando você está criando um release. Embora a elseramificação esteja inacessível, ele faz com que Gradle crie uma install...Releasetarefa.

História de fundo . Conforme observado em https://stackoverflow.com/a/19130098/3664487 , "Os scripts Gradle podem solicitar a entrada do usuário usando o método System.console (). ReadLine ." Infelizmente, o Gradle sempre solicita uma senha, mesmo quando você está criando uma versão de depuração (consulte Como criar um arquivo apk assinado de versão usando o Gradle? ). Felizmente, isso pode ser superado, como mostrei acima.

user2768
fonte
Minha resposta anterior teve problemas devido a stackoverflow.com/questions/33897802/… . Revi minha resposta para eliminar esse problema.
user2768
@Haroon, funcionou a partir de 24 de novembro de 15. Talvez a comunidade possa ajudar com seu problema, mas você precisará fornecer mais detalhes.
User2768
Eu gosto dessa solução, pois evita colocar a senha em texto não criptografado em um arquivo de texto, mas o System.console (). ReadLine não funciona gradle devido a esse problema irritante.
morpheus
@morpheus, eu nunca tive um problema. O acima está funcionando para mim.
precisa saber é o seguinte
Eu acho que você executa o script de dentro de um IDE. se o script for executado no terminal, você verá o erro. mas obrigado por esta resposta. isto é o que eu estava procurando.
morpheus
0

Adicionando minha maneira de fazer isso no React-Native usando o pacote react-native-config .
Crie um arquivo .env:

RELEASE_STORE_PASSWORD=[YOUR_PASSWORD]
RELEASE_KEY_PASSWORD=[YOUR_PASSWORD]

note que isso não deve fazer parte do controle de versão.

no seu build.gradle:

signingConfigs {
        debug {
            ...
        }
        release {
            storeFile file(RELEASE_STORE_FILE)
            storePassword project.env.get('RELEASE_STORE_PASSWORD')
            keyAlias RELEASE_KEY_ALIAS
            keyPassword project.env.get('RELEASE_KEY_PASSWORD')
        }
    }
chenop
fonte
0

No meu caso, eu estava carregando o apk errado, para o lançamento de outro aplicativo.

Dewsworld
fonte
0

Para Groovy (build.gradle)

Você não deve colocar suas credenciais de assinatura diretamente no arquivo build.gradle . Em vez disso, as credenciais devem vir de um arquivo que não está sob controle de versão.

Coloque um arquivo signature.properties em que o build.gradle específico do módulo é encontrado. Não se esqueça de adicioná-lo ao seu arquivo .gitignore !

signature.properties

storeFilePath=/home/willi/example.keystore
storePassword=secret
keyPassword=secret
keyAlias=myReleaseSigningKey

build.gradle

android {
    // ...
    signingConfigs{
        release {
            def props = new Properties()

            def fileInputStream = new FileInputStream(file('../signing.properties'))
            props.load(fileInputStream)
            fileInputStream.close()

            storeFile = file(props['storeFilePath'])
            storePassword = props['storePassword']
            keyAlias = props['keyAlias']
            keyPassword = props['keyPassword']
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
            // ...
        }
    }
}
Willi Mentzel
fonte
0

Para script Kotlin (build.gradle.kts)

Você não deve colocar suas credenciais de assinatura diretamente no arquivo build.gradle.kts . Em vez disso, as credenciais devem vir de um arquivo que não está sob controle de versão.

Coloque um arquivo signature.properties onde o build.gradle.kts específico do módulo é encontrado. Não se esqueça de adicioná-lo ao seu arquivo .gitignore !

signature.properties

storeFilePath=/home/willi/example.keystore
storePassword=secret
keyPassword=secret
keyAlias=myReleaseSigningKey

build.gradle.kts

android {
    // ...
    signingConfigs {
        create("release") {
            val properties = Properties().apply {
                load(File("signing.properties").reader())
            }
            storeFile = File(properties.getProperty("storeFilePath"))
            storePassword = properties.getProperty("storePassword")
            keyPassword = properties.getProperty("keyPassword")
            keyAlias = "release"
        }
    }

    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
            // ...
        }
    }
}
Willi Mentzel
fonte
-1

se você não quiser ver Não é possível chamar o método readLine () no objeto nulo. você precisa escrever primeiro em gradle.properties .

KEYSTORE_PASS=*****
ALIAS_NAME=*****
ALIAS_PASS=*****
JeasonWong
fonte