web-dev-qa-db-fra.com

Signer APK sans mettre les informations de magasin de clés dans build.gradle

J'essaie de configurer le processus de signature de sorte que le mot de passe du fichier de clés et le mot de passe de la clé ne sont pas soient stockés dans le fichier build.gradle Du projet.

Actuellement, j'ai les éléments suivants dans le build.gradle:

Android {
    ...
    signingConfigs {
        release {
            storeFile file("my.keystore")
            storePassword "store_password"
            keyAlias "my_key_alias"
            keyPassword "key_password"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release            
        }
    }
}

Cela fonctionne parfaitement bien mais je ne doit pas mettre les valeurs pour le storePassword et le keyPassword dans mon référentiel. Je préférerais ne pas y mettre storeFile et keyAlias.

Y a-t-il un moyen de modifier le build.gradle Pour qu'il obtienne les mots de passe d'une source externe (comme un fichier résidant sur mon ordinateur uniquement)?

Et bien sûr, le build.gradle Modifié devrait être utilisable sur tout autre ordinateur (même si l'ordinateur n'a pas accès aux mots de passe).

J'utilise Android Studio et Maverics sous Mac OS X, le cas échéant).

133
Bobrovsky

La bonne chose à propos de Groovy est que vous pouvez librement mélanger du code Java), et il est assez facile de lire un fichier clé/valeur en utilisant Java.util.Properties. Il existe peut-être un moyen encore plus simple d’utiliser Groovy idiomatique, mais Java est encore assez simple.

