Come creare un file apk firmato con una versione usando Gradle?


514

Vorrei che il mio Gradle fosse compilato per creare un file apk firmato dal rilascio usando Gradle.

Non sono sicuro che il codice sia corretto o che manchi un parametro quando lo faccio gradle build ?

Questo è un po 'del codice nel mio file gradle:

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

La build gradle termina SUCCESSO, e nella mia build/apkcartella vedo solo ...-release-unsigned.apke...-debug-unaligned.apk file .

Qualche suggerimento su come risolverlo?



firmare con la versione v1 (firma jar) o v2 (firma apk completa) dal file gradle? soluzione qui: stackoverflow.com/questions/57943259/...
user1506104

Risposte:


430

Modo più semplice rispetto alle risposte precedenti:

Metti questo ~/.gradle/gradle.properties

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

Modifica il tuo app/build.gradlee aggiungilo all'interno del android {blocco di codice:

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

Quindi puoi correre gradle assembleRelease


Vedi anche il riferimento per il signingConfigsDSL Gradle


12
Il metodo migliore se me lo chiedi. Non salva nulla nella cartella del mio progetto / SVN e posso controllare 10 versioni dei miei progetti senza doversi preoccupare delle chiavi.
Frank,

8
Se stai usando Gradlew su Windows, devi assicurarti che GRADLE_USER_HOME sia definito come una variabile d'ambiente per farlo funzionare. L'ho impostato su una directory sopra la directory del mio progetto e ho messo lì il mio keystore. Il percorso del keystore in gradle.properties dovrebbe utilizzare barre rovesciate (/) o doppie barre rovesciate (\\), non barre rovesciate singole di Windows. Per creare un keystore dal prompt dei comandi di Windows, consultare stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
Anacronista

3
Il percorso è relativo a dove si trova il file build.gradle o relativo alla directory principale dei computer?
Prem

1
@Prem, file()assume sempre percorsi relativi. Utilizzare new File(path)se si desidera che sia trattato come assoluto.
ars-longa-vita-brevis,

4
Questo ha funzionato per me e il più semplice. In gradle.properties specifica storeFile relativo al tuo modulo build.gradle in questo modo RELEASE_STORE_FILE = .. / mykeystore. Non aggiungere citazioni altrimenti gradle mangles the path
Lakshman Chilukuri

263

Sono riuscito a risolverlo aggiungendo questo codice e costruendo con gradle build:

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

Questo genera un file apk di rilascio firmato.


33
C'è un modo per farmi richiedere le password? O altri suggerimenti per mantenere le password fuori dai miei repository git?
user672009

3
Modifico il mio build.gradle in modo che assomigli al tuo, ma eseguendo "Costruito> Genera APK firmato ..." mi viene ancora visualizzata quella finestra di dialogo ("Vedi la Guida dell'utente di Gradle per maggiori informazioni." Ecc.) E nessun APK.
Semanticer,

3
@Semanticer Execute gradle buildo gradlew buildnel comando Terminal / Prompt
Phillip Kamikaze il

12
@ user672009 è possibile inserire le password in un file delle proprietà ed escluderlo dai repository con .gitignore. Puoi vedere questo link. gist.github.com/gabrielemariotti/6856974
Gabriele Mariotti

1
@GabrieleMariotti Questo lascia ancora un repository incompleto. Un modo migliore sarebbe quello di creare uno scheletro signing.properties e dopo aver eseguito l'emissione di "git update-index --assume-invariato signing.properties". Tuttavia, ciò impedisce che vengano apportate modifiche alle futura. Qualcosa come la prima opzione che sdqali suggerisce sembra ancora migliore.
user672009,

67

Si noti che lo script di @ sdqali (almeno quando si utilizza Gradle 1.6) chiederà la password ogni volta che si richiama qualsiasi compito gradle. Dal momento che ne hai bisogno solo quando lo fai gradle assembleRelease(o simile), puoi usare il seguente trucco:

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

Nota che ho anche dovuto aggiungere il seguente (sotto Android) per farlo funzionare:

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}

