【问题标题】:Gradle build null console objectGradle 构建空控制台对象
【发布时间】:2013-10-29 12:50:45
【问题描述】:

我正在尝试使用堆栈溢出中的示例让我的 gradle 构建在控制台提示输入密码

当我有这样的陈述时:

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

运行时出现错误

Cannot invoke method readLine() on null object

控制台似乎以null 的形式出现。我读到的内容需要 java 6,如果我进入命令提示符并键入 java -version,我正在运行 Java(TM) SE 运行时环境(build 1.6.0_27-b07)。

Gradle 的 Github 存储库中正在跟踪此问题:Can't use System.console() with the Gradle Daemon

【问题讨论】:

    标签: gradle android-gradle-plugin build.gradle


    【解决方案1】:

    出于某种原因,在守护程序模式下运行 gradle 会导致控制台对象为空。如果您指定了适当的命令行标志,

    ./gradlew assembleRelease --no-daemon

    它会起作用的。

    【讨论】:

    • 大声笑,这对一个项目有效,但对另一个项目无效。
    • 无法使用 gradle 4.2 > 无法在 null 对象上调用方法 readPassword()
    【解决方案2】:

    我在https://www.timroes.de/2014/01/19/using-password-prompts-with-gradle-build-files 找到了一个解决方案并稍作修改。尽管如此,所有的功劳都归于 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
        }
    }
    

    在某个 gradle 文件的某处,您已经定义了发布签名的配置。

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

    (别忘了import groovy.swing.SwingBuilder。)

    关于第二部分,你也可以看看How to create a release signed apk file using Gradle?

    【讨论】:

    • Tim Roes 的解决方案很棒
    • 非常好的生产就绪修改,谢谢。别忘了import groovy.swing.SwingBuilder
    • AS 现在显示关于 import groovy.swing.SwingBuilder 的错误。幸运的是它仍然会进行调试构建,命令行 gradlew 仍然可以导入 groovy。见stackoverflow.com/q/43423331/1682419
    • 哇,很简单,只需使用:def pass = javax.swing.JOptionPane.showInputDialog("请输入密码:")
    • 对我不起作用,我得到一个Failed to create component for 'dialog' reason: java.awt.HeadlessException &gt; java.awt.HeadlessException (no error message)
    【解决方案3】:

    好的,这不起作用的原因很愚蠢,但以防万一其他人遇到它,我想我会发布。

    我正在通过 android studio 运行任务,但没有意识到控制台对象将始终为空。从命令行运行时,“命令”对象不为空,并且可以正常工作。

    【讨论】:

    • 从这两个地方运行时,您是否找到了解决方法来使这项工作正常进行?
    • 在我的情况下,即使通过终端运行,对象也是空的。我不想通过 AS 运行。
    【解决方案4】:

    org.gradle.daemon 属性为true 时从Gradle 执行System.getConsole(),或者当它从IntelliJAndroid Studio 等IDE 执行时em> 它返回null。因此,例如做System.console().readLine() 变得不可能。

    另外从Gradle 3.0 gradle.daemon is turned on by default开始。

    然后,我打算使用System.getConsole(),而不是使用System.getConsole() 的解决方法,像这样使用ant.input

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

    在这种情况下,ant.input 显示message,并使用addProperty 中定义的值作为属性名称在ant.properties 中添加用户输入。如果没有用户输入,则使用default 属性中定义的值。

    执行后,您可以使用ant.properties.yourPropertyant.properties['yourProperty'] 获取用户输入。

    您可以查看ant.input attributes here 的其余部分。

    注意:如果您想多次使用ant.input,请考虑到您无法覆盖现有属性,因此每个addProperty 属性必须不同。

    【讨论】:

    • 效果很好,有没有办法隐藏用户正在输入的内容?
    • 如果您使用ant.version &gt; 1.8 似乎将handler(type:'secure') 添加到ant.input 必须有效...我检查在build.xml 中使用&lt;input message="Enter some user input data?" addproperty="userInput" defaultValue="nothing"&gt;&lt;handler type="secure"/&gt;&lt;/input&gt; 并且效果很好,但是在@ 987654347@等价的ant.input(message: 'Enter some user input data?', addproperty: 'userInput', defaultValue : 'nothing'){ handler(type: 'secure') }不隐藏用户输入:(
    【解决方案5】:

    看看这篇博文 (https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/)。

    它描述了处理签名配置的多种方法,其中之一正是您关于控制台输入密码的问题。

    【讨论】:

      【解决方案6】:

      为了解决这个问题,我使用了标准输入流作为下一个:

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

      【讨论】:

      • 有效。 Howeber,如何读取密码? readPassword()Console 类的函数。
      • @galcyurio,readPassword() 给你什么readLine() 没有?它只是隐藏输入吗?
      【解决方案7】:

      您也可以使用以下命令执行脚本:

      -Dorg.gradle.daemon=false

      【讨论】:

        【解决方案8】:

        解决这个问题的简单方法是检查控制台对象是否为空:

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

        Android Studio 不再抱怨null object

        要隐藏键入的字符,请使用 readPassword() 而不是 readLine()

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

        【讨论】:

        • 这并不能解决没有控制台的问题。您想通过命令行或控制台输入密码。现在您将遇到空密码的问题。
        【解决方案9】:

        创建一个简单的函数来请求密码:

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

        或者如果你想要 Y/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)
            }
          }
          ...
        }
        

        【讨论】:

        【解决方案10】:
        password System.console() != null ? System.console().readLine("\ password: ") : ""
        

        【讨论】:

        • 完全不设置密码也无济于事。
        猜你喜欢
        • 2013-02-03
        • 1970-01-01
        • 2012-01-28
        • 1970-01-01
        • 2017-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-13
        相关资源
        最近更新 更多