¿Cómo crear un archivo apk firmado con Gradle?

514

Me gustaría tener mi compilación de Gradle para crear un archivo apk firmado con Gradle.

No estoy seguro de si el código es correcto o si me falta un parámetro al hacerlo gradle build.

Este es parte del código en mi archivo gradle:

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

La construcción de Gradle termina con ÉXITO, y en mi build/apkcarpeta solo veo los archivos ...-release-unsigned.apky ...-debug-unaligned.apk.

¿Alguna sugerencia sobre cómo resolver esto?

Jan-Terje Sørensen
fuente
firmar con la versión v1 (firma jar) o v2 (firma apk completa) del archivo gradle? solución aquí: stackoverflow.com/questions/57943259/…
user1506104

Respuestas:

430

Forma más fácil que las respuestas anteriores:

Pon esto en ~/.gradle/gradle.properties

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

Modifique su app/build.gradley agregue esto dentro del android {bloque 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
        }
}
....

Entonces puedes correr gradle assembleRelease


Consulte también la referencia para signingConfigsGradle DSL

David Vávra
fuente
12
El mejor método si me preguntas. No guarda nada en mi carpeta de proyecto / SVN y puedo verificar 10 versiones de mis proyectos sin tener que preocuparme por las claves.
Frank
8
Si está utilizando gradlew en Windows, debe asegurarse de que GRADLE_USER_HOME esté definido como una variable de entorno para que esto funcione. Lo configuré en un directorio sobre mi directorio de proyecto y puse mi almacén de claves allí. La ruta a su almacén de claves en gradle.properties debe usar barras diagonales (/) o barras diagonales inversas dobles (\\), no barras diagonales inversas simples de Windows. Para crear un almacén de claves desde el símbolo del sistema de Windows, consulte stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
Anachronist
3
¿Es la ruta relativa al lugar donde se encuentra el archivo build.gradle, o relativo al directorio raíz de las máquinas?
Prem
1
@Prem, file()siempre asume caminos relativos. Úselo new File(path)si desea que sea tratado como absoluto.
ars-longa-vita-brevis
44
Esto funcionó para mí y lo más simple. En gradle.properties, especifique storeFile en relación con su módulo build.gradle de la misma manera RELEASE_STORE_FILE = .. / mykeystore. No agregue citas, de lo contrario Gradle destroza el camino
Lakshman Chilukuri
263

Logré resolverlo agregando este código y construyendo con gradle build:

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

Esto genera un archivo apk de lanzamiento firmado.

Jan-Terje Sørensen
fuente
33
¿Hay alguna manera de hacer que me solicite las contraseñas? ¿O otras sugerencias para mantener las contraseñas fuera de mis repositorios git?
user672009
3
Edito mi build.gradle para que se parezca al suyo, pero ejecutar "Construido> Generar APK firmado ..." todavía me da ese cuadro de diálogo ("Consulte la Guía del usuario de Gradle para obtener más información", etc.) y ningún APK.
Semántica
3
@Semanticer Ejecutar gradle buildo gradlew builden el comando Terminal / Solicitud
Phillip Kamikaze
12
@ user672009 puede poner contraseñas en un archivo de propiedades y excluirlo de repositorios con .gitignore. Puedes ver este enlace. gist.github.com/gabrielemariotti/6856974
Gabriele Mariotti
1
@GabrieleMariotti Eso todavía deja un repositorio incompleto. Una mejor manera sería crear un esqueleto signature.properties y después de comprometerse a emitir "git update-index --assume-unchanged Signature.properties". Sin embargo, eso evita que se cometan futuras ediciones. Algo así como la primera opción que sugiere sdqali parece aún mejor.
user672009
67

Tenga en cuenta que el script de @ sdqali (al menos cuando usa Gradle 1.6) le pedirá la contraseña cada vez que invoque cualquier tarea de Gradle. Como solo lo necesita cuando lo hace gradle assembleRelease(o similar), puede usar el siguiente truco:

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"
    }
}