Dopo aver implementato questo, è installReleasescomparso dall'elenco delle attività ... Perché?
Kaarel,

1
@caspase Vorrei aver preso sul serio il tuo commento su quel falso "storePassword" e "keyPassword". Senza inizializzare queste proprietà ("" per esempio) il * -release.apk firmato non viene creato, non viene visualizzato alcun errore e si rimane completamente perplessi solo con il * -release-unsigned.apk nella directory PROJECT_NAME / build / apk / . Man ...: /
vizZ

Grazie per la nota sull'aggiunta di signingConfig in buildTypes -> Release. Mi ha risolto la firma automatica!
mm2001

1
Ho creato un semplice plugin gradle che richiede password durante la creazione di apk di rilascio (usando mathod descritto in questo post, ma non sarà necessario definire storePassword e keyPassword falsi). È disponibile anche in centrale. github.com/alexvasilkov/AndroidGradleSignPlugin
Alex Vasilkov

Questo è fantastico Fai attenzione che la variabile di ambiente KEYSTOREdeve essere definita anche per build di debug e per "sincronizzazione graduale" all'interno di Android Studio, altrimenti genererà un errore sul percorso null.
Jerry101,

63

Se si desidera evitare la codifica hardware del keystore e della password in build.gradle , è possibile utilizzare un file delle proprietà come spiegato qui: GESTIONE DELLE CONFIGURAZIONI DI FIRMA CON GRADLE

Fondamentalmente:

1) creare un file myproject.properties a /home/[username]/.signing con tali contenuti:

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

2) crea un file gradle.properties (forse alla radice della directory del tuo progetto) con il contenuto:

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

3) fare riferimento ad esso nel tuo build.gradle in questo modo:

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

1
Funziona alla grande! Grazie. Questo codice deve essere aggiunto prima della sezione buildTypes {} e la sezione deve dichiarare il signingConfig signingConfigs.release come normale.
theczechsensation,

Finalmente ho trovato una soluzione per questo problema. L'unica cosa che mi ha davvero aiutato! Questa potrebbe essere la risposta accettata ...
devnull69,

39

Firma automatica dell'app con Gradle quando si utilizza git

È incredibile quanti modi contorti ci siano per farlo. Ecco la mia strada, in cui provo ad aderire alla raccomandazione di Google . Tuttavia, la loro spiegazione non è completamente chiara, quindi descriverò dettagliatamente la procedura per Linux.


Descrizione:

Le istruzioni predefinite di Google per la firma automatica di un'app durante la compilazione, senza conservare le password e i file delle firme nel percorso di sviluppo dell'app (GIT), sono piuttosto oscure. Ecco le istruzioni dettagliate su come procedere.

Ipotesi iniziali:

Si dispone di un applicazione chiamata "MyApp" in una directory proposta dal seguente percorso: $HOME/projects/mydev/MyApp. Tuttavia, la directory MyApp viene utilizzata e controllata con GIT.

inserisci qui la descrizione dell'immagine

Problema

Ovviamente non vogliamo avere i nostri file di firma o password ovunque nella directory controllata da GIT, anche se siamo in grado di usare .gitignoreecc, è ancora troppo rischioso e facile commettere un errore. Quindi vogliamo che i nostri file keystore e di firma all'esterno.

Soluzione

Dobbiamo fare tre (3) cose:

  1. Crea un file di password che verrà utilizzato da Android Studio
  2. Crea file chiave firma
  3. Modifica il build.gradlefile del modulo per usare (1) e (2).

Per questo esempio chiamiamo i due file:

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

Possiamo inserire entrambi questi file qui:

cd $HOME/projects/mydev/

(1) Creare il file della password del keystore

Il primo file contiene le password in chiaro utilizzate; e percorsi al file della chiave di rilascio in (2). Inizia compilando questo, in quanto faciliterà un'operazione di copia e incolla per il passaggio successivo.

cd $HOME/projects/mydev/

Modifica in keystore.propertiesmodo che il suo contenuto sia:

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

