By Jan-Terje Sørensen


2013-08-20 06:53:47 8 Comments

I would like to have my Gradle build to create a release signed apk file using Gradle.

I'm not sure if the code is correct or if I'm missing a parameter when doing gradle build?

This is some of the code in my gradle file:

android {
    ...
    signingConfigs {
          release {
              storeFile file("release.keystore")
              storePassword "******"
              keyAlias "******"
              keyPassword "******"
         }
     }
}

The gradle build finishes SUCCESSFUL, and in my build/apk folder I only see the ...-release-unsigned.apk and ...-debug-unaligned.apk files.

Any suggestions on how to solve this?

27 comments

@user1506104 2019-09-15 18:11:21

It is 2019 and I need to sign APK with V1 (jar signature) or V2 (full APK signature). I googled "generate signed apk gradle" and it brought me here. So I am adding my original solution here.

signingConfigs {
    release {
        ...
        v1SigningEnabled true
        v2SigningEnabled true
    }
}

My original question: How to use V1 (Jar signature) or V2 (Full APK signature) from build.gradle file

@Takeshi Kaga 2019-11-22 19:40:24

No need semi-colons; it will give you an error.

@user1506104 2019-11-23 09:00:31

That is right. Thanks. I edited the answer.

@user2288580 2014-09-13 02:34:30

I had quite a lot of fun figuring this one out. Here is my walk-through.

A to Z walk-through on how to create a gradle build file in IntelliJ (v.13.1.4) This walk-through assumes you know how to make a keystore file. For this tutorial to work you will need your keystore file to be located in your app folder and you will need to have your zipalign.exe file to be located in 'SDK-ROOT\tools'. This file is usually found in 'SDK-ROOT\build-tools' and under this folder it will be in the highest api folder (alpha or beta I recommend the alpha version).