Tenga en cuenta que también tuve que agregar lo siguiente (en Android) para que funcione:

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}
jclehner
fuente
Después de implementar esto, installReleasedesapareció de la lista de tareas ... ¿Por qué?
Kaarel
1
@caspase Ojalá hubiera tomado más en serio tu comentario sobre esa "storePassword" y "keyPassword" falsas. Sin inicializar estas propiedades ("" por ejemplo) el * -release.apk firmado no se crea, no se muestra ningún error y queda completamente desconcertado con solo el * -release-unsigned.apk en su directorio PROJECT_NAME / build / apk / . Hombre ...: /
vizZ
Gracias por la nota acerca de agregar signConfig en buildTypes -> Release. ¡Eso resolvió la firma automatizada para mí!
mm2001
1
Hice un complemento de gradle simple que pide contraseñas al compilar la versión de lanzamiento (usando el método descrito en esta publicación, pero no necesitará definir la contraseña y la contraseña falsas de la tienda). También está disponible en maven central. github.com/alexvasilkov/AndroidGradleSignPlugin
Alex Vasilkov
Esto es genial. Tenga en cuenta que la variable de entorno KEYSTOREdebe definirse incluso para las compilaciones de depuración y para la "sincronización de gradle" dentro de Android Studio, de lo contrario, se producirá un error acerca de que la ruta es nula.
Jerry101
63

Si desea evitar codificar su almacén de claves y contraseña en build.gradle , puede usar un archivo de propiedades como se explica aquí: MANEJO DE LA CONFIGURACIÓN DE LA FIRMA CON GRADLE

Básicamente:

1) cree un archivo myproject.properties en /home/[usernamefont>/.signing with tales contenidos:

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

2) cree un archivo gradle.properties (quizás en la raíz del directorio de su proyecto) con el contenido:

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

3) consúltelo en su build.gradle así:

    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
fuente
1
¡Funciona genial! Gracias. Este código debe agregarse antes de la sección buildTypes {} y la sección debe declarar la firma de la firma de configuración.
theczechsensation
Finalmente encontré una solución para este problema. ¡Lo único que realmente me ayudó! Esta debería ser la respuesta aceptada ...
devnull69
39

Firma automática de aplicaciones con Gradle cuando usa git

Es sorprendente la cantidad de formas complicadas que hay para hacer esto. Aquí está mi propio camino, donde trato de cumplir con la recomendación de Google . Sin embargo, su explicación no está completamente clara, por lo que describiré el procedimiento para Linux en detalle.


Descripción:

Las instrucciones predeterminadas de Google para firmar automáticamente una aplicación durante la compilación, sin mantener las contraseñas y los archivos de firma en la ruta de desarrollo de su aplicación (GIT), son bastante oscuras. Aquí están las instrucciones paso a paso aclaradas sobre cómo hacerlo.

Suposiciones iniciales:

Usted tiene una aplicación llamada "MyApp" en un directorio dado por la siguiente ruta: $HOME/projects/mydev/MyApp. Sin embargo, el directorio MyApp se usa y controla con GIT.

ingrese la descripción de la imagen aquí

Problema

Obviamente no queremos tener nuestros archivos de firma o contraseña en ninguna parte del directorio controlado por GIT, incluso si somos muy capaces de usar .gitignore, etc., todavía es demasiado arriesgado y fácil cometer un error. Por lo tanto, queremos nuestro almacén de claves y archivos de firma fuera.

Solución

Necesitamos hacer tres (3) cosas:

  1. Cree un archivo de contraseña para ser utilizado por Android Studio
  2. Crear archivo de clave de firma
  3. Edite el build.gradlearchivo del módulo para usar (1) y (2).

Para este ejemplo nombramos los dos archivos:

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

Podemos poner ambos archivos aquí:

cd $HOME/projects/mydev/

(1) Crear el archivo de contraseña del almacén de claves

El primer archivo contiene las contraseñas de texto claro utilizadas en; y rutas al archivo de clave de lanzamiento en (2). Comience completando esto, ya que facilitará la operación de copiar y pegar para el siguiente paso.

cd $HOME/projects/mydev/