L'unica parte difficile qui, è il myStoreFileLocation. Questo è il percorso visto dalbuild.gradle file del modulo durante la compilazione. Ciò significa solitamente un percorso simile e relativa a: $HOME/projects/mydev/MyApp/app/build.gradle. Quindi, per indicare il MyApp-release-key.jks file, quello che dobbiamo mettere qui è:

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

Qui, abbiamo anche scelto l'alias "myapp" per la chiave. Quindi il file finale dovrebbe apparire:

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

(2) Creare il file della firma

Il secondo file viene generato automaticamente quando si crea la chiave della firma. Se non hai altre app e questo è il tuo unico archivio chiavi, crea il file con:

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

Questo ti chiederà due password e un mucchio di informazioni. (Stesse cose come in Android Studio.) Ora copia / incolla le password scelte in precedenza.

(3) Modifica il gradle.buildfile del modulo per utilizzare quanto sopra

Le seguenti parti devono essere presenti nel file di build Gradle della tua app / modulo. Innanzitutto, aggiungi le seguenti righe all'esterno e prima del android {}blocco.

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

Quindi, all'interno del android {}blocco, aggiungi:

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

Ora dalla shell, puoi ricostruire la tua app con:

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

Ciò dovrebbe generare un'app firmata correttamente che può essere utilizzata in Google Play.


AGGIORNAMENTO: 2019-04-02

Versioni più recenti di keytoole qualcosa ti sta dicendo che dovresti usare un file di chiavi basato su PKCS12 invece dell'originale / predefinito come uso sopra. Hanno poi andare su di te dicendo si dovrebbe convertire il nuovo formato aperto PKCS12. Tuttavia, sembra che gli strumenti di sviluppo Android non siano ancora pronti per questo, perché se lo fai, otterrai i seguenti strani errori:

com.android.ide.common.signing.KeytoolException:Impossibile leggere la chiave XXX dall'archivio "F: \ XXX \ XXX.jks": Ottieni chiave non riuscita: dato blocco finale non correttamente riempito. Tali problemi possono sorgere se durante la decodifica viene utilizzata una chiave errata.

Quindi non usare una chiave convertita!


SigningConfigs viene salvato all'interno dell'apk e quindi può essere decompilato da qualsiasi utente per ottenere password o non viene visualizzato nell'apk?
JavierSegoviaCordoba,

2
Funziona come il fascino. Grazie, questa dovrebbe essere la risposta accettata
pratham kesarkar,

Cosa succede se si desidera solo il keystore e le password su un server di build? Con la soluzione sopra ogni sviluppatore nel team deve avere il keystore sul proprio computer locale. Altrimenti la sincronizzazione del progetto Gradle fallirà: keystore.properties (nessun file o directory di questo tipo).
Diana Farin,

1
È possibile eseguire il commit di un keystore.propertiesfile fittizio nel controllo del codice sorgente, quindi crea lavori su macchine sviluppatore. Ho descritto una configurazione del server di build qui .
dskrvk,

1
Una nota sul tuo ultimo aggiornamento sulla keytoolgenerazione di un keystore PKCS12: puoi passare -storetype JKSil keytoolcomando per impostare il tipo di keystore su JKS, necessario per gli strumenti Android.
Trevor Halvorson,

35

Come ha detto @Destil, ma consenti ad altri che non hanno la chiave per costruire: un modo più semplice delle risposte precedenti:

Metti questo ~/.gradle/gradle.properties

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

Modifica il tuo in build.gradlequesto modo:

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

Quindi puoi eseguire gradle assembleRelease OR gradle build


Come impostare il percorso in Windows: percorso del keystore
reza_khalafi

file storeFile ("C: \\ Users \\ xxxx \\ Documents \\ yyyy \\ mykey.jks") è giusto?
reza_khalafi,

28

(In risposta a user672009 sopra.)