For those of you that wish to jump straight in here is the gradle build file.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}
android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        playstore {
            keyAlias 'developers4u'
            keyPassword 'thisIsNotMyRealPassword'
            storeFile file('developers4u.keystore')
            storePassword 'realyItIsNot'
        }
    }
    buildTypes {
        assembleRelease {
            debuggable false
            jniDebugBuild false
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            zipAlign true
            signingConfig signingConfigs.playstore
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

You can build part of this build file (above) from menu option: File/Project Structure From here select Facets and click 'Android-Gradle(App). From here you will see tabs: 'Properties', 'Signing', 'Flavors', 'Build Types' and 'Dependencies' for this walk-through we will just be using 'Signing' and 'Build Types'. Under 'Build Types' (in the name section) enter any name that you wish to identify your build type configuration and in the other 4 fields enter your keystore information (setting the keystore path the the one under your app folder).

Under the 'Build Types' enter the value 'assembleRelease' into the name field, 'Debuggable' should be set to false, 'Jni Debug Build' should be false, set 'Run Proguard' to true and 'Zip Align' to true. This will generate build file, but not as depicted above, you will have to add a few things to the build file afterwards. The ProGuard file location here will be set manually in the gradle build file. (as depicted above)

The DSL containers you will have to add afterwards are as follows:

android {
    ....
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    ....
}

You will also have to add:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

note this DSL container above('dependencies') should be at the bottom of the config file but not inside the android DSL container. In order to build the dependencies container from the IntelliJ menu, select: File/Project Structure. From there select Facets again and then Android-Gradle(app). You will see the same 5 tabs as mentioned above. Select the 'Dependencies' tab and add the dependencies you require.

After all of this is done you should see a Gradle build file similar to the file at the top of this walk-through. To build your signed zip aligned release you will need to open the Gradle tasks. You can get to this window by selecting View/Tool Windows/Gradle. From here you can double Click 'assembleAssembleRelease. This should generate your deployable APK.

The potential problems that can occur when compiling your release are (but not limited to): Your Gradle build file being in the wrong place. There are two Gradle build files; one in your application root folder and another in the app folder under the application root. You must user the latter.

You may also have lint problems. (Note: Android Developer Studio is much better at spotting Lint problems than IntelliJ you will notice this when trying to generate an signed APK from the menu options)

To get around lint problems you will need to put the following DSL container inside the android container (at the top):

android {
        ....
    lintOptions {
        abortOnError false
    }
    ....
}

putting this inside your android DSL container will cause an error file to be generated in the build folder (directly under your app folder) the file name should be something like 'lint-results-release-fatal.html' this file will tell you the the class where the error occurred. Another file that will be generated is an XML file that contains the 'issue ID' associated with the lint error. The file name should be something like 'lint-results-release-fatal.xml'. Somewhere near the top of the file you will see a node 'issue' inside which you will see something similar to 'id="IDOfYourLintProblem"'

To correct this problem open the file in your project that was listed in the 'lint-results-assembleRelease-fatal.html' file and enter the following line of code in the Java Class file just above the class name: @SuppressLint("IDOfYourLintProblem"). You may have to import 'android.annotation.SuppressLint;'

So your java class file should appear like:

package com.WarwickWestonWright.developers4u.app.CandidateArea;

import android.annotation.SuppressLint;
... other imports

@SuppressLint("IDOfYourLintProblem")
public class SearchForJobsFragment extends Fragment {... rest of your class definition}

Note that suppressing lint errors is not always the best IDEA you may be better off to change your code that caused the lint errors.

Another problem that could potentially occur is if you have not set the environment variable for the Gradle HOME environment variable. This variable is named 'GRADLE_HOME' and should be set the the path of the gradle home directory, something like 'C:\gradle-1.12' Sometimes you may also want to set the environment variable for 'ANDROID_HOME' set this to 'YOUR-SDK-Root\sdk'

After this is done return to the Gradle tasks window and double click the assembleAssembleRelease.

If all is successful you should be able to go to the folder app\build\apk and find your deployable APK file.

@Raz Tourgman 2015-06-17 12:06:51

+1 for the effort and: 'lintOptions { abortOnError false }'

@not2qubit 2017-04-05 11:51:44

Automatic app signing with Gradle when using git

It's amazing how many convoluted ways there are for doing this. Here is my own way, where I try to adhere to Googles own recommendation. However, their explanation is not fully clear, so I will describe the procedure for Linux in detail.


Description:

The default Google instructions for automatically signing an app during the build, without keeping the passwords and signature files in your app development (GIT) path, is rather obscure. Here are the clarified step-by-step instructions how to do so.

Initial assumptions:

You have an app called "MyApp" in a directory given by the following path: $HOME/projects/mydev/MyApp. However, the MyApp directory is used and controlled with GIT.

enter image description here

Problem

We obviously don't want to have our signature or password files anywhere in the GIT controlled directory, even if we are very able to use .gitignore etc, it is still too risky and easy to make a mistake. So we want our keystore and signature files outside.

Solution

We need to do three (3) things:

  1. Create a password file to be used by Android Studio
  2. Create signature key file
  3. Edit the module build.gradle file to use (1) and (2).

For this example we name the two files:

  1. keystore.properties
  2. MyApp-release-key.jks

We can put both of these files here:

cd $HOME/projects/mydev/

(1) Create the keystore password file

The first file contain the clear text passwords used in; and paths to the release-key file in (2). Start with filling this out, as it will make a copy paste operation easier for the next step.

cd $HOME/projects/mydev/

Edit keystore.properties so that it's content is:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation

The only tricky part here, is the myStoreFileLocation. This is the path as seen from the module build.gradle file during the build. This usually means a path similar and relative to: $HOME/projects/mydev/MyApp/app/build.gradle. So in order to point to the MyApp-release-key.jks file, what we need to put here is:

../../../MyApp-release-key.jks

Here, we also chose the "myapp" alias for the key. Then the final file should look:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myapp
storeFile=../../../MyApp-release-key.jks

(2) Create the signature file

The second file is automatically generated when you create the signature key. If you have no other apps and this is your only keystore, then create the file with:

cd $HOME/projects/mydev/
keytool -genkeypair -v -keystore MyApp-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myapp

This will ask you for two passwords and a bunch of info. (Same stuff as in Android Studio.) Now copy/paste your previously chosen passwords.

(3) Edit your module gradle.build file to use the above

The following parts need to be present in your app/module's Gradle build file. First, add the following lines outside and before your android {} block.

//def keystorePropertiesFile = rootProject.file("$HOME/.android/keystore.properties")
def keystorePropertiesFile = rootProject.file("../../keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

Then, inside the android {} block, add:

android {
    ...
    defaultConfig { ... }
    signingConfigs {
            release {
                keyAlias keystoreProperties['keyAlias']
                keyPassword keystoreProperties['keyPassword']
                storeFile file(keystoreProperties['storeFile'])
                storePassword keystoreProperties['storePassword']
            }
        }
    // Tell Gradle to sign your APK
    buildTypes {
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

Now from shell, you can re-build your app with:

cd $HOME/projects/mydev/MyApp/app/
./gradlew clean build

This should generate a properly signed app that can be used in Google Play.


UPDATE: 2019-04-02

More recent versions of keytool and something is telling you that you should use a PKCS12 based keyfile instead of the original/default as I use above. They then go on telling you you should convert to the new open PKCS12 format. However, it seem that the Android development tools are not quite ready for this yet, because if you do, you will get the following weird errors:

com.android.ide.common.signing.KeytoolException: Failed to read key XXX from store "F:\XXX\XXX.jks": Get Key failed: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

So don't use a converted key!

@JavierSegoviaCordoba 2017-08-29 00:49:09

Is signingConfigs saved inside the apk and then it can be decompiled by any user to get passwords or it doens't appear in the apk?

@pratham kesarkar 2017-09-05 07:52:30

Works like charm. Thank-you this should be the accepted Answer

@Diana Farin 2017-09-08 12:58:04

What if you only want the keystore and passwords on a build server? With the solution above every developer in the team needs to have the keystore on their local machine. Otherwise the Gradle project sync will fail: keystore.properties (No such file or directory).

@dskrvk 2017-10-22 15:46:15

You can commit a dummy keystore.properties file to source control, so builds work on dev machines. I've described a build server setup here.

@Ahamadullah Saikat 2017-12-12 10:32:07

Android Studio Go to File -> Project Structure or press Ctrl+Alt+Shift+S

See The Image

enter image description here

Click Ok

Then the signingConfigs will generate on your build.gradle file.

enter image description here

@not2qubit 2018-12-15 09:50:51

And this is exactly what you don't want to do. This way all your passwords are in clear-text and part of your project, and very easy to accidentally include, even in your distributed build.

@janpio 2017-11-17 18:03:58

If you have the keystore file already, it can be as simple as adding a few parameters to your build command:

./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

No permanent changes to your Android project necessary.

Source: http://www.tinmith.net/wayne/blog/2014/08/gradle-sign-command-line.htm

@SRC 2017-01-17 08:48:38

Extending the answer by David Vavra,create a file ~/.gradle/gradle.properties and add

RELEASE_STORE_FILE=/path/to/.keystore
RELEASE_KEY_ALIAS=XXXXX
RELEASE_STORE_PASSWORD=XXXXXXXXX
RELEASE_KEY_PASSWORD=XXXXXXXXX

Then in build.gradle

  signingConfigs {
    release {
    }
  }

  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true

    }
  }

  // make this optional
  if ( project.hasProperty("RELEASE_KEY_ALIAS") ) {
    signingConfigs {
      release {
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
      }
    }
    buildTypes {
      release {
        signingConfig signingConfigs.release
      }
    }
  }

@Torge 2016-03-24 00:38:28

If you, like me, just want to be able to run the release on your device for testing purposes, consider creating a second keystore for signing, so you can simply put the passwords for it into your build.gradle without worrying for your market key store security.

You can create a new keystore by clicking Build/Generate Signed APK/Create new...

@Egis 2016-01-07 09:53:11

If you build apk via command line like me then you can provide signing configuration as arguments.

Add this to your build.gradle

def getStore = { ->
    def result = project.hasProperty('storeFile') ? storeFile : "null"
    return result
}

def getStorePassword = { ->
    def result = project.hasProperty('storePassword') ? storePassword : ""
    return result
}

def getKeyAlias = { ->
    def result = project.hasProperty('keyAlias') ? keyAlias : ""
    return result
}

def getKeyPassword = { ->
    def result = project.hasProperty('keyPassword') ? keyPassword : ""
    return result
}

Make your signingConfigs like this

signingConfigs {
    release {
        storeFile file(getStore())
        storePassword getStorePassword()
        keyAlias getKeyAlias()
        keyPassword getKeyPassword()
    }
}

Then you execute gradlew like this

./gradlew assembleRelease -PstoreFile="keystore.jks" -PstorePassword="password" -PkeyAlias="alias" -PkeyPassword="password"

@Vlad 2018-05-12 08:24:56

Which is build.gradle? Top level? Please add more code

@Egis 2018-05-13 09:21:03

To clarify, this is app/build.gradle file I'm talking about.

@JeasonWong 2016-01-25 03:49:23

if you don't want to see Cannot invoke method readLine() on null object. you need write in gradle.properties first.

KEYSTORE_PASS=*****
ALIAS_NAME=*****
ALIAS_PASS=*****

@sandalone 2015-06-18 11:01:43

In newer Android Studio, there is a GUI way which is very easy and it populates Gradle file as well.

  1. File -> Project Structure

  2. Module -> Choose the main module ('app' or other custom name)

  3. Signing tab -> Plus image to add new configuration

  4. Fill data on the right side

  5. OK and Gradle file is automatically created

  6. You will manually have to add a line signingConfig signingConfigs.NameOfYourConfig inside builtTypes{release{}}

Images:

enter image description here

enter image description here

Two important(!) notes:

(EDIT 12/15)

  1. To create signed APK, you'd have to open Terminal tab of Android Studio (the bottom of the main interface) and issue a command ./gradlew assembleRelease

  2. If you forgot keyAlias (what happens often to me), you will have to initiate Build -> Generate Signed APK to start the process and see the name of the Alias key.

@Joshua Pinter 2017-09-06 18:19:48

This hardcodes your passwords into the build.gradle file, though, doesn't it?

@user2768 2015-11-17 19:38:15

You can request passwords from the command line:

...

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
  }

  ...
}

...

The if-then-else block prevents requests for passwords when you're building a release. Although the else branch is unreachable, it tricks Gradle into creating an install...Release task.

Backstory. As noted by https://stackoverflow.com/a/19130098/3664487, "Gradle scripts can prompt for user input using the System.console().readLine method." Unfortunately, Gradle will always request a password, even when you're building a debug release (cf. How to create a release signed apk file using Gradle?). Fortunately, this can be overcome, as I have shown above.

@user2768 2015-11-24 16:16:02

My earlier answer ran into problems due to stackoverflow.com/questions/33897802/…. I have revised my answer to eliminate this problem.

@user2768 2016-05-29 19:07:00

@Haroon, it worked as of 24 Nov '15. The community can perhaps help with your problem, but you'll need to provide more details.

@morpheus 2017-11-03 01:55:52

I like this solution since it avoids putting the password in clear text in a text file but System.console().readLine does not work in gradle due to this annoying issue.

@user2768 2017-11-03 13:44:08

@morpheus, I've never had a problem. The above is working for me.

@morpheus 2017-11-03 18:16:28

I think you run the script from within a IDE. if the script is run from terminal you will see the error. but thanks for this answer. this is what i was looking for.

@user2768 2017-11-07 09:01:59

I'm running the script from the command-line. I'll be using it in the next few days, I'll double-check.

@user2768 2017-11-08 15:22:17

I can confirm that the script is still working for me. I can't see anything obvious that would preclude it from working for you. Perhaps buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0' } }, compileSdkVersion 23, or buildToolsVersion "23.0.2".