Editar keystore.propertiespara que su contenido sea:

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

La única parte difícil aquí, es el myStoreFileLocation. Esta es la ruta como se ve desde el build.gradlearchivo del módulo durante la compilación. Esto generalmente significa que un camino similar y con relación a: $HOME/projects/mydev/MyApp/app/build.gradle. Entonces, para señalar el MyApp-release-key.jks archivo, lo que necesitamos poner aquí es:

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

Aquí, también elegimos el alias "myapp" para la clave. Entonces el archivo final debería verse:

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

(2) Crear el archivo de firma

El segundo archivo se genera automáticamente cuando crea la clave de firma. Si no tiene otras aplicaciones y este es su único almacén de claves, cree el archivo con:

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

Esto le pedirá dos contraseñas y un montón de información. (Lo mismo que en Android Studio.) Ahora copie / pegue las contraseñas elegidas previamente.

(3) Edite su módulo gradle.build archivo de para usar lo anterior

Las siguientes partes deben estar presentes en el archivo de compilación Gradle de su aplicación / módulo. Primero, agregue las siguientes líneas afuera y antes de su android {}bloque.

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

Luego, dentro del android {}bloque, agregue:

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
            ...
        }
    }
}

Ahora desde shell, puede reconstruir su aplicación con:

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

Esto debería generar una aplicación debidamente firmada que se pueda usar en Google Play.


ACTUALIZAR: 2019-04-02

Las versiones más recientes de keytooly algo le dice que debe usar un archivo de claves basado en PKCS12 en lugar del original / predeterminado como uso arriba. Ellos pasan luego le dice que debe convertir al nuevo formato PKCS12 abierta. Sin embargo, parece que las herramientas de desarrollo de Android aún no están listas para esto, porque si lo haces, obtendrás los siguientes errores extraños:

com.android.ide.common.signing.KeytoolException:Error al leer la clave XXX de la tienda "F: \ XXX \ XXX.jks": Error al obtener la clave: dado que el bloque final no se rellena correctamente. Tales problemas pueden surgir si se usa una clave incorrecta durante el descifrado.

¡Así que no use una clave convertida!

not2qubit
fuente
¿Se guarda signConfigs dentro del apk y luego cualquier usuario puede descompilarlo para obtener contraseñas o no aparece en el apk?
JavierSegoviaCordoba
2
Funciona como encanto. Gracias, esta debería ser la respuesta aceptada
pratham kesarkar
¿Qué sucede si solo desea el almacén de claves y las contraseñas en un servidor de compilación? Con la solución anterior, cada desarrollador en el equipo necesita tener el almacén de claves en su máquina local. De lo contrario, la sincronización del proyecto Gradle fallará: keystore.properties (No existe tal archivo o directorio).
Diana Farin
1
Puede enviar un keystore.propertiesarchivo ficticio al control de origen, por lo que las compilaciones funcionan en máquinas de desarrollo. Describí una configuración del servidor de compilación aquí .
dskrvk
1
Una nota sobre su última actualización sobre la keytoolgeneración de un almacén de claves PKCS12: puede pasar -storetype JKSel keytoolcomando para establecer el tipo de almacén de claves en JKS, que es necesario para las herramientas de Android.
Trevor Halvorson
35

Como dijo @Destil, pero permite a otros que no tienen la clave para construir: una forma más fácil que las respuestas anteriores:

Pon esto en ~/.gradle/gradle.properties

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

Modifique su build.gradlegusto así:

...    
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
        }
    }
}
....

Entonces puedes ejecutar gradle assembleRelease OR gradle build

Gal Bracha
fuente
Cómo establecer la ruta de ventanas: ruta de acceso al almacén de claves
reza_khalafi
El archivo storeFile ("C: \\ Users \\ xxxx \\ Documents \\ aaaa \\ mykey.jks") ¿es correcto?
reza_khalafi
28

(En respuesta al usuario 672009 anterior).