Una soluzione ancora più semplice, se si desidera mantenere le password fuori da un repository git; tuttavia, vuoi includere il tuo build.gradle in esso, che funziona perfettamente anche con i sapori del prodotto, è creare un file gradle separato. Chiamiamolo "signing.gradle" (includilo nel tuo .gitignore). Proprio come se fosse il tuo file build.gradle meno tutto ciò che non riguarda l'accesso.

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

Quindi nel tuo file build.gradle includi questa riga proprio sotto "applica plugin: 'android'"

 apply from: 'signing.gradle'

Se non hai o usi più sapori, rinomina "flavour1" per "rilasciare" sopra e dovresti aver finito. Se si utilizzano i sapori, continuare.

Infine, collega i tuoi sapori alla corretta signingConfig nel tuo file build.gradle e dovresti aver finito.

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...

Potresti essere un po 'più specifico. Non riesco a farlo funzionare: "impossibile risolvere il simbolo signingConfig".
Amio.io,

Se includo 'signing.gradle' in build.gradle - Sono costretto ad averne uno nel repository git (altrimenti visualizzo l'errore 'signing.gradle non esiste'). E se metto il 'signing.gradle' in git, questo vanifica lo scopo. Come posso rendere opzionale l'inclusione di signing.gradle?
Jaguar,

21

Se hai già il file keystore, può essere semplice come aggiungere alcuni parametri al tuo 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

Non sono necessarie modifiche permanenti al tuo progetto Android.

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


18

Questa è una risposta a user672009 e un'aggiunta al post di sdqali (il suo codice andrà in crash durante la creazione della versione di debug tramite il pulsante "Esegui" di IDE):

Puoi usare il seguente codice:

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 {

        }
    }

}

C'è un modo per avere alcuni valori predefiniti? Il mio keystore è generalmente lo stesso. StorePassword solitamente corrisponde a keyPassword e keyAlias ​​in genere il nome del progetto in minuscolo.
user672009

@ user672009 puoi sempre usare il codice Java all'interno dello script.
AChep,

1
potresti voler usare qualcosa del genere: keyPassword new String(console.readPassword("Enter key password: "))per assicurarti che la tua password non sia visualizzata durante l'immissione
Alex Semeniuk,

Questo non funziona più, vedi github.com/gradle/gradle/issues/1251
SqAR.org

16

Nel nuovo Android Studio, esiste un modo GUI che è molto semplice e popola anche i file Gradle.

  1. File -> Project Structure

  2. Module -> Scegli il modulo principale ('app' o altro nome personalizzato)

  3. Signing scheda -> Immagine Plus per aggiungere una nuova configurazione

  4. Inserisci i dati sul lato destro

  5. OK e il file Gradle viene creato automaticamente

  6. Dovrai aggiungere manualmente una riga signingConfig signingConfigs.NameOfYourConfig all'internobuiltTypes{release{}}

Immagini:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Due note importanti (!):

(MODIFICA 15/12)

  1. Per creare un APK firmato, dovresti aprire la scheda Terminale di Android Studio (la parte inferiore dell'interfaccia principale) ed emettere un comando ./gradlew assembleRelease

  2. Se hai dimenticato keyAlias(cosa succede spesso a me), dovrai iniziare Build -> Generate Signed APKper avviare il processo e vedere il nome della chiave Alias.


2
Questo codifica le tue password nel build.gradlefile, vero?
Joshua Pinter,

16

Se crei apk tramite riga di comando come me, puoi fornire la configurazione della firma come argomenti.

Aggiungi questo al tuo 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
}

Rendi il tuo signingConfigscosì

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

Quindi esegui in gradlewquesto modo

./gradlew assembleRelease -PstoreFile="keystore.jks" -PstorePassword="password" -PkeyAlias="alias" -PkeyPassword="password"

Quale è build.gradle? Di livello superiore? Per favore, aggiungi altro codice
Vlad

Per chiarire, questo è il app/build.gradlefile di cui sto parlando.
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
        }
    }
}

Utilizzo di Android Studio 0.5.1, Gradle 1.11 e plug-in Gradle 0.9.
JP Ventura,