@user2768 2017-11-15 11:02:21

@morpheus please let me know whether the above comment helped and I'll edit my answer.

@morpheus 2017-11-15 18:38:01

@user2768 I am surprised that the script works for you. Don't you run into the issue documented here: stackoverflow.com/questions/19487576/…

@user2768 2017-11-16 08:51:54

@morpheus. No, I don't. Possibly because the problematic call System.console().readLine() does not appear.

@davidpetter 2015-07-27 13:54:32

An alternative is to define a task that runs only on release builds.

android {
  ...
  signingConfigs {
     release {
        // We can leave these in environment variables
        storeFile file('nameOfKeystore.keystore')
        keyAlias 'nameOfKeyAlias'

        // These two lines make gradle believe that the signingConfigs
        // section is complete. Without them, tasks like installRelease
        // will not be available!
        storePassword "notYourRealPassword"
        keyPassword "notYourRealPassword"

     }
  }
  buildTypes {
     ...
     release {
        signingConfig signingConfigs.release
        ...
     }
  }
  ...
}

task setupKeystore << {
final Console console = System.console();
if (console != null) {
    //def keyFile = console.readLine(“\nProject: “ + project.name + “Enter keystore path: "))
    //def keyAlias = console.readLine(“Project: “ + project.name + “Enter key alias: ")
        def storePw = new String(console.readPassword(“Project: “ + project.name + “. Enter keystore password: "))
        def keyPw  = new String(console.readPassword(“Project: “ + project.name + “.Enter keystore password: "))

    //android.signingConfigs.release.storeFile = file(keyFile);
    //android.signingConfigs.release.keyAlias = keyAlias
        android.signingConfigs.release.storePassword = storePw
        android.signingConfigs.release.keyPassword = keyPw
}
}

//Validate t
def isReleaseConfig = gradle.startParameter.taskNames.any {it.contains('Release') }
if (isReleaseConfig) {
    setupKeystore.execute();
}

@user2768 2015-11-17 19:03:10

The following seems preferable to me: stackoverflow.com/a/19130098/3664487 How do the two approaches compare?

@ayyb1988 2015-04-07 06:22:37

i am work in Ubuntu14.04. vim ~/.bashrc and add export ANDROID_KEYSTORE= export ANDROID_KEYALIAS=

and then in build.gradle set.

    final Console console = System.console();
if (console != null) {

    // Building from console
    signingConfigs {
        release {
            storeFile file(System.getenv("KEYSTORE"))
            storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
            keyAlias System.getenv("KEY_ALIAS")
            keyPassword new String(System.console().readPassword("\n\$ Enter key password: "))
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}

@Antonio Vinicius Menezes Medei 2018-06-10 19:58:13

IMHO that seems to be the best solution, but unfortunately it stopped working on newer versions of Gradle: System.console() returns null.

@mkjeldsen 2015-01-26 08:05:56

@Destil's answer is good if you can reuse the same configuration across all projects. Alternatively, Android Studio comes with a local.properties file that can maybe be used instead, but it's supposedly IDE-generated and I can't find a way to extend it from within Android Studio.

This is a variation of @jonbo's answer. That answer allows project specific settings but it comes with a bit of developer overhead. Specifically, significant boilerplate is required to move the signingConfigs definition into a separate file -- especially if you need to do so for multiple projects, which is a prime reason for picking this solution over Destil's. This can be somewhat alleviated by also including the line

apply plugin: 'com.android.application'

in the credentials file, as this will allow IDE completion.

Finally, most solutions here do not allow building the project in debug mode -- which handles debug-signing automatically -- without providing a syntactically if not semantically valid signingConfigs definition. If you do not need to produce a release build from a given machine, this extra step can be seen as an unnecessary obstacle. On the other hand, it can be an aid against ignorant or lazy colleagues running debug builds in production.

This solution will allow debug builds without worrying about credentials at all, but it will require valid credentials to produce release builds, and it takes very little boilerplate. However, as a downside it might encourage others to replace dummy values with real credentials and there's no way to protect against that.

// app/build.gradle
// Define this structure in signing.gradle to enable release builds.
ext.signing = [
        storeFilePath : 'path/to/keystore',
        storePassword : 'keystore password',
        keyAlias      : 'key alias',
        keyPassword   : 'key password',
]

if (file('signing.gradle').exists()) {
    apply from: 'signing.gradle'
}

android {
    ...
    signingConfigs {
        release {
            storeFile file(project.signing.storeFilePath)
            storePassword project.signing.storePassword
            keyAlias project.signing.keyAlias
            keyPassword project.signing.keyPassword
        }
    }
    buildTypes {
        debug { ... }
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

This creates a dummy property that serves purely to produce a syntactically valid build file. The values assigned to ext.signing's properties are irrelevant as far as debug builds go. To enable release builds, copy ext.signing into signing.gradle and replace the dummy values with valid credentials.

// signing.gradle
ext.signing = [
        storeFilePath : 'real/keystore',
        storePassword : 'real keystore password',
        keyAlias : 'real key alias',
        keyPassword : 'real key password',
]

Of course, signing.gradle should be ignored by VCS.

@cprcrack 2014-12-28 19:41:04

To complement the other answers, you can also place your gradle.properties file in your own module folder, together with build.gradle, just in case your keystore is specific to one project.

@Gal Bracha 2014-08-19 19:52:44

Like @Destil said but allow others who don't have the key to build: Easier way than previous answers:

Put this into ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Modify your build.gradle like this:

...    
if(project.hasProperty("RELEASE_STORE_FILE")) {
    signingConfigs {    
       release {
           storeFile file(RELEASE_STORE_FILE)
           storePassword RELEASE_STORE_PASSWORD
           keyAlias RELEASE_KEY_ALIAS
           keyPassword RELEASE_KEY_PASSWORD
       }
    }
}

buildTypes {
    if(project.hasProperty("RELEASE_STORE_FILE")) {
        release {
            signingConfig signingConfigs.release
        }
    }
}
....

Then you can run gradle assembleRelease OR gradle build

@argenkiwi 2014-08-19 03:48:26

Yet another approach to the same problem. As it is not recommended to store any kind of credential within the source code, we decided to set the passwords for the key store and key alias in a separate properties file as follows:

key.store.password=[STORE PASSWORD]
key.alias.password=[KEY PASSWORD]

If you use git, you can create a text file called, for example, secure.properties. You should make sure to exclude it from your repository (if using git, adding it to the .gitignore file). Then, you would need to create a signing configuration, like some of the other answers indicate. The only difference is in how you would load the credentials:

android {
    ...
    signingConfigs {
        ...
        release {
            storeFile file('[PATH TO]/your_keystore_file.jks')
            keyAlias "your_key_alias"

            File propsFile = file("[PATH TO]/secure.properties");
            if (propsFile.exists()) {
                Properties props = new Properties();
                props.load(new FileInputStream(propsFile))
                storePassword props.getProperty('key.store.password')
                keyPassword props.getProperty('key.alias.password')
            }
        }
        ...
    }

    buildTypes {
        ...
        release {
            signingConfig signingConfigs.release
            runProguard true
            proguardFile file('proguard-rules.txt')
        }
        ...
    }
}

Never forget to assign the signingConfig to the release build type manually (for some reason I sometimes assume it will be used automatically). Also, it is not mandatory to enable proguard, but it is recommendable.

We like this approach better than using environment variables or requesting user input because it can be done from the IDE, by switching to the realease build type and running the app, rather than having to use the command line.

@cesards 2014-10-21 17:36:44

Gradle doesn't compile using this: props = new Properties(); Cannot set the value of read-only property 'props'

@argenkiwi 2014-10-22 02:44:13

You are right @m3n0R. I edited a line of my response to reflect the fix we had to introduce in our app so it would still compile using the latest versions of Gradle. Basically, props has to be declared as a local variable.

@sirvon 2014-11-09 05:53:48

how would this be adoptable using cloud CI/CD tools....the /path/to/keystore and /path/to/secure.props is throwing me....thanks for this though.

@Andy Shiue 2014-08-05 00:27:20

You can also use -P command line option of gradle to help the signing. In your build.gradle, add singingConfigs like this:

signingConfigs {
   release {
       storeFile file("path/to/your/keystore")
       storePassword RELEASE_STORE_PASSWORD
       keyAlias "your.key.alias"
       keyPassword RELEASE_KEY_PASSWORD
   }
}

Then call gradle build like this:

gradle -PRELEASE_KEYSTORE_PASSWORD=******* -PRELEASE_KEY_PASSWORD=****** build

You can use -P to set storeFile and keyAlias if you prefer.

This is basically Destil's solution but with the command line options.

For more details on gradle properties, check the gradle user guide.

@Vlad 2017-12-06 12:18:58

Thank you. Very helpful

@naufraghi 2014-03-23 22:05:35

Almost all platforms now offer some sort of keyring, so there is no reason to leave clear text passwords around.

I propose a simple solution that uses the Python Keyring module (mainly the companion console script keyring) and a minimal wrapper around Groovy ['do', 'something'].execute() feature:

def execOutput= { args ->
    def proc = args.execute()
    proc.waitFor()
    def stdout = proc.in.text
    return stdout.trim()
}

Using this function, the signingConfigs section becomes:

signingConfigs {
    release {
        storeFile file("android.keystore")
        storePassword execOutput(["keyring", "get", "google-play", storeFile.name])
        keyAlias "com.example.app"
        keyPassword execOutput(["keyring", "get", "google-play", keyAlias])
    }
}

Before running gradle assembleRelease you have to set the passwords in your keyring, only once:

$ keyring set google-play android.keystore # will be prompted for the passwords
$ keyring set google-play com.example.app

Happy releases!

@JP Ventura 2014-03-18 16:18:12

android {
    compileSdkVersion 17
    buildToolsVersion "19.0.3"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 18
    }

    File signFile = rootProject.file('sign/keystore.properties')
    if (signFile.exists()) {
        Properties properties = new Properties()
        properties.load(new FileInputStream(signFile))
        signingConfigs {
            release {
                storeFile rootProject.file(properties['keystore'])
                storePassword properties['storePassword']
                keyAlias properties['keyAlias']
                keyPassword properties['keyPassword']
            }
        }
    }

    buildTypes {
        release {
            runProguard true
            zipAlign true
            proguardFile rootProject.file('proguard-rules.cfg')
            signingConfig signingConfigs.release
        }
        debug {
            runProguard false
            zipAlign true
        }
    }
}

@JP Ventura 2014-03-18 16:24:18

Using Android Studio 0.5.1, Gradle 1.11, and Gradle plugin 0.9.

@JP Ventura 2014-03-25 16:22:13

Creating properties on demand (a.k.a. dynamic properties) has been deprecated and is scheduled to be removed in Gradle 2.0

@jonbo 2014-02-01 05:22:27

(In reply to user672009 above.)

An even easier solution, if you want to keep your passwords out of a git repository; yet, want to include your build.gradle in it, that even works great with product flavors, is to create a separate gradle file. Let's call it 'signing.gradle' (include it in your .gitignore). Just as if it were your build.gradle file minus everything not related to signing in it.

android {
    signingConfigs { 
        flavor1 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
        flavor2 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
    }
}

Then in your build.gradle file include this line right underneath "apply plugin: 'android'"

 apply from: 'signing.gradle'

If you don't have or use multiple flavors, rename "flavor1" to "release" above, and you should be finished. If you are using flavors continue.

Finally link your flavors to its correct signingConfig in your build.gradle file and you should be finished.

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...

@Amio.io 2014-09-06 13:17:00

Can you be a little more specific. I can't make it run: "cannot resolve symbol signingConfig".

@Jaguar 2015-02-19 23:06:38

If I include 'signing.gradle' in the build.gradle - I am forced to have one in git repository (else I get error 'signing.gradle does not exist'). And if I put the 'signing.gradle' in git, it defeats the purpose. How can I make inclusion of signing.gradle optional ?

@Botond Kopacz 2014-01-20 17:42:16

I had several issues that I put the following line in a wrong place:

signingConfigs {
    release {
        // We can leave these in environment variables
        storeFile file("d:\\Fejlesztés\\******.keystore")
        keyAlias "mykey"

        // These two lines make gradle believe that the signingConfigs
        // section is complete. Without them, tasks like installRelease
        // will not be available!
        storePassword "*****"
        keyPassword "******"
    }
}

Make sure that you put the signingConfigs parts inside the android section:

android
{
    ....
    signingConfigs {
        release {
          ...
        }
    }
}

instead of

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

It is easy to make this mistake.

@David Vávra 2014-01-09 12:36:23

Easier way than previous answers:

Put this into ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Modify your build.gradle like this:

...    
signingConfigs {

   release {
       storeFile file(RELEASE_STORE_FILE)
       storePassword RELEASE_STORE_PASSWORD
       keyAlias RELEASE_KEY_ALIAS
       keyPassword RELEASE_KEY_PASSWORD
   }
}

buildTypes {
        release {
            signingConfig signingConfigs.release
        }
}
....

Then you can run gradle assembleRelease

@Frank 2014-01-21 10:01:43

Best method if you ask me. Saves nothing in my project folder/SVN and I can checkout 10 versions of my projects without having to worry about the keys.

@Anachronist 2014-02-06 23:15:16

If you're using gradlew on Windows, you need to be sure GRADLE_USER_HOME is defined as an environment variable to make this work. I set it to one directory above my project directory, and put my keystore there. The path to your keystore in gradle.properties should use forward slashes (/) or double backslashes (\\), not Windows single backslashes. To create a keystore from the Windows command prompt, see stackoverflow.com/questions/3997748/how-can-i-create-a-keyst‌​ore

@Prem 2014-03-19 13:55:28

Is the path relative to where the build.gradle file is located, or relative to the machines root directory?

@ars-longa-vita-brevis 2014-07-14 09:55:26

@Prem, file() always assumes relative paths. Use new File(path) if you want it to be treated as absolute.

@cjayem13 2014-10-15 18:41:29

none of the variables, arguments, etc were recognized. anyone know why?

@John Shelley 2015-03-31 02:27:24

@cjayem13 my guess is your gradle home isn't setup correctly to your PATH

@Lakshman Chilukuri 2015-10-07 13:18:40

This worked for me and the simplest. In the gradle.properties specify storeFile relative to your module build.gradle like so RELEASE_STORE_FILE=../mykeystore. Dont add quotes else gradle mangles the path

@Shervin Gharib 2016-04-23 20:53:27

It's the best approach, working in both Linux and Windows.

@anunixercoder 2017-04-10 02:03:23

Hi, my Jenkins still cannot found this variable, any idea ?

@Arkady 2017-07-03 15:56:42

in case you are using gradle-expiremental, look here stackoverflow.com/questions/32898555/…

@Joshua Pinter 2017-09-06 18:14:31

Why would you put this in your home .gradle directory? Wouldn't that apply these settings to all of your Android projects instead of the specific project? What happens if you have two or more projects with two or more keystores?

@David Vávra 2017-09-08 09:02:09

@JoshuaPinter Yes this applies to all projects, which is helpful in many cases. Lot of people sign many apps with the same certificates. If you have multiple certificates, create a more variants with different prefixes.

@Nouman Ch 2017-09-29 14:07:17

What about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?

@Johan Walles 2017-11-10 21:08:18

@anunixercoder, this won't fly if your CI doesn't have these variables set. The answer from Igor Ganapolsky does though, check it out!

@Ruslan 2019-11-25 21:22:23

Please note that the build.gradle lines showed here are to be put inside the android{} part, not on the top level.

@IgorGanapolsky 2013-10-26 05:01:07

If you want to avoid hardcoding your keystore & password in build.gradle, you can use a properties file as explained here: HANDLING SIGNING CONFIGS WITH GRADLE

Basically:

1) create a myproject.properties file at /home/[username]/.signing with such contents:

keystore=[path to]\release.keystore
keystore.password=*********
keyAlias=***********
keyPassword=********

2) create a gradle.properties file (perhaps at the root of your project directory) with the contents:

MyProject.properties=/home/[username]/.signing/myproject.properties

3) refer to it in your build.gradle like this:

    if(project.hasProperty("MyProject.properties")
        && new File(project.property("MyProject.properties")).exists()) {

    Properties props = new Properties()
    props.load(new FileInputStream(file(project.property("MyProject.properties"))))

    signingConfigs {
        release {
            storeFile file(props['keystore'])
            storePassword props['keystore.password']
            keyAlias props['keyAlias']
            keyPassword props['keyPassword']
        }
    }
}

@theczechsensation 2014-06-23 04:09:27

Works great! Thank you. This code must be added before the buildTypes {} section and the section must declare the signingConfig signingConfigs.release as normal.

@devnull69 2016-05-03 11:13:51

Finally I found a solution for this problem. The only thing that really helped me out! This sould be the accepted answer ...

@jclehner 2013-10-13 21:17:44

Note that @sdqali's script will (at least when using Gradle 1.6) ask for the password anytime you invoke any gradle task. Since you only need it when doing gradle assembleRelease (or similar), you could use the following trick:

android {
    ...
    signingConfigs {
        release {
            // We can leave these in environment variables
            storeFile file(System.getenv("KEYSTORE"))
            keyAlias System.getenv("KEY_ALIAS")

            // These two lines make gradle believe that the signingConfigs
            // section is complete. Without them, tasks like installRelease
            // will not be available!
            storePassword "notYourRealPassword"
            keyPassword "notYourRealPassword"
        }
    }
    ...
}

task askForPasswords << {
    // Must create String because System.readPassword() returns char[]
    // (and assigning that below fails silently)
    def storePw = new String(System.console().readPassword("Keystore password: "))
    def keyPw  = new String(System.console().readPassword("Key password: "))

    android.signingConfigs.release.storePassword = storePw
    android.signingConfigs.release.keyPassword = keyPw
}

tasks.whenTaskAdded { theTask -> 
    if (theTask.name.equals("packageRelease")) {
        theTask.dependsOn "askForPasswords"
    }
}

Note that I also had to add the following (under android) to make it work:

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}

@Kaarel 2013-10-17 18:32:09

After implementing this, installRelease disappeared from the list of tasks... Why?

@jclehner 2013-10-18 19:11:51

I've updated the script; this should fix your problem!

@vizZ 2013-12-02 16:40:17

@caspase Wish I had taken your comment about that fake "storePassword" and "keyPassword" more seriously. Without initialising these properties ("" for example) the signed *-release.apk is not created, no error is displayed and your are left completely puzzled with just the *-release-unsigned.apk in your PROJECT_NAME/build/apk/ directory. Man... :/

@mm2001 2013-12-14 04:28:34

Thanks for the note about adding signingConfig under buildTypes -> Release. That solved automated signing for me!

@Alex Vasilkov 2014-02-28 07:40:53

I made a simple gradle plugin that asks for passwords when building release apk (using mathod described in this post, but you will not need to define fake storePassword & keyPassword). It is also available in maven central. github.com/alexvasilkov/AndroidGradleSignPlugin

@Jerry101 2014-03-31 08:07:35

This is great. Beware that the environment variable KEYSTORE needs to be defined even for debug builds and for "gradle sync" inside Android Studio, otherwise it'll give an error about path being null.

@codebeard 2016-04-23 05:14:24

If running from GUI and System.console() is not available, try something like: def storePw = new Scanner(Runtime.getRuntime().exec("/usr/libexec/openssh/ssh-‌​askpass Keystore Password").getInputStream()).useDelimiter("\\n").next()

@Adrian Adamczyk 2018-06-02 17:26:28

Other solution is def storePw = new Scanner(System.in).nextLine() but the disadvantage is that password is visible on screen.

@Pierre-Luc Paour 2019-06-26 09:54:52

This was my favorite solution until Gradle 5 started ignoring my attempts to override android.signingConfigs.release values. If this solution fails for you, you can try to stay with Gradle 4 until another solution is found.

@AChep 2013-10-06 14:45:44

This is a reply to user672009 and addition to sdqali's post (his code will crash on building debug version by IDE's "Run" button):

You can use the following code:

final Console console = System.console();
if (console != null) {

    // Building from console 
    signingConfigs {
        release {
            storeFile file(console.readLine("Enter keystore path: "))
            storePassword console.readLine("Enter keystore password: ")
            keyAlias console.readLine("Enter alias key: ")
            keyPassword console.readLine("Enter key password: ")
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}

@user672009 2013-10-10 19:03:21

Is there a way to have some default values? My keystore is usually the same. The storePassword usually the same as keyPassword and the keyAlias usually the project name in lower case.

@AChep 2013-10-13 16:42:49

@user672009 you can always use Java code inside of the script.

@Alex Semeniuk 2014-02-11 10:29:57

you might want to use something like this: keyPassword new String(console.readPassword("Enter key password: ")) to make sure your password is not displayed during input

@Jan-Terje Sørensen 2013-08-20 08:00:17

I managed to solve it adding this code, and building with gradle build:

android {
    ...
    signingConfigs {
        release {
            storeFile file("release.keystore")
            storePassword "******"
            keyAlias "******"
            keyPassword "******"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

This generates a signed release apk file.

@user672009 2013-09-18 23:38:18

Is there a way to make it prompt me for the passwords? Or other suggestions to keep passwords out of my git repos?

@Semanticer 2013-10-05 18:21:56

I edit my build.gradle to look like yours but running "Built > Generate signed APK... " still gives my that dialog("See the Gradle User Guide for more info." etc.) and no APK.

@Phillip Kamikaze 2013-10-05 21:50:29

@Semanticer Execute gradle build or gradlew build in Terminal/Prompt command

@Gabriele Mariotti 2013-10-06 17:51:07

@user672009 you can put passwords in a properties file and exclude it from repos with .gitignore. You can see this link.gist.github.com/gabrielemariotti/6856974

@user672009 2013-10-06 19:19:46

@GabrieleMariotti That still leaves an incomplete repository. A better way would be to create a skeleton signing.properties and after committing issuing "git update-index --assume-unchanged signing.properties". However that prevents futura edits from being committed. Something like the first option sdqali suggests seems even better.

@Gabriele Mariotti 2013-10-06 22:40:52

@user672009 You are right. I've improved the script with a check if file exist to prevent incomplete repository.

@user672009 2013-10-06 22:51:42

But in case the file doesn't exists the user is left with a message about a missing file of which he has no idea about how to create. Or am I missing something?

@Gabriele Mariotti 2013-10-07 10:26:55

@user672009 you can add a template file (I see signing.properties.template in many projects in last days). You can also improve the script with an alert with println 'signing.properties not found'. (I updated my gist).

@Jorge 2014-01-11 06:02:17

Does zip alignment (zipalign) occur as well ?

@Brian Knoblauch 2014-12-02 15:33:23

Doesn't work for me. I'm still unable to build signed apk files ("blah.apk is not signed. Please configure..." error message still pops up).

@Nouman Ch 2017-09-29 14:07:08

What about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?

@treesAreEverywhere 2018-08-17 01:11:21

Make sure you have the signingConfigs block ABOVE the buildTypes block in your file.

@ravid rinek 2019-05-19 08:04:36

and then I can just go and 'Build -> Build Bundle/APk -> ...' (instead of 'Generate singed Bundle/APK') for release version ???

Related Questions

Sponsored Content

5 Answered Questions

33 Answered Questions

[SOLVED] How do you install an APK file in the Android emulator?

4 Answered Questions

21 Answered Questions

[SOLVED] Is there a way to get the source code from an APK file?

2 Answered Questions

28 Answered Questions

[SOLVED] "Gradle Version 2.10 is required." Error

2 Answered Questions

Sponsored Content