How to create a release signed apk file using Gradle?
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.
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:
- Create a password file to be used by Android Studio
- Create signature key file
- Edit the module
build.gradle
file to use (1) and (2).
For this example we name the two files:
keystore.properties
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!
Jan-Terje Sørensen
Updated on July 20, 2022Comments
-
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 almost 11 yearsIs there a way to make it prompt me for the passwords? Or other suggestions to keep passwords out of my git repos?
-
Semanticer over 10 yearsI 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 over 10 years@Semanticer Execute
gradle build
orgradlew build
in Terminal/Prompt command -
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 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 over 10 years@user672009 You are right. I've improved the script with a check if file exist to prevent incomplete repository.
-
user672009 over 10 yearsBut 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 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 over 10 yearsIs 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 over 10 years@user672009 you can always use Java code inside of the script.
-
Joshua Ong over 10 yearsAfter implementing this,
installRelease
disappeared from the list of tasks... Why? -
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 over 10 yearsThanks for the note about adding signingConfig under buildTypes -> Release. That solved automated signing for me!
-
Jorge over 10 yearsDoes zip alignment (zipalign) occur as well ?
-
Frank over 10 yearsBest 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 over 10 yearsIf 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-keystore
-
Alex Semeniuk over 10 yearsyou 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 over 10 yearsI 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 over 10 yearsUsing Android Studio 0.5.1, Gradle 1.11, and Gradle plugin 0.9.
-
Prem over 10 yearsIs the path relative to where the build.gradle file is located, or relative to the machines root directory?
-
JP Ventura over 10 yearsCreating properties on demand (a.k.a. dynamic properties) has been deprecated and is scheduled to be removed in Gradle 2.0
-
Jerry101 about 10 yearsThis 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 about 10 yearsWorks 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 almost 10 years@Prem,
file()
always assumes relative paths. Usenew File(path)
if you want it to be treated as absolute. -
Amio.io almost 10 yearsCan you be a little more specific. I can't make it run: "cannot resolve symbol signingConfig".
-
cjayem13 over 9 yearsnone of the variables, arguments, etc were recognized. anyone know why?
-
cesards over 9 yearsGradle doesn't compile using this: props = new Properties(); Cannot set the value of read-only property 'props'
-
argenkiwi over 9 yearsYou 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 over 9 yearshow 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 over 9 yearsDoesn'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 over 9 yearsIf 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 about 9 years@cjayem13 my guess is your gradle home isn't setup correctly to your PATH
-
Raz Tourgman about 9 years+1 for the effort and: 'lintOptions { abortOnError false }'
-
Lakshman Chilukuri over 8 yearsThis 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 over 8 yearsThe following seems preferable to me: stackoverflow.com/a/19130098/3664487 How do the two approaches compare?
-
user2768 over 8 yearsMy earlier answer ran into problems due to stackoverflow.com/questions/33897802/…. I have revised my answer to eliminate this problem.
-
codebeard about 8 yearsIf 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 about 8 yearsIt's the best approach, working in both Linux and Windows.
-
devnull69 about 8 yearsFinally I found a solution for this problem. The only thing that really helped me out! This sould be the accepted answer ...
-
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 about 7 yearsHi, my Jenkins still cannot found this variable, any idea ?
-
Arkady almost 7 yearsin case you are using gradle-expiremental, look here stackoverflow.com/questions/32898555/…
-
JavierSegoviaCordoba almost 7 yearsIs 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 almost 7 yearsWorks like charm. Thank-you this should be the accepted Answer
-
Joshua Pinter almost 7 yearsWhy 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 almost 7 yearsThis hardcodes your passwords into the
build.gradle
file, though, doesn't it? -
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 almost 7 yearsWhat 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 over 6 yearsWhat about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?
-
Nouman Ch over 6 yearsWhat about flags V1 (Jar Signature) and V2 (Full APK Signature)? How turn on it?
-
dskrvk over 6 yearsYou 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 over 6 yearsI 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 over 6 years@morpheus, I've never had a problem. The above is working for me.
-
morpheus over 6 yearsI 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 over 6 yearsI'm running the script from the command-line. I'll be using it in the next few days, I'll double-check.
-
user2768 over 6 yearsI 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
, orbuildToolsVersion "23.0.2"
. -
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 over 6 years@morpheus please let me know whether the above comment helped and I'll edit my answer.
-
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 over 6 years@morpheus. No, I don't. Possibly because the problematic call
System.console().readLine()
does not appear. -
Vlad about 6 yearsWhich is
build.gradle
? Top level? Please add more code -
Egis about 6 yearsTo clarify, this is
app/build.gradle
file I'm talking about. -
Adrian Adamczyk about 6 yearsOther solution is
def storePw = new Scanner(System.in).nextLine()
but the disadvantage is that password is visible on screen. -
Antônio Medeiros about 6 yearsIMHO that seems to be the best solution, but unfortunately it stopped working on newer versions of Gradle:
System.console()
returnsnull
. -
treesAreEverywhere almost 6 yearsMake sure you have the signingConfigs block ABOVE the buildTypes block in your file.
-
not2qubit over 5 yearsAnd 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 about 5 yearsand then I can just go and 'Build -> Build Bundle/APk -> ...' (instead of 'Generate singed Bundle/APK') for release version ???
-
Pierre-Luc Paour about 5 yearsThis 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 over 4 yearsPlease note that the
build.gradle
lines showed here are to be put inside theandroid{}
part, not on the top level. -
Trevor Halvorson over 4 yearsA note on your last update about
keytool
generating a PKCS12 keystore: you can pass-storetype JKS
in thekeytool
command to set the keystore type to JKS which is needed by the Android tooling. -
ofundefined over 4 yearsAs I already have these passwords set on my
android.signingConfigs.relase
on build.gradle, I chose to just addsigningConfig signingConfigs.release
on mybuildTypes.release
-
Roger over 4 years@user672009 this also helps. This works with bundle ? Google playstore request this
-
reza_khalafi about 4 yearsHow to set path in windows: path to your keystore
-
reza_khalafi about 4 yearsstoreFile file("C:\\Users\\xxxx\\Documents\\yyyy\\mykey.jks") is it right?
-
JensV about 4 years@NoumanCh fwiw I amended the answer with the v1/v2 signing configuration
-
SqAR.org about 4 yearsThis doesn't work anymore, see github.com/gradle/gradle/issues/1251
-
Sam almost 4 yearsI 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 almost 3 yearsFor me I had to do ./gradlew assembleRelease instead of using the gradle executable.
-
Bhoomi Zalavadiya over 2 yearsHow to use this in build.gradle file?
-
thouliha over 2 yearsThat if statement is vital unless you want your CI builds to fail.
-
thouliha over 2 yearsThis is very close, but your CI builds will fail unless you add the if statements from this answer: stackoverflow.com/a/25391891/1655478