web-dev-qa-db-fra.com

Gradle build null console object

J'essaie d'obtenir mes versions Gradle pour demander un mot de passe à la console à l'aide d'exemples de débordement de pile

Quand j'ai une déclaration telle que:

def password = System.console().readLine("Enter keystore password ")

Quand je cours, j'obtiens l'erreur

Cannot invoke method readLine() on null object

Il semble que la console sort sous la forme null. Ce que j'ai lu nécessite Java 6 qui, si je vais à une invite de commande et tape Java -version J'exécute Java (TM) SE Runtime Environment (build 1.6.0_27-b07).

Ce problème est suivi dans le dépôt Github de Gradle: Impossible d'utiliser System.console () avec le démon Gradle .

42
Andrew

Ok, la raison pour laquelle cela n'a pas fonctionné était idiote, mais juste au cas où quelqu'un d'autre le rencontrerait, je pensais que je posterais.

J'exécutais la tâche à travers Android studio et je ne savais pas que l'objet console serait toujours nul. Lors de l'exécution à partir de la ligne de commande, l'objet "commande" n'est pas nul et cela fonctionne bien .

16
Andrew

Pour une raison quelconque, l'exécution de gradle en mode démon provoque un objet console nul. Si vous spécifiez l'indicateur de ligne de commande approprié,

./gradlew assembleRelease --no-daemon

ça va marcher.

44
Jason Tu

J'ai trouvé une solution ici à https://www.timroes.de/2014/01/19/using-password-prompts-with-gradle-build-files et l'ai légèrement modifiée. Néanmoins, tous les crédits reviennent à Tim Roes!

gradle.taskGraph.whenReady { taskGraph ->
if(taskGraph.hasTask(':app:assembleRelease')) {
    def storePass = ''
    def keyPass = ''
    if(System.console() == null) {
        new SwingBuilder().edt {
            dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
                vbox { // Put everything below each other
                    label(text: "Please enter store passphrase:")
                    def input1 = passwordField()
                    label(text: "Please enter key passphrase:")
                    def input2 = passwordField()
                    button(defaultButton: true, text: 'OK', actionPerformed: {
                        storePass = input1.password;
                        keyPass = input2.password;
                        dispose();
                    })
                }
            }
        }
    } else {
        storePass = System.console().readPassword("\nPlease enter store passphrase: ")
        keyPass = System.console().readPassword("\nPlease enter key passphrase: ")
    }

    if(storePass.size() <= 0 || keyPass.size() <= 0) {
        throw new InvalidUserDataException("You must enter the passwords to proceed.")
    }

    storePass = new String(storePass)
    keyPass = new String(keyPass)

    Android.signingConfigs.release.storePassword = storePass
    Android.signingConfigs.release.keyPassword = keyPass
    }
}

Quelque part dans le fichier Gradle, vous avez défini la configuration de la signature de version.

Android {
...
signingConfigs {
    ...
    release {
        storeFile file(System.getProperty("user.home")+"\\Android-key")
        storePassword ''
        keyAlias "standard"
        keyPassword ''
    }
}

...
}

(N'oubliez pas de import groovy.swing.SwingBuilder.)

En ce qui concerne la deuxième partie, vous pouvez également consulter Comment créer un fichier apk signé avec Gradle?

20
Martin L.

Exécution de System.getConsole() à partir de Gradle lorsque la propriété org.gradle.daemon Est true, ou lorsqu'elle est exécutée à partir d'un IDE = comme IntelliJ ou Android Studio il renvoie null. Ainsi, par exemple, faire System.console().readLine() devient impossible.

De plus, à partir de Gradle 3.0gradle.daemon Est activé par défaut .

Ensuite, au lieu d'une solution de contournement pour utiliser System.getConsole() Je propose une alternative, utilisez ant.input Comme ceci:

task avoidNullOnConsole << {
    ant.input(message: 'Enter keystore password:', addproperty: 'userInputPassword', defaultValue : '1234')
    def password = ant.properties.userInputPassword
}

Dans ce cas, ant.input Affiche le message et ajoute l'entrée utilisateur dans ant.properties En utilisant comme nom de propriété la valeur définie dans addProperty. S'il n'y a pas d'entrée utilisateur, la valeur définie dans l'attribut default est utilisée.

Une fois exécuté, vous pouvez obtenir l'entrée utilisateur en utilisant ant.properties.yourProperty Ou ant.properties['yourProperty'].

Vous pouvez vérifier le reste des attributs ant.input Ici .

Remarque: Si vous souhaitez utiliser ant.input Plusieurs fois, tenez compte du fait que vous ne pouvez pas remplacer la propriété existante, donc addProperty l'attribut doit être différent pour chacun.

9
albciff

Jetez un œil à cet article de blog ( https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/ ).

Il décrit plusieurs façons de gérer les configurations de signature et l'une d'entre elles est exactement votre question concernant l'entrée de la console pour le mot de passe.

7
Michael Barany

Vous pouvez également exécuter votre script avec:

-Dorg.gradle.daemon = false

3
ezgi

Une solution simple à cela consiste à vérifier la null de l'objet console:

def password = null
def console = System.console()
if (console != null) {
    password = console.readLine("Enter keystore password: ")
}

Android Studio ne se plaint plus du null object.

Pour masquer les caractères saisis, utilisez readPassword() au lieu de readLine():

password = new String(console.readPassword("\nEnter key password: "))
3
petrsyn

Pour contourner ce problème, j'ai utilisé le flux d'entrée standard comme suit:

println "Enter keystore password"
def password = System.in.newReader().readLine()
3
Nicolas Filotto

créer une fonction simple pour demander un mot de passe:

import javax.swing.JOptionPane

def askPass() {
  def msg = 'Enter keystore password'
  if (System.console() != null) {
    return System.console().readLine(msg)
  } else {
    return javax.swing.JOptionPane.showInputDialog(msg)
  }
}

ou si vous voulez une réponse O/n:

import javax.swing.JOptionPane

def ask(msg) {
  if (System.console() != null) {
    return System.console().readLine(msg + ' [y/n]') == 'y'
  } else {
    def res = JOptionPane.showConfirmDialog(null, msg, "Confirm operation", JOptionPane.YES_NO_OPTION)
    return res == JOptionPane.YES_OPTION
  }
}

// usage:

task run() {
  doFirst {
    if (file('out.txt').exists() && !ask('overwrite output?')) {
      System.exit(2)
    }
  }
  ...
}
1
Grigory K