1
La creazione di proprietà su richiesta (ovvero proprietà dinamiche) è stata deprecata ed è programmata per essere rimossa in Gradle 2.0
JP Ventura

10

Puoi anche usare l' opzione -P della riga di comando di gradle per aiutare la firma. Nel tuo build.gradle aggiungi cantoConfigs in questo modo:

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

Quindi chiama gradle build in questo modo:

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

Puoi usare -P per impostare storeFile e keyAlias ​​se preferisci.

Questa è sostanzialmente la soluzione di Destil ma con le opzioni della riga di comando.

Per maggiori dettagli sulle proprietà dei gradi, consultare la guida per l'utente dei gradi .


7

La risposta di @Destil è buona se puoi riutilizzare la stessa configurazione in tutti i progetti. In alternativa, Android Studio viene fornito con un local.propertiesfile che può essere eventualmente utilizzato, ma è presumibilmente generato dall'IDE e non riesco a trovare un modo per estenderlo da Android Studio.

Questa è una variante della risposta di @ jonbo . Questa risposta consente impostazioni specifiche del progetto ma ha un po 'di sovraccarico per gli sviluppatori. In particolare, per spostare la signingConfigsdefinizione in un file separato è necessaria un'importante piastra di caldaia, soprattutto se è necessario farlo per più progetti, motivo fondamentale per scegliere questa soluzione rispetto a quella di Destil. Questo può essere in qualche modo alleviato includendo anche la linea

apply plugin: 'com.android.application'

nel file delle credenziali, in quanto ciò consentirà il completamento dell'IDE.

Infine, la maggior parte delle soluzioni qui non consente di costruire il progetto in modalità debug - che gestisce automaticamente la firma del debug - senza fornire una signingConfigsdefinizione sintatticamente se non semanticamente valida . Se non è necessario produrre una build di rilascio da una determinata macchina, questo passaggio aggiuntivo può essere visto come un ostacolo non necessario. D'altra parte, può essere un aiuto contro colleghi ignoranti o pigri che eseguono build di debug in produzione.

Questa soluzione consentirà di creare build di debug senza preoccuparsi delle credenziali, ma richiederà credenziali valide per produrre build di rilascio e richiede pochissimo boilerplate. Tuttavia, come inconveniente potrebbe incoraggiare gli altri a sostituire i valori fittizi con credenziali reali e non c'è modo di proteggerlo.

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

Questo crea una proprietà fittizia che serve esclusivamente per produrre un file di build sintatticamente valido. I valori assegnati aext.signing proprietà di sono irrilevanti per quanto riguarda le build di debug. Per abilitare la build di rilascio, la copia ext.signingin signing.gradlee sostituire i valori fittizi con credenziali valide.

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

Naturalmente, signing.gradledovrebbe essere ignorato da VCS.


6

Quasi tutte le piattaforme ora offrono una sorta di portachiavi, quindi non c'è motivo di lasciare password di testo chiare in giro.

Propongo una soluzione semplice che utilizza il modulo Python Keyring (principalmente lo script della console companion keyring) e un wrapper minimo attorno alla ['do', 'something'].execute() funzione Groovy :

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

Usando questa funzione, la signingConfigssezione diventa:

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])
    }
}

Prima di eseguire gradle assembleReleasedevi impostare le password nel tuo portachiavi, una sola volta:

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

Rilasci felici!


5

Estendendo la risposta di David Vavra, crea un file ~ / .gradle / gradle.properties e aggiungi

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

Quindi in 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
      }
    }
  }

5

Mi sono divertito parecchio a capirlo. Ecco il mio walk-through.

Walk-through dalla A alla Z su come creare un file build gradle in IntelliJ (v.13.1.4) Questo walk-through presuppone che tu sappia come creare un file keystore. Per far funzionare questa esercitazione, è necessario che il file del keystore si trovi nella cartella dell'app e che il file zipalign.exe si trovi in ​​"SDK-ROOT \ tools". Questo file si trova di solito in 'SDK-ROOT \ build-tools' e sotto questa cartella sarà nella cartella api più alta (alpha o beta che consiglio la versione alpha).

