I\'m trying to get my gradle builds to prompt at the console for a password using examples from stack overflow
When I have a statment such as:
def pa
Simple solution to this is to check the console object for null:
def password = null
def console = System.console()
if (console != null) {
password = console.readLine("Enter keystore password: ")
}
Android Studio no longer complaints about the null object
.
To hide typed chars use readPassword()
instead of readLine()
:
password = new String(console.readPassword("\nEnter key password: "))
Executing System.getConsole()
from Gradle when org.gradle.daemon
property is true
, or when it's executed from an IDE like IntelliJ or Android Studio it returns null
. So for example do System.console().readLine()
becomes not possible.
Furthermore starting from Gradle 3.0 gradle.daemon is turned on by default.
Then instead of a workaround to use System.getConsole()
I purpose an alternative, use ant.input
like so:
task avoidNullOnConsole << {
ant.input(message: 'Enter keystore password:', addproperty: 'userInputPassword', defaultValue : '1234')
def password = ant.properties.userInputPassword
}
In this case ant.input
shows the message
and adds the user input in ant.properties
using as a property name the value defined in addProperty
. If there is no user input then the value defined in default
attribute is used.
Once executed you can get the user input using ant.properties.yourProperty
or ant.properties['yourProperty']
.
You can check the rest of the ant.input attributes here.
Note: If you want to use ant.input
multiple times take in account that you cannot override and existing property so addProperty
attribute must be different for each one.
To workaround this problem I used the standard input stream as next:
println "Enter keystore password"
def password = System.in.newReader().readLine()
Take a look at this blog post (https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/).
It describes multiple ways to handle signing configs and one of them is exactly your question regarding console input for the password.
create a simple function to request a password:
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)
}
}
or if you want Y/n answer:
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)
}
}
...
}
I found a solution here at https://www.timroes.de/2014/01/19/using-password-prompts-with-gradle-build-files and slightly modified it. Nevertheless, all credits go to 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
}
}
Somewhere in the some gradle file, you have the configuration for the release signing defined.
android {
...
signingConfigs {
...
release {
storeFile file(System.getProperty("user.home")+"\\android-key")
storePassword ''
keyAlias "standard"
keyPassword ''
}
}
...
}
(Don't forget to import groovy.swing.SwingBuilder
.)
Regarding the second part, you may also have a look at How to create a release signed apk file using Gradle?