How to create a release signed apk file using Gradle?

318,764

Solution 1

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 app/build.gradle, and add this inside the android { code block:

...    
signingConfigs {

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

       // Optional, specify signing versions used
       v1SigningEnabled true
       v2SigningEnabled true
   }
}

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

Then you can run gradle assembleRelease


Also see the reference for the signingConfigs Gradle DSL

Solution 2

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.

Solution 3

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

Solution 4

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']
        }
    }
}

Solution 5

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!

Share:
318,764
Jan-Terje Sørensen
Author by

Jan-Terje Sørensen

Updated on July 20, 2022

Comments

  • Jan-Terje Sørensen
    Jan-Terje Sørensen almost 2 years

    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?

  • user672009
    user672009 almost 11 years
    Is there a way to make it prompt me for the passwords? Or other suggestions to keep passwords out of my git repos?
  • Semanticer
    Semanticer over 10 years
    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
    Phillip Kamikaze over 10 years
    @Semanticer Execute gradle build or gradlew build in Terminal/Prompt command
  • Gabriele Mariotti
    Gabriele Mariotti over 10 years
    @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
    user672009 over 10 years
    @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
    Gabriele Mariotti over 10 years
    @user672009 You are right. I've improved the script with a check if file exist to prevent incomplete repository.
  • user672009
    user672009 over 10 years
    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
    Gabriele Mariotti over 10 years
    @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).
  • user672009
    user672009 over 10 years
    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
    AChep over 10 years
    @user672009 you can always use Java code inside of the script.
  • Joshua Ong
    Joshua Ong over 10 years
    After implementing this, installRelease disappeared from the list of tasks... Why?
  • vizZ
    vizZ over 10 years
    @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
    mm2001 over 10 years
    Thanks for the note about adding signingConfig under buildTypes -> Release. That solved automated signing for me!
  • Jorge
    Jorge over 10 years
    Does zip alignment (zipalign) occur as well ?
  • Frank
    Frank over 10 years
    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
    Anachronist over 10 years
    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
  • Alex Semeniuk
    Alex Semeniuk over 10 years
    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
  • Alex Vasilkov
    Alex Vasilkov over 10 years
    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
  • JP Ventura
    JP Ventura over 10 years
    Using Android Studio 0.5.1, Gradle 1.11, and Gradle plugin 0.9.
  • Prem
    Prem over 10 years
    Is the path relative to where the build.gradle file is located, or relative to the machines root directory?
  • JP Ventura
    JP Ventura over 10 years
    Creating properties on demand (a.k.a. dynamic properties) has been deprecated and is scheduled to be removed in Gradle 2.0
  • Jerry101
    Jerry101 about 10 years
    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.
  • theczechsensation
    theczechsensation about 10 years
    Works great! Thank you. This code must be added before the buildTypes {} section and the section must declare the signingConfig signingConfigs.release as normal.
  • ars-longa-vita-brevis
    ars-longa-vita-brevis almost 10 years
    @Prem, file() always assumes relative paths. Use new File(path) if you want it to be treated as absolute.
  • Amio.io
    Amio.io almost 10 years
    Can you be a little more specific. I can't make it run: "cannot resolve symbol signingConfig".
  • cjayem13
    cjayem13 over 9 years
    none of the variables, arguments, etc were recognized. anyone know why?
  • cesards
    cesards over 9 years
    Gradle doesn't compile using this: props = new Properties(); Cannot set the value of read-only property 'props'
  • argenkiwi
    argenkiwi over 9 years
    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
    sirvon over 9 years
    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.
  • user1568901
    user1568901 over 9 years
    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).
  • dev
    dev over 9 years
    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 ?
  • John Shelley
    John Shelley about 9 years
    @cjayem13 my guess is your gradle home isn't setup correctly to your PATH
  • Raz Tourgman
    Raz Tourgman about 9 years
    +1 for the effort and: 'lintOptions { abortOnError false }'
  • Lakshman Chilukuri
    Lakshman Chilukuri over 8 years
    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
  • user2768
    user2768 over 8 years
    The following seems preferable to me: stackoverflow.com/a/19130098/3664487 How do the two approaches compare?
  • user2768
    user2768 over 8 years
    My earlier answer ran into problems due to stackoverflow.com/questions/33897802/…. I have revised my answer to eliminate this problem.
  • codebeard
    codebeard about 8 years
    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()
  • Shervin Gharib
    Shervin Gharib about 8 years
    It's the best approach, working in both Linux and Windows.
  • devnull69
    devnull69 about 8 years
    Finally I found a solution for this problem. The only thing that really helped me out! This sould be the accepted answer ...
  • user2768
    user2768 about 8 years
    @Haroon, it worked as of 24 Nov '15. The community can perhaps help with your problem, but you'll need to provide more details.
  • questionasker
    questionasker about 7 years
    Hi, my Jenkins still cannot found this variable, any idea ?
  • Arkady
    Arkady almost 7 years
    in case you are using gradle-expiremental, look here stackoverflow.com/questions/32898555/…
  • JavierSegoviaCordoba
    JavierSegoviaCordoba almost 7 years
    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
    pratham kesarkar almost 7 years
    Works like charm. Thank-you this should be the accepted Answer
  • Joshua Pinter
    Joshua Pinter almost 7 years
    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?
  • Joshua Pinter
    Joshua Pinter almost 7 years
    This hardcodes your passwords into the build.gradle file, though, doesn't it?
  • David Vávra
    David Vávra almost 7 years
    @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.
  • Diana Farin
    Diana Farin almost 7 years
    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).
  • Nouman Ch
    Nouman Ch over 6 years
    What about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?
  • Nouman Ch
    Nouman Ch over 6 years
    What about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?
  • dskrvk
    dskrvk over 6 years
    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.
  • morpheus
    morpheus over 6 years
    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
    user2768 over 6 years
    @morpheus, I've never had a problem. The above is working for me.
  • morpheus
    morpheus over 6 years
    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
    user2768 over 6 years
    I'm running the script from the command-line. I'll be using it in the next few days, I'll double-check.
  • user2768
    user2768 over 6 years
    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".
  • Johan Walles
    Johan Walles over 6 years
    @anunixercoder, this won't fly if your CI doesn't have these variables set. The answer from Igor Ganapolsky does though, check it out!
  • user2768
    user2768 over 6 years
    @morpheus please let me know whether the above comment helped and I'll edit my answer.
  • morpheus
    morpheus over 6 years
    @user2768 I am surprised that the script works for you. Don't you run into the issue documented here: stackoverflow.com/questions/19487576/…
  • user2768
    user2768 over 6 years
    @morpheus. No, I don't. Possibly because the problematic call System.console().readLine() does not appear.
  • Vlad
    Vlad about 6 years
    Which is build.gradle? Top level? Please add more code
  • Egis
    Egis about 6 years
    To clarify, this is app/build.gradle file I'm talking about.
  • Adrian Adamczyk
    Adrian Adamczyk about 6 years
    Other solution is def storePw = new Scanner(System.in).nextLine() but the disadvantage is that password is visible on screen.
  • Antônio Medeiros
    Antônio Medeiros about 6 years
    IMHO that seems to be the best solution, but unfortunately it stopped working on newer versions of Gradle: System.console() returns null.
  • treesAreEverywhere
    treesAreEverywhere almost 6 years
    Make sure you have the signingConfigs block ABOVE the buildTypes block in your file.
  • not2qubit
    not2qubit over 5 years
    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.
  • ravid rinek
    ravid rinek about 5 years
    and then I can just go and 'Build -> Build Bundle/APk -> ...' (instead of 'Generate singed Bundle/APK') for release version ???
  • Pierre-Luc Paour
    Pierre-Luc Paour about 5 years
    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.
  • Ruslan
    Ruslan over 4 years
    Please note that the build.gradle lines showed here are to be put inside the android{} part, not on the top level.
  • Trevor Halvorson
    Trevor Halvorson over 4 years
    A note on your last update about keytool generating a PKCS12 keystore: you can pass -storetype JKS in the keytool command to set the keystore type to JKS which is needed by the Android tooling.
  • ofundefined
    ofundefined over 4 years
    As I already have these passwords set on my android.signingConfigs.relaseon build.gradle, I chose to just add signingConfig signingConfigs.release on my buildTypes.release
  • Roger
    Roger over 4 years
    @user672009 this also helps. This works with bundle ? Google playstore request this
  • reza_khalafi
    reza_khalafi about 4 years
    How to set path in windows: path to your keystore
  • reza_khalafi
    reza_khalafi about 4 years
    storeFile file("C:\\Users\\xxxx\\Documents\\yyyy\\mykey.jks") is it right?
  • JensV
    JensV about 4 years
    @NoumanCh fwiw I amended the answer with the v1/v2 signing configuration
  • SqAR.org
    SqAR.org about 4 years
    This doesn't work anymore, see github.com/gradle/gradle/issues/1251
  • Sam
    Sam almost 4 years
    I made one change to this, which is to place the keystore.properties file in the same folder as the keystore (.jks) file. This way, I know right from build.gradle, when hitting sync now..., if the path specified for the properties file is correct. In the properties file, then, I don't need to specify the path to the .jks file because both the properties file and keystore file are in the same folder, as mentioned above.
  • Shn
    Shn almost 3 years
    For me I had to do ./gradlew assembleRelease instead of using the gradle executable.
  • Bhoomi Zalavadiya
    Bhoomi Zalavadiya over 2 years
    How to use this in build.gradle file?
  • thouliha
    thouliha over 2 years
    That if statement is vital unless you want your CI builds to fail.
  • thouliha
    thouliha over 2 years
    This is very close, but your CI builds will fail unless you add the if statements from this answer: stackoverflow.com/a/25391891/1655478