Per quelli di voi che desiderano saltare direttamente qui c'è il file di costruzione 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'
}

È possibile creare parte di questo file di build (sopra) dall'opzione di menu: Struttura file / progetto Da qui selezionare Facet e fare clic su Android-Gradle (App). Da qui vedrai le schede: "Proprietà", "Firma", "Sapori", "Tipi di costruzione" e "Dipendenze" per questa procedura, utilizzeremo semplicemente "Firma" e "Tipi di costruzione". In "Tipi di build" (nella sezione del nome) inserisci qualsiasi nome che desideri identificare la configurazione del tuo tipo di build e negli altri 4 campi inserisci le informazioni del tuo keystore (impostando il percorso del keystore quello nella cartella della tua app).

Sotto 'Tipi di build' inserisci il valore 'assembleRelease' nel campo del nome, 'Debuggable' dovrebbe essere impostato su false, 'Jni Debug Build' dovrebbe essere falso, impostare 'Run Proguard' su true e 'Zip Align' su true. Questo genererà il file di build, ma non come illustrato sopra, dovrai aggiungere alcune cose al file di build in seguito. Il percorso del file ProGuard qui verrà impostato manualmente nel file di build gradle. (come illustrato sopra)

I contenitori DSL che dovrai aggiungere in seguito sono i seguenti:

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

Dovrai anche aggiungere:

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

nota che questo contenitore DSL sopra ("dipendenze") dovrebbe trovarsi nella parte inferiore del file di configurazione ma non all'interno del contenitore Android DSL. Per creare il contenitore delle dipendenze dal menu IntelliJ, selezionare: Struttura file / progetto. Da lì seleziona di nuovo Facet e poi Android-Gradle (app). Vedrai le stesse 5 schede di cui sopra. Seleziona la scheda "Dipendenze" e aggiungi le dipendenze richieste.

Dopo aver fatto tutto ciò, dovresti vedere un file di build Gradle simile al file nella parte superiore di questa procedura dettagliata. Per creare la tua versione con allineamento zip firmata dovrai aprire le attività Gradle. Puoi accedere a questa finestra selezionando Visualizza / Strumenti Windows / Grado. Da qui puoi fare doppio clic su 'assembleAssembleRelease. Questo dovrebbe generare il tuo APK distribuibile.

I potenziali problemi che possono verificarsi durante la compilazione della versione sono (ma non limitati a): il file di build Gradle si trova nella posizione errata. Esistono due file di build Gradle; uno nella cartella principale dell'applicazione e un altro nella cartella dell'app sotto la radice dell'applicazione. È necessario utilizzare quest'ultimo.

Potresti anche avere problemi di lanugine. (Nota: Android Developer Studio è molto più bravo a individuare i problemi di Lint rispetto a IntelliJ, lo noterai quando provi a generare un APK firmato dalle opzioni di menu)

Per aggirare i problemi di lanugine dovrai inserire il seguente contenitore DSL nel contenitore Android (in alto):

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