Una solución aún más fácil, si desea mantener sus contraseñas fuera de un repositorio git; sin embargo, desea incluir su build.gradle, que incluso funciona muy bien con los sabores de los productos, es crear un archivo gradle separado. Llamémoslo 'signature.gradle' (inclúyalo en su .gitignore). Al igual que si fuera su archivo build.gradle menos todo lo que no esté relacionado con el inicio de sesión.

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

Luego, en su archivo build.gradle, incluya esta línea justo debajo de "apply plugin: 'android'"

 apply from: 'signing.gradle'

Si no tiene o usa varios sabores, cambie el nombre de "flavour1" para "liberar" arriba, y debería haber terminado. Si está usando sabores continúe.

Finalmente, vincule sus sabores a su firma de configuración correcta en su archivo build.gradle y debería haber terminado.

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...
jonbo
fuente
Podrías ser un poco más específico. No puedo hacer que se ejecute: "no se puede resolver el símbolo signatureConfig".
Amio.io
Si incluyo 'sign.gradle' en build.gradle, me veo obligado a tener uno en el repositorio git (de lo contrario, aparece el error 'sign.gradle no existe'). Y si pongo el 'sign.gradle' en git, se pierde el propósito. ¿Cómo puedo hacer que la inclusión de sign.gradle sea opcional?
Jaguar
21

Si ya tiene el archivo de almacén de claves, puede ser tan simple como agregar algunos parámetros a su comando de compilación:

./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

No es necesario realizar cambios permanentes en su proyecto de Android.

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

janpio
fuente
18

Esta es una respuesta al usuario672009 y una adición a la publicación de sdqali (su código se bloqueará al crear la versión de depuración mediante el botón "Ejecutar" de IDE):

Puedes usar el siguiente 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
fuente
¿Hay alguna manera de tener algunos valores predeterminados? Mi almacén de claves suele ser el mismo. StorePassword suele ser lo mismo que keyPassword y keyAlias ​​suele ser el nombre del proyecto en minúsculas.
user672009
@ user672009 siempre puede usar código Java dentro del script.
AChep
1
es posible que desee usar algo como esto: keyPassword new String(console.readPassword("Enter key password: "))para asegurarse de que su contraseña no se muestre durante la entrada
Alex Semeniuk
Esto ya no funciona, vea github.com/gradle/gradle/issues/1251
SqAR.org
16

En el nuevo Android Studio, hay una forma de GUI que es muy fácil y también llena el archivo Gradle.

  1. File -> Project Structure

  2. Module -> Elija el módulo principal ('aplicación' u otro nombre personalizado)

  3. Signing pestaña -> Más imagen para agregar una nueva configuración

  4. Rellenar datos en el lado derecho

  5. OK y el archivo Gradle se crea automáticamente

  6. Tendrá que agregar manualmente una línea signingConfig signingConfigs.NameOfYourConfigdentrobuiltTypes{release{}}

Imágenes:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Dos notas importantes (!):

(EDITAR 15/12)

  1. Para crear un APK firmado, deberías abrir la pestaña Terminal de Android Studio (la parte inferior de la interfaz principal) y emitir un comando ./gradlew assembleRelease

  2. Si olvidó keyAlias(lo que me pasa a menudo), tendrá que iniciar Build -> Generate Signed APKpara iniciar el proceso y ver el nombre de la clave Alias.

sandalone
fuente
2
Sin build.gradleembargo, esto codifica sus contraseñas en el archivo, ¿no?
Joshua Pinter
16

Si crea apk a través de la línea de comandos como yo, puede proporcionar la configuración de firma como argumentos.

Agregue esto a su 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
}

Haz tu signingConfigscomo este

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

Entonces ejecutas gradlewasí

./gradlew assembleRelease -PstoreFile="keystore.jks" -PstorePassword="password" -PkeyAlias="alias" -PkeyPassword="password"
Égida
fuente
¿Qué es build.gradle? ¿Nivel superior? Agregue más código
Vlad
Para aclarar, este es el app/build.gradlearchivo del que estoy hablando.
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
fuente
Usando Android Studio 0.5.1, Gradle 1.11 y Gradle plugin 0.9.
JP Ventura
1
La creación de propiedades a pedido (también conocidas como propiedades dinámicas) ha quedado en desuso y está programado para su eliminación en Gradle 2.0
JP Ventura
10