Créer un keystore.properties fichier (dans cet exemple, dans le répertoire racine de votre projet à côté de settings.gradle, bien que vous puissiez le placer où bon vous semble:

storePassword=...
keyPassword=...
keyAlias=...
storeFile=...

Ajoutez ceci à votre build.gradle:

allprojects {
    afterEvaluate { project ->
        def propsFile = rootProject.file('keystore.properties')
        def configName = 'release'

        if (propsFile.exists() && Android.signingConfigs.hasProperty(configName)) {
            def props = new Properties()
            props.load(new FileInputStream(propsFile))
            Android.signingConfigs[configName].storeFile = file(props['storeFile'])
            Android.signingConfigs[configName].storePassword = props['storePassword']
            Android.signingConfigs[configName].keyAlias = props['keyAlias']
            Android.signingConfigs[configName].keyPassword = props['keyPassword']
        }
    }
}
109
Scott Barta

Sinon, si vous souhaitez appliquer la réponse de Scott Barta d'une manière plus similaire au code de gradation généré automatiquement, vous pouvez créer un keystore.properties fichier dans le dossier racine de votre projet:

storePassword=my.keystore
keyPassword=key_password
keyAlias=my_key_alias
storeFile=store_file  

et modifiez votre code de classement pour:

// Load keystore
def keystorePropertiesFile = rootProject.file("keystore.properties");
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

...

Android{

    ...

    signingConfigs {
        release {
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
        }
    }

    ...

}

Vous pouvez stocker ce fichier de propriétés à la racine de votre module, auquel cas il suffit d'omettre rootProject, et vous pouvez également modifier ce code pour avoir plusieurs ensembles de propriétés pour différents magasins de clés et alias de clés.

93
CurlyCorvus

Le moyen le plus simple consiste à créer un fichier ~/.gradle/gradle.properties.

Android_STORE_PASSWORD=hunter2
Android_KEY_PASSWORD=hunter2

Votre fichier build.gradle Peut alors ressembler à ceci:

Android {
    signingConfigs {
        release {
            storeFile file('yourfile.keystore')
            storePassword Android_STORE_PASSWORD
            keyAlias 'youralias'
            keyPassword Android_KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
27
Dan Fabulich

Après avoir lu quelques liens:

http://blog.macromates.com/2006/keychain-access-from-Shell/http://www.thoughtworks.com/es/insights/blog/signing-open -source-applications-android-sans-divulgation-mots-de-passe

Puisque vous utilisez Mac OSX, vous pouvez utiliser le trousseau d'accès pour stocker vos mots de passe.

How to add password in Keychain Access

Ensuite, dans vos scripts Gradle:

/* Get password from Mac OSX Keychain */
def getPassword(String currentUser, String keyChain) {
    def stdout = new ByteArrayOutputStream()
    def stderr = new ByteArrayOutputStream()
    exec {
        commandLine 'security', '-q', 'find-generic-password', '-a', currentUser, '-gl', keyChain
        standardOutput = stdout
        errorOutput = stderr
        ignoreExitValue true
    }
    //noinspection GroovyAssignabilityCheck
    (stderr.toString().trim() =~ /password: '(.*)'/)[0][1]
}

Utilisez comme ceci:

getPassword (currentUser, "Android_Store_Password")

/* Plugins */
apply plugin: 'com.Android.application'

/* Variables */
ext.currentUser = System.getenv("USER")
ext.userHome = System.getProperty("user.home")
ext.keystorePath = 'KEY_STORE_PATH'

/* Signing Configs */
Android {  
    signingConfigs {
        release {
            storeFile file(userHome + keystorePath + project.name)
            storePassword getPassword(currentUser, "Android_STORE_PASSWORD")
            keyAlias 'jaredburrows'
            keyPassword getPassword(currentUser, "Android_KEY_PASSWORD")
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
20
Jared Burrows

C'est comme ça que je le fais. Utiliser les variables d'environnement

  signingConfigs {
    release {
        storeFile file(System.getenv("KEYSTORE"))
        storePassword System.getenv("KEYSTORE_PASSWORD")
        keyAlias System.getenv("KEY_ALIAS")
        keyPassword System.getenv("KEY_PASSWORD")
    }
16
Madhur Ahuja

La réponse acceptée utilise un fichier pour contrôler le magasin de clés à utiliser pour signer le fichier APK qui réside dans le même dossier racine du projet. Lorsque nous utilisons vcs comme Git , cela peut être une mauvaise chose d’oublier d’ajouter le fichier de propriétés à ignorer. Parce que nous allons divulguer notre mot de passe au monde. Les problèmes persistent encore.

Au lieu de créer un fichier de propriétés dans le même répertoire de notre projet, nous devrions le faire en dehors. Nous le faisons à l'extérieur en utilisant le fichier gradle.properties.

Voici les étapes:

1. Modifiez ou créez gradle.properties sur votre projet racine et ajoutez le code suivant. N'oubliez pas de modifier le chemin avec le vôtre:

AndroidProject.signing=/your/path/androidproject.properties  

2.Créez androidproject.properties dans/votre/chemin/et ajoutez-y le code suivant, n'oubliez pas de changer le paramètre /your/path/to/Android.keystore en votre chemin de magasin de clés:

STORE_FILE=/your/path/to/Android.keystore  
STORE_PASSWORD=yourstorepassword  
KEY_ALIAS=yourkeyalias  
KEY_PASSWORD=yourkeypassword  

3.Dans votre module d'application build.gradle (pas votre build.gradle racine du projet), ajoutez le code suivant s'il n'existe pas ou ajustez-le:

signingConfigs {  
     release  
   }  
   buildTypes {  
   debug {  
     debuggable true  
   }  
   release {  
     minifyEnabled true  
     proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'  
     signingConfig signingConfigs.release  
   }  
 }  

4.Ajoutez le code suivant sous le code de l'étape 3:

if (project.hasProperty("AndroidProject.signing")  
     && new File(project.property("AndroidProject.signing").toString()).exists()) {  
     def Properties props = new Properties()  
     def propFile = new File(project.property("AndroidProject.signing").toString())  
     if(propFile.canRead()) {  
      props.load(new FileInputStream(propFile))  
      if (props!=null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&  
         props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {  
         Android.signingConfigs.release.storeFile = file(props['STORE_FILE'])  
         Android.signingConfigs.release.storePassword = props['STORE_PASSWORD']  
         Android.signingConfigs.release.keyAlias = props['KEY_ALIAS']  
         Android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']  
      } else {  
         println 'androidproject.properties found but some entries are missing'  
         Android.buildTypes.release.signingConfig = null  
      }  
     } else {  
            println 'androidproject.properties file not found'  
          Android.buildTypes.release.signingConfig = null  
     }  
   }  

Ce code va rechercher la propriété AndroidProject.signing dans gradle.properties à partir de étape 1. Si la propriété est trouvée, elle convertira la valeur de la propriété en chemin de fichier qui pointe vers androidproject.properties que nous créons dans étape 2. Ensuite, toute la valeur de la propriété sera utilisée comme configuration de signature pour notre build.gradle.

Désormais, nous n'avons plus besoin de craindre le risque de divulgation du mot de passe de notre magasin de clés.

En savoir plus sur Signature Android apk sans mettre les informations du magasin de clés dans le fichier build.gradle

Il est possible de prendre n'importe quel projet Android Studio Gradle et de le construire/le signer à partir de la ligne de commande sans éditer aucun fichier. Ceci le rend très pratique pour stocker votre projet dans le contrôle de version tout en conservant vos clés et les mots de passe sont séparés et non dans votre fichier build.gradle:

./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
6
Wayne Piekarski

Pour ceux qui cherchent à mettre leurs identifiants dans un fichier JSON externe et à le lire dans le dégradé, voici ce que j'ai fait:

mon_projet/credentials.json:

{
    "Android": {
        "storeFile": "/path/to/acuity.jks",
        "storePassword": "your_store_password",
        "keyAlias": "your_Android_alias",
        "keyPassword": "your_key_password"
    }
}

mon_projet/Android/app/build.gradle

// ...
signingConfigs {
        release {

            def credsFilePath = file("../../credentials.json").toString()
            def credsFile = new File(credsFilePath, "").getText('UTF-8')
            def json = new groovy.json.JsonSlurper().parseText(credsFile)
            storeFile file(json.Android.storeFile)
            storePassword = json.Android.storePassword
            keyAlias = json.Android.keyAlias
            keyPassword = json.Android.keyPassword
        }
        ...
        buildTypes {
            release {
                signingConfig signingConfigs.release //I added this
                // ...
            }
        }
    }
// ...
}

La raison pour laquelle j'ai choisi un .json type de fichier, et non un .properties type de fichier (comme dans la réponse acceptée), c’est parce que je voulais également stocker d’autres données (autres propriétés personnalisées dont j'avais besoin) dans ce même fichier (my_project/credentials.json), et demandez toujours à Gradle d’analyser également les informations de signature contenues dans ce fichier.

6
SudoPlz

Cette question a reçu de nombreuses réponses valables, mais je voulais partager mon code qui pourrait être utile pour responsables de la bibliothèque, car laisse l'original build.gradle assez propre.

J'ajoute un dossier au répertoire du module dans lequel je gitignore. Cela ressemble à ceci:

/signing
    /keystore.jks
    /signing.gradle
    /signing.properties

keystore.jks et signing.properties devrait être explicite. Et signing.gradle ressemble à ça:

def propsFile = file('signing/signing.properties')
def buildType = "release"

if (!propsFile.exists()) throw new IllegalStateException("signing/signing.properties file missing")

def props = new Properties()
props.load(new FileInputStream(propsFile))

def keystoreFile = file("signing/keystore.jks")
if (!keystoreFile.exists()) throw new IllegalStateException("signing/keystore.jks file missing")

Android.signingConfigs.create(buildType, {
    storeFile = keystoreFile
    storePassword = props['storePassword']
    keyAlias = props['keyAlias']
    keyPassword = props['keyPassword']
})

Android.buildTypes[buildType].signingConfig = Android.signingConfigs[buildType]

Et l'original build.gradle

apply plugin: 'com.Android.application'
if (project.file('signing/signing.gradle').exists()) {
    apply from: 'signing/signing.gradle'
}

Android {
    compileSdkVersion 27
    defaultConfig {
        applicationId ...
    }
}

dependencies {
    implementation ...
}

Comme vous pouvez le constater, vous n'avez pas du tout besoin de spécifier les buildTypes. Si l'utilisateur a accès à un répertoire valide signing, il le met simplement dans le module et peut créer une application valide signée, sinon cela fonctionne pour lui comme il le ferait normalement.

3
Michał K

Vous pouvez demander des mots de passe à partir de la ligne de commande:

...

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
  }

  ...
}

...

Cette réponse est apparue précédemment: https://stackoverflow.com/a/33765572/3664487

0
user2768