inserendo questo nel tuo contenitore DSL Android, verrà generato un file di errore nella cartella build (direttamente sotto la cartella dell'app) il nome del file dovrebbe essere qualcosa come 'lint-results-release-fatal.html' questo file ti dirà il la classe in cui si è verificato l'errore. Un altro file che verrà generato è un file XML che contiene l '"ID problema" associato all'errore lint. Il nome del file dovrebbe essere simile a "lint-results-release-fatal.xml". Da qualche parte vicino alla parte superiore del file vedrai un nodo 'problema' all'interno del quale vedrai qualcosa di simile a 'id = "IDOfYourLintProblem"'

Per correggere questo problema, apri il file nel tuo progetto elencato nel file 'lint-results-assembleRelease-fatal.html' e inserisci la seguente riga di codice nel file di classe Java appena sopra il nome della classe: @SuppressLint ("IDOfYourLintProblem "). Potrebbe essere necessario importare 'android.annotation.SuppressLint;'

Quindi il tuo file di classe java dovrebbe apparire come:

package com.WarwickWestonWright.developers4u.app.CandidateArea;

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

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

Notare che la soppressione degli errori di lanugine non è sempre la migliore IDEA per cui è meglio cambiare il codice che ha causato gli errori di lanugine.

Un altro problema che potrebbe verificarsi potenzialmente è se non è stata impostata la variabile di ambiente per la variabile di ambiente Gradle HOME. Questa variabile è denominata "GRADLE_HOME" e dovrebbe essere impostata il percorso della directory principale gradle, qualcosa del tipo "C: \ gradle-1.12" A volte potresti anche voler impostare la variabile d'ambiente per "ANDROID_HOME" impostarla su "YOUR- SDK-Root \ SDK'

Al termine, torna alla finestra delle attività di Gradle e fai doppio clic su assembleAssembleRelease.

Se tutto ha esito positivo, dovresti essere in grado di accedere alla cartella app \ build \ apk e trovare il tuo file APK distribuibile.


+1 per lo sforzo e: 'lintOptions {abortOnError false}'
Raz Tourgman,

4

Ancora un altro approccio allo stesso problema. Poiché non è consigliabile memorizzare alcun tipo di credenziale nel codice sorgente, abbiamo deciso di impostare le password per l'archivio chiavi e l'alias chiave in un file di proprietà separato come segue:

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

Se usi git, puoi creare un file di testo chiamato, ad esempio, secure.properties. Dovresti assicurarti di escluderlo dal tuo repository (se usi git, aggiungilo al file .gitignore). Quindi, è necessario creare una configurazione di firma, come indicano alcune delle altre risposte. L'unica differenza è nel modo in cui caricare le credenziali:

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

Non dimenticare mai di assegnare manualmente signingConfig al tipo di build di rilascio (per qualche motivo presumo a volte che verrà utilizzato automaticamente). Inoltre, non è obbligatorio abilitare proguard, ma è consigliabile.

Apprezziamo questo approccio piuttosto che usare le variabili di ambiente o richiedere l'input dell'utente perché può essere fatto dall'IDE, passando al tipo di build realease ed eseguendo l'app, anziché dover utilizzare la riga di comando.


1
Gradle non si compila usando questo: props = new Properties (); Impossibile impostare il valore della proprietà di sola lettura 'props'
cesards

Hai ragione @ m3n0R. Ho modificato una riga della mia risposta per riflettere la correzione che dovevamo introdurre nella nostra app in modo che potesse essere compilata utilizzando le ultime versioni di Gradle. Fondamentalmente, gli oggetti di scena devono essere dichiarati come una variabile locale.
Argenkiwi,

come sarebbe adottabile usando gli strumenti cloud CI / CD .... il / path / to / keystore e /path/to/secure.props mi sta lanciando .... grazie per questo però.
sirvon,

4

Android Studio Vai a File -> Struttura del progetto o premi Ctrl + Alt + Maiusc + S

Vedi l'immagine

inserisci qui la descrizione dell'immagine

Fai clic su OK

Quindi signingConfigs genererà sul tuo file build.gradle.

inserisci qui la descrizione dell'immagine


E questo è esattamente ciò che non vuoi fare. In questo modo tutte le password sono in chiaro e fanno parte del progetto e sono molto facili da includere accidentalmente, anche nella build distribuita.
not2qubit

2

Ho avuto diversi problemi che ho messo la seguente riga in un posto sbagliato:

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

Assicurati di inserire le parti signingConfigs nella sezione Android:

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

invece di

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

È facile fare questo errore.


2

È il 2019 e devo firmare APK con V1 (firma del vaso) o V2 ​​(firma APK completa). Ho cercato su Google "genera un livello apk firmato" e mi ha portato qui. Quindi sto aggiungendo la mia soluzione originale qui.

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

La mia domanda originale: come utilizzare V1 (firma Jar) o V2 ​​(firma APK completa) dal file build.gradle


Non servono punti e virgola; ti darà un errore.
Takeshi Kaga,

È giusto. Grazie. Ho modificato la risposta.
user1506104

1

Per integrare le altre risposte, puoi anche posizionare il tuo file gradle.properties nella tua cartella del modulo, insieme a build.gradle, nel caso in cui il tuo keystore sia specifico di un progetto.


1

sto lavorando in Ubuntu14.04. vim ~ / .bashrc e aggiungi export ANDROID_KEYSTORE = export ANDROID_KEYALIAS =

e quindi nel set 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 {

        }
    }

}