También puede usar la opción de línea de comando -P de gradle para ayudar a la firma. En su build.gradle, agregue cantandoConfigs como este:

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

Luego llame a gradle build de esta manera:

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

Puede usar -P para configurar storeFile y keyAlias ​​si lo prefiere.

Esta es básicamente la solución de Destil pero con las opciones de línea de comando.

Para obtener más detalles sobre las propiedades de gradle, consulte la guía del usuario de gradle .

Andy Shiue
fuente
7

La respuesta de @ Destil es buena si puede reutilizar la misma configuración en todos los proyectos. Alternativamente, Android Studio viene con unlocal.properties archivo que puede ser usado en su lugar, pero supuestamente está generado por IDE y no puedo encontrar una manera de extenderlo desde Android Studio.

Esta es una variación de la respuesta de @ jonbo . Esa respuesta permite configuraciones específicas del proyecto, pero viene con un poco de sobrecarga del desarrollador. Específicamente, se requiere una placa repetitiva importante para mover la signingConfigsdefinición a un archivo separado, especialmente si necesita hacerlo para múltiples proyectos, lo cual es una razón principal para elegir esta solución sobre la de Destil. Esto se puede aliviar un poco al incluir también la línea

apply plugin: 'com.android.application'

en el archivo de credenciales, ya que esto permitirá completar el IDE.

Finalmente, la mayoría de las soluciones aquí no permiten construir el proyecto en modo de depuración, que maneja la firma de depuración automáticamente, sin proporcionar una signingConfigsdefinición sintáctica si no semánticamente válida . Si no necesita producir una versión de lanzamiento de una máquina determinada, este paso adicional puede verse como un obstáculo innecesario. Por otro lado, puede ser una ayuda contra colegas ignorantes o perezosos que ejecutan versiones de depuración en producción.

Esta solución permitirá compilaciones de depuración sin preocuparse por las credenciales, pero requerirá credenciales válidas para producir compilaciones de lanzamiento, y se necesita muy poca información. Sin embargo, como inconveniente , podría alentar a otros a reemplazar los valores ficticios con credenciales reales y no hay forma de protegerse contra eso.

// 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
            ...
        }
    }
}

Esto crea una propiedad ficticia que sirve únicamente para producir un archivo de compilación sintácticamente válido. Los valores asignados a ext.signinglas propiedades de son irrelevantes en lo que respecta a las compilaciones de depuración. Para habilitar las versiones de lanzamiento, copia ext.signingen signing.gradley reemplazar los valores ficticios con credenciales válidas.

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

Por supuesto, signing.gradledebe ser ignorado por VCS.

mkjeldsen
fuente
6

Casi todas las plataformas ahora ofrecen algún tipo de llavero, por lo que no hay razón para dejar contraseñas de texto claro.

Propongo una solución simple que utiliza el módulo Python Keyring (principalmente el script de consola complementario keyring) y un envoltorio mínimo alrededor de la ['do', 'something'].execute() función Groovy :

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

Usando esta función, la signingConfigssección se convierte en:

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 ejecutar gradle assembleRelease, debe configurar las contraseñas en su llavero, solo una vez:

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

¡Felices lanzamientos!

naufraghi
fuente
5

Extendiendo la respuesta de David Vavra, cree un archivo ~ / .gradle / gradle.properties y agregue

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

Luego en 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
fuente
5

Me divertí bastante resolviendo esto. Aquí está mi recorrido.

Recorrido de la A a la Z sobre cómo crear un archivo de compilación gradle en IntelliJ (v.13.1.4) Este recorrido supone que usted sabe cómo crear un archivo de almacén de claves. Para que este tutorial funcione, necesitará que su archivo de almacén de claves esté ubicado en la carpeta de su aplicación y deberá tener su archivo zipalign.exe en 'SDK-ROOT \ tools'. Este archivo generalmente se encuentra en 'SDK-ROOT \ build-tools' y debajo de esta carpeta estará en la carpeta api más alta (alfa o beta, recomiendo la versión alfa).

