📜 ⬆️ ⬇️

Entering passwords when building projects using gradle

When building projects for Android, Gradle allows you to specify some parameters that allow you to build and sign a package ready for download to Google Play. However, it is hardly worth downloading some data, such as the password of the private key to the public repository. In the article, which is translated below, the author considers ways to enter private information, such as passwords, during project assembly.

Gradle allows access to the console using the System.console () method. The console provides a method for reading passwords, so you can use the following to enter a password:
def password = System.console().readPassword("\nPlease enter key passphrase: ") 

Now you can use the password anywhere in the build script, and everything is ready ... oh, then it will be too short a post, so now let's talk about the problems.


Problem number 1 - no need to pester me all the time.


If you simply place this line in your build.gradle, you will notice that it runs every time you build something. It does not matter whether you need to sign something in this build or not, the password will be requested in any case.
')
To solve this problem, you can use TaskGraph to check if a task that needs this key is being executed. Since the taskGraph will be filled at the beginning of the build process, you need to wait until it is filled:
 gradle.taskGraph.whenReady { taskGraph -> // ,  TaskGraph . } 

Simply place this piece of code in the build script and the code inside it will be executed when the graph is ready.

Now you need to check that we are performing a task that needs entering a password. TaskGraph has a hasTask () method, designed to ensure that a particular task will be executed at build time. You must specify the task name as a parameter. Also, you must specify a colon before the root directory name. If the task is defined in a submodule (as is usually the case in Android projects), you must also specify the name of this module. Let there be an app module in your project and we need a key password when we perform assembleRelease. So we can do the necessary verification:
 gradle.taskGraph.whenReady { taskGraph -> if(taskGraph.hasTask(':app:assembleRelease')) { //  ,      def pass = System.console().readPassword("\nPlease enter key passphrase: ") // readPassword  char[],       String pass = new String(pass) //      pass } } 

Now gradle won't bother you until he needs a password.

Problem number 2 - We do not have a console.


If you try to execute the code given above in the IDE (for example, in Android Studio) or using gradle.daemon , you will not have access to the console (System.console () will return null) and the assembly will fail due to an exception. But do not panic, this problem is solved. If we don't have access to the console, we still have the UI. We can use Groovy's SwngBuilder to show a simple password dialog.

First, you need to import it, so place the following line at the beginning of your build.gradle:
 import groovy.swing.SwingBuilder 

Now you can use SwingBuilder to show a simple input dialog:
 def pass = '' new SwingBuilder().edt { dialog(modal: true, //    ,    . title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, //     . pack: true, show: true ) { vbox { label(text: "Please enter key passphrase:") input = passwordField() button(defaultButton: true, text: 'OK', actionPerformed: { pass = input.password; dispose(); }) } } } 

Add this code where you need to request a password and you will receive the password entered by the user in the pass variable.

We connect everything together.


Let's put it all together now. The UI is good (ok, the one we used earlier is not very good, but you are free to modify it as you want: SwingBuilder docs ), but you may sometimes need to build on a system where there is only a console and no graphical interface (like a build server) and sometimes from your IDE. You may also want to cancel the build if the user has not entered a password. Now your build script should look like this:
 gradle.taskGraph.whenReady { taskGraph -> if(taskGraph.hasTask(':app:assembleRelease')) { def pass = '' if(System.console() == null) { new SwingBuilder().edt { dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true ) { vbox { label(text: "Please enter key passphrase:") input = passwordField() button(defaultButton: true, text: 'OK', actionPerformed: { pass = input.password dispose(); }) } } } } else { pass = System.console().readPassword("\nPlease enter key passphrase: ") pass = new String(pass) } if(pass.size() <= 0) { throw new InvalidUserDataException("You must enter a password to proceed.") } // ----- //      pass ,  ! // ----- } } 

Feel free to dive into the groovy documentation and see how you could improve this UI.

Source: https://habr.com/ru/post/221741/


All Articles