IMHO che sembra essere la soluzione migliore, ma purtroppo ha smesso di funzionare sulle versioni più recenti di Gradle : System.console()rendimenti null.
Antonio Vinicius Menezes Medei,

1

Un'alternativa è definire un'attività che viene eseguita solo su build di rilascio.

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();
}

Mi sembra preferibile quanto segue: stackoverflow.com/a/19130098/3664487 Come si confrontano i due approcci?
user2768

1

Puoi richiedere le password dalla riga di 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
  }

  ...
}

...

Il if-then-elseblocco impedisce le richieste di password durante la creazione di una versione. Sebbene il elseramo sia irraggiungibile, induce Gradle a creare install...Releaseun'attività.

Retroscena . Come notato da https://stackoverflow.com/a/19130098/3664487 , "Gli script Gradle possono richiedere l'input dell'utente utilizzando il metodo System.console (). ReadLine ." Sfortunatamente, Gradle richiederà sempre una password, anche durante la creazione di una versione di debug (vedi Come creare un file apk con rilascio della versione utilizzando Gradle? ). Fortunatamente, questo può essere superato, come ho mostrato sopra.


La mia precedente risposta ha riscontrato problemi dovuti a stackoverflow.com/questions/33897802/… . Ho rivisto la mia risposta per eliminare questo problema.
user2768

@Haroon, ha funzionato dal 24 nov '15. La community può forse aiutarti con il tuo problema, ma dovrai fornire maggiori dettagli.
user2768

Mi piace questa soluzione poiché evita di inserire la password in chiaro in un file di testo ma System.console (). ReadLine non funziona a poco a causa di questo fastidioso problema.
Morpheus,

@morpheus, non ho mai avuto problemi. Quanto sopra funziona per me.
user2768,

Penso che tu esegua lo script dall'interno di un IDE. se lo script viene eseguito dal terminale vedrai l'errore. ma grazie per questa risposta. questo è quello che stavo cercando.
Morpheus,

0

Aggiungendo il mio modo di farlo in React-Native usando il pacchetto React -native-config .
Crea un file .env:

RELEASE_STORE_PASSWORD=[YOUR_PASSWORD]
RELEASE_KEY_PASSWORD=[YOUR_PASSWORD]

nota che questo non dovrebbe far parte del controllo versione.

nel tuo 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')
        }
    }

0

Nel mio caso, stavo caricando l'apk sbagliato nella versione di un'altra app.


0

Per Groovy (build.gradle)

Non inserire le credenziali di firma direttamente nel file build.gradle . Invece le credenziali dovrebbero provenire da un file non sotto il controllo della versione.

Inserisci un file signing.properties dove si trova il build.gradle specifico del modulo . Non dimenticare di aggiungerlo al tuo file .gitignore !

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

0

Per Kotlin Script (build.gradle.kts)

Non inserire le credenziali di firma direttamente in build.gradle.kts file . Invece le credenziali dovrebbero provenire da un file non sotto il controllo della versione.

Inserisci un file signing.properties dove si trova il build.gradle.kts specifico del modulo . Non dimenticare di aggiungerlo al tuo file .gitignore !

signing.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")
            // ...
        }
    }
}

-1

se non si desidera visualizzare Impossibile richiamare il metodo readLine () sull'oggetto null. devi prima scrivere in gradle.properties .

KEYSTORE_PASS=*****
ALIAS_NAME=*****
ALIAS_PASS=*****
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.