Para aquellos de ustedes que deseen saltar directamente aquí, está el archivo de compilación de 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'
}

Puede compilar parte de este archivo de compilación (arriba) desde la opción de menú: Estructura de Archivo / Proyecto Desde aquí, seleccione Facetas y haga clic en 'Android-Gradle (Aplicación). Desde aquí, verá pestañas: 'Propiedades', 'Firma', 'Sabores', 'Tipos de compilación' y 'Dependencias' para este tutorial, solo usaremos 'Firma' y 'Tipos de compilación'. En 'Tipos de compilación' (en la sección de nombre) ingrese cualquier nombre que desee para identificar su configuración de tipo de compilación y en los otros 4 campos ingrese la información de su almacén de claves (estableciendo la ruta del almacén de claves en la carpeta de su aplicación).

Debajo de 'Tipos de compilación' ingrese el valor 'assembleRelease' en el campo de nombre, 'Debuggable' debe establecerse en falso, 'Jni Debug Build' debe ser falso, establezca 'Run Proguard' en true y 'Zip Align' en true. Esto generará un archivo de compilación, pero no como se muestra arriba, tendrá que agregar algunas cosas al archivo de compilación después. La ubicación del archivo ProGuard aquí se establecerá manualmente en el archivo de compilación gradle. (como se muestra arriba)

Los contenedores DSL que tendrá que agregar después son los siguientes:

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

También deberás agregar:

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'
}

tenga en cuenta que este contenedor DSL anterior ('dependencias') debe estar en la parte inferior del archivo de configuración, pero no dentro del contenedor DSL de Android. Para construir el contenedor de dependencias desde el menú IntelliJ, seleccione: Estructura de Archivo / Proyecto. Desde allí, seleccione Facetas nuevamente y luego Android-Gradle (aplicación). Verá las mismas 5 pestañas mencionadas anteriormente. Seleccione la pestaña 'Dependencias' y agregue las dependencias que necesite.

Después de todo esto, debería ver un archivo de compilación de Gradle similar al archivo en la parte superior de este tutorial. Para construir su lanzamiento alineado zip firmado deberá abrir las tareas de Gradle. Puede acceder a esta ventana seleccionando Ver / Ventanas de herramientas / Gradle. Desde aquí puede hacer doble clic en 'assembleAssembleRelease. Esto debería generar su APK desplegable.

Los posibles problemas que pueden ocurrir al compilar su versión son (pero no se limitan a): su archivo de compilación Gradle está en el lugar incorrecto. Hay dos archivos de compilación de Gradle; uno en la carpeta raíz de la aplicación y otro en la carpeta de la aplicación debajo de la raíz de la aplicación. Debe usar este último.

También puede tener problemas de pelusa. (Nota: Android Developer Studio es mucho mejor para detectar problemas de Lint que IntelliJ lo notará cuando intente generar un APK firmado desde las opciones del menú)

Para solucionar los problemas de pelusa, deberá colocar el siguiente contenedor DSL dentro del contenedor de Android (en la parte superior):

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

poner esto dentro de su contenedor DSL de Android hará que se genere un archivo de error en la carpeta de compilación (directamente debajo de la carpeta de su aplicación) el nombre del archivo debería ser algo así como 'lint-results-release-fatal.html' este archivo le dirá el La clase donde ocurrió el error. Otro archivo que se generará es un archivo XML que contiene el 'ID de problema' asociado con el error de pelusa. El nombre del archivo debería ser algo así como 'lint-results-release-fatal.xml'. En algún lugar cerca de la parte superior del archivo, verá un 'problema' de nodo dentro del cual verá algo similar a 'id = "IDOfYourLintProblem"'

Para corregir este problema, abra el archivo en su proyecto que figuraba en el archivo 'lint-results-assembleRelease-fatal.html' e ingrese la siguiente línea de código en el archivo de clase Java justo encima del nombre de la clase: @SuppressLint ("IDOfYourLintProblem "). Puede que tenga que importar 'android.annotation.SuppressLint;'

Entonces su archivo de clase de Java debería 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}

Tenga en cuenta que la supresión de los errores de pelusa no siempre es la mejor IDEA. Es mejor que cambie su código que causó los errores de pelusa.

Otro problema que podría ocurrir es si no ha configurado la variable de entorno para la variable de entorno Gradle HOME. Esta variable se llama 'GRADLE_HOME' y debe establecerse en la ruta del directorio de inicio de Gradle, algo así como 'C: \ gradle-1.12'. A veces, también puede establecer la variable de entorno para 'ANDROID_HOME'. SDK-Root \ sdk '

Una vez hecho esto, regrese a la ventana de tareas de Gradle y haga doble clic en assembleAssembleRelease.

Si todo tiene éxito, debería poder ir a la carpeta app \ build \ apk y encontrar su archivo APK desplegable.

usuario2288580
fuente
+1 por el esfuerzo y: 'lintOptions {abortOnError false}'
Raz Tourgman
4

Otro enfoque para el mismo problema. Como no se recomienda almacenar ningún tipo de credencial dentro del código fuente, decidimos establecer las contraseñas para el almacén de claves y el alias de claves en un archivo de propiedades separado de la siguiente manera:

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

Si usa git, puede crear un archivo de texto llamado, por ejemplo, secure.properties. Debe asegurarse de excluirlo de su repositorio (si usa git, agregándolo al archivo .gitignore). Luego, necesitaría crear una configuración de firma, como indican algunas de las otras respuestas. La única diferencia está en cómo cargaría las credenciales:

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 olvide asignar manualmente la configuración de firma al tipo de compilación de lanzamiento (por alguna razón, a veces asumo que se usará automáticamente). Además, no es obligatorio habilitar Proguard, pero es recomendable.

Este enfoque nos gusta más que usar variables de entorno o solicitar la entrada del usuario porque se puede hacer desde el IDE, cambiando al tipo de compilación realease y ejecutando la aplicación, en lugar de tener que usar la línea de comando.

argenkiwi
fuente
1
Gradle no compila usando esto: props = new Properties (); No se puede establecer el valor de propiedad de solo lectura 'props'
cesards
Tienes razón @ m3n0R. Edité una línea de mi respuesta para reflejar la solución que teníamos que introducir en nuestra aplicación para que aún se compilara utilizando las últimas versiones de Gradle. Básicamente, los accesorios deben declararse como una variable local.
argenkiwi
¿cómo sería esto adoptable usando herramientas de CI / CD en la nube? ... el / path / to / keystore y /path/to/secure.props me está arrojando ... gracias por esto.
sirvon el
4

Android Studio Vaya a Archivo -> Estructura del proyecto o presione Ctrl + Alt + Shift + S

Ver la imagen

ingrese la descripción de la imagen aquí

Haga clic en Aceptar

Entonces la firmaConfigs generará en su archivo build.gradle.

ingrese la descripción de la imagen aquí

Ahamadullah Saikat
fuente
Y esto es exactamente lo que no quieres hacer. De esta manera, todas sus contraseñas están en texto claro y son parte de su proyecto , y son muy fáciles de incluir accidentalmente, incluso en su compilación distribuida.
not2qubit
2

Tuve varios problemas que puse la siguiente línea en un lugar incorrecto:

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 "******"
    }
}

Asegúrate de poner las partes de signConfigs dentro de la sección de Android:

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

en vez de

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

Es fácil cometer este error.

Botond Kopacz
fuente
2

Es 2019 y necesito firmar APK con V1 (firma jar) o V2 ​​(firma APK completa). Busqué en Google "generar apk gradle firmado" y me trajo aquí. Entonces estoy agregando mi solución original aquí.

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

Mi pregunta original: Cómo usar V1 (firma Jar) o V2 ​​(firma APK completa) desde el archivo build.gradle

usuario1506104
fuente
No necesita punto y coma; Te dará un error.
Takeshi Kaga
Eso es correcto. Gracias. Edité la respuesta.
user1506104
1

Para complementar las otras respuestas, también puede colocar su archivo gradle.properties en su propia carpeta de módulos, junto con build.gradle, en caso de que su almacén de claves sea específico para un proyecto.

cprcrack
fuente
1

Estoy trabajando en Ubuntu14.04. vim ~ / .bashrc y agregue export ANDROID_KEYSTORE = export ANDROID_KEYALIAS =

y luego en build.gradle set.

    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
fuente
En mi humilde opinión, parece ser la mejor solución, pero desafortunadamente dejó de funcionar en las nuevas versiones de Gradle : System.console()devoluciones null.
Antonio Vinicius Menezes Medei
1

Una alternativa es definir una tarea que se ejecute solo en versiones de lanzamiento.

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
fuente
Me parece preferible lo siguiente: stackoverflow.com/a/19130098/3664487 ¿Cómo se comparan los dos enfoques?
user2768
1

Puede solicitar contraseñas desde la línea 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
  }

  ...
}

...

El if-then-elsebloqueo evita las solicitudes de contraseñas cuando está creando una versión. Aunque la elserama es inalcanzable, engaña a Gradle para que cree una install...Releasetarea.

Historia de fondo . Como señaló https://stackoverflow.com/a/19130098/3664487 , "los scripts de Gradle pueden solicitar la entrada del usuario utilizando el método System.console (). ReadLine ". Desafortunadamente, Gradle siempre solicitará una contraseña, incluso cuando esté creando una versión de depuración (vea ¿Cómo crear un archivo apk firmado con Gradle? ). Afortunadamente, esto se puede superar, como he mostrado anteriormente.

usuario2768
fuente
Mi respuesta anterior tuvo problemas debido a stackoverflow.com/questions/33897802/… . He revisado mi respuesta para eliminar este problema.
user2768
@Haroon, funcionó a partir del 24 de noviembre de 2015. Quizás la comunidad pueda ayudarlo con su problema, pero deberá proporcionar más detalles.
user2768
Me gusta esta solución, ya que evita poner la contraseña en texto claro en un archivo de texto pero System.console (). ReadLine no funciona en gradle debido a este molesto problema.
morfeo
@morpheus, nunca he tenido un problema. Lo anterior está funcionando para mí.
user2768
Creo que ejecuta el script desde un IDE. Si el script se ejecuta desde la terminal, verá el error. pero gracias por esta respuesta Esto es lo que estaba buscando.
morpheus el
0

Agregando mi forma de hacerlo en React-Native usando el paquete react-native-config .
Crea un archivo .env:

RELEASE_STORE_PASSWORD=[YOUR_PASSWORD]
RELEASE_KEY_PASSWORD=[YOUR_PASSWORD]

tenga en cuenta que esto no debería ser parte del control de versiones.

en tu 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
fuente
0

En mi caso, estaba cargando el apk incorrecto, al lanzamiento de otra aplicación.

Dewsworld
fuente
0

Para Groovy (build.gradle)

No debe colocar sus credenciales de firma directamente en el archivo build.gradle . En cambio, las credenciales deben provenir de un archivo que no esté bajo control de versiones.

Coloque un archivo sign.properties donde se encuentre el módulo build.gradle específico del módulo . ¡No olvide agregarlo a su archivo .gitignore !

firma.propiedades

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
fuente
0

Para Kotlin Script (build.gradle.kts)

No debe poner sus credenciales de firma directamente en build.gradle.kts archivo . En cambio, las credenciales deben provenir de un archivo que no esté bajo control de versiones.

Coloque un archivo sign.properties donde se encuentre el módulo build.gradle.kts específico . ¡No olvide agregarlo a su archivo .gitignore !

firma.propiedades

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
fuente
-1

si no desea ver No se puede invocar el método readLine () en un objeto nulo. primero necesita escribir en gradle.properties .

KEYSTORE_PASS=*****
ALIAS_NAME=*****
ALIAS_PASS=*****
JeasonWong
fuente