How to generate signed app bundle using jenkins? - android

Using jenkins i am able to generate a release app bundle for my app but, I am stuck in the next step which involves generating a signed app bundle for my app so that i can update my build on playstore. So is there a plugin or any other way by which i can generate signed app bundle for my app on jenkins?

This could be done by:
Configuring the Android app's build.gradle file to pick up the signing info from environment variables if they are available.
Configuring the signing key, alias and password(s) as Credentials in the Jenkins job (secret file, secret text...) via the Jenkins UI.
Using the Credentials Binding plugin to set the environment variables from the credentials in the Jenkinsfile, and thus pass them to build.gradle.
Extract from build.gradle:
apply plugin: 'com.android.application'
def myStoreFile = System.getenv('MY_STORE_FILE')
def myStorePassword = System.getenv('MY_STORE_PASSWORD')
def myKeyAlias = System.getenv('MY_KEY_ALIAS')
def myKeyPassword = System.getenv('MY_KEY_PASSWORD')
android {
...
signingConfigs {
release {
if (myStoreFile) {
storeFile rootProject.file(myStoreFile)
storePassword myStorePassword
keyAlias myKeyAlias
keyPassword myKeyPassword
}
}
}
buildTypes {
release {
...
if (myStoreFile && myStorePassword && myKeyAlias && myKeyPassword) {
signingConfig signingConfigs.release
}
}
}
...
}
Extract from Jenkinsfile:
stage ('Build and Sign Android Bundle') {
...
steps {
// Signing parameters are configured in Jenkins (here we use secret file, secret text and username with password respectively)
// and are passed to the build.gradle file using the environment variables (MY_STORE_FILE, MY_KEY_ALIAS etc)
withCredentials([file(credentialsId: 'android-store-file', variable: 'MY_STORE_FILE'),
string(credentialsId: 'android-store-password', variable: 'MY_STORE_PASSWORD'),
usernamePassword(credentialsId: 'android-key', usernameVariable: 'MY_KEY_ALIAS', passwordVariable: 'MY_KEY_PASSWORD')]) {
dir ('android-app-root-directory') {
sh 'gradle clean bundleRelease'
}
}
}
}

Related

what is the exact keystore securefile path used in yaml script for signing the android app bundle in azure devops when key.properties file is added?

I added the signing process in the app gradle file (this process is executed only for release build) instead of using Android signing task in my azure pipeline. I have added a keystore.properties in my project like this and added the my "dev" keystore values as they replaced by my pipeline variables and secure file anyway!
keyPassword=****
keyAlias=****
storeFile=/** jks path **/
And the app build.gradle file contains this signing process for release build variant using my properties file :
// Create a variable called keystorePropertiesFile, and initialize it to your
// keystore.properties file, in the rootProject folder.
def keystorePropertiesFile = rootProject.file("keystore.properties")
// Initialize a new Properties() object called keystoreProperties.
def keystoreProperties = new Properties()
// Load your keystore.properties file into the keystoreProperties object.
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
....
android {
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
compileSdkVersion 30
defaultConfig {
//.....
}
buildTypes {
release {
//+ specify the signing config
signingConfig signingConfigs.release
}
And my pipeline YAML script is:
I added this tasks before Gradle#2, copy files and publish artifact tasks in script,
steps:
#get the keyStore file encoded
- task: DownloadSecureFile#1
name: yourNameHere
displayName: 'Get KeyStore file'
inputs:
secureFile: 'yourKeyStore.keystore'
# rewrite keystore.properties
- script: |
printf 'storePassword=%s\nkeyPassword=%s\nkeyAlias=%s\nstoreFile=%s' $(Store.Password) $(KeyStore.Password) $(KeyStore.KeyAlias) $(yourNameHere.secureFilePath) > keystore.properties
displayName: Generate keystore.properties
But the problem is, I'm getting an error while running the pipeline in azure devops:
A problem occurred evaluating project ':app'.
path may not be null or empty string. path='null'
I think, I mentioned the wrong securefile path in my yaml file. If it is related to azure devops securefile path, please tell me path I have to use, if not what is solution to sign the app bundle without using Android signing task in pipeline and also without adding our keystore file in the repo.**

MirrorLink-aware app validator fails after signing APK with Google developer key

I'm working on MirrorLink-aware Android application and faced issues with Mirrorlink's check of 'application ID' after signing APK with Google developer key.
I have created empty project generated with Mirrorlink plugin for Android studio, which created Gradle task allowing to generate .crt file with Mirrorlink-related configuration info. I just copied this script to my own build.gradle file in the main app module. But Mirrorlink-aware application validator show error for signed APK (standard app signing for publishing to Google Play), while find no problems if APK is unsigned.
How to find out the issue arisen after the app was signed?
What I tried:
1) Align Gradle script with example app provided by Mirrorlink - no luck.
2) Inserting v1SigningEnabled false and v2SigningEnabled false - no luck.
3) Gradle outputs for signed- and unsigned APKs are the same, except of output file name and > Task :app:validateSigningRelease task.
AndroidManifest.xml Mirrorlink-related snipped:
<uses-permission android:name="com.mirrorlink.android.service.ACCESS_PERMISSION"/>
<intent-filter>
<action android:name="com.mirrorlink.android.app.LAUNCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.mirrorlink.android.app.TERMINATE"/>
<category android:name="android.intent.category.DEFAULT"/>
App module's build.gradle:
def generateSelfSignedCertificate(version){
def buildType = version == "release" ? "assembleRelease": "assembleDebug"
def rerunAssemble = true
def projectLocation = projectDir.toString()
def certGeneratorLocation = "certificategenerator-android-studio.jar"
def certXmlLocation = projectLocation + "/certificate.xml"
def certificateDestination = projectLocation + "/src/main/assets/self-signed.ccc.crt"
def certificateFolder = projectLocation + "/src/main/assets/"
def certificateIssuer = "CN=SELF-SIGNED"
def developerId = ""
def apkLocation = ""
android.applicationVariants.all { variant ->
if ((variant.name).equals(version)) {
variant.outputs.each { output ->
//noinspection GrReassignedInClosureLocalVar
apkLocation = output.outputFile
}
}
}
if (project.hasProperty("isLast")) {
rerunAssemble = !isLast
}
if (rerunAssemble) {
def subdir = new File(certificateFolder)
if( !subdir.exists() ) {
subdir.mkdirs()
}
exec {
executable 'java'
args "-jar", certGeneratorLocation, "generate-certificate", apkLocation,
android.defaultConfig.applicationId, android.defaultConfig.versionCode,
certXmlLocation, certificateDestination, certificateIssuer, developerId
println(args)
}
if (System.properties['os.name'].toLowerCase().contains("windows")) {
exec {
executable "cmd"
workingDir projectLocation
args "/c", "..\\gradlew.bat", buildType, "-PisLast=true"
}
} else {
exec {
executable "bash"
workingDir projectLocation
args "../gradlew", buildType, "-PisLast=true"
}
}
}
}
android {
.....
signingConfigs {
storeFile = 'sign.keyStorePath')
keyAlias = 'sign.keyAlias'
storePassword = 'sign.storePassword'
keyPassword = 'sign.keyPassword'
}
}
afterEvaluate {
if (this.hasProperty("assembleRelease")){
assembleRelease.finalizedBy generateSelfSignedCertificateForRelase
}
}
task generateSelfSignedCertificateForRelase {
doLast {
generateSelfSignedCertificate("release")
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}
....
}
Running "assesbleRelease" runs with no problems - it produces .crt file with Mirrorlink application ID. But if I put this file in "Mirrorlink-aware application validator" - it shows error report, as follows:
Checking com.mirrorlink.android.app.LAUNCH intent - OK
Checking com.mirrorlink.android.app.TERMINATE intent - OK
Checking com.mirrorlink.android.service.ACCESS_PERMISSION permission - OK
Checking DEVELOPER entity - INCONCLUSIVE. DEVELOPER entity not found
Checking if developer certificate exists for serverID="" - INCONCLUSIVE. DEVELOPER entity not found
Checking application id - FAIL. Calculated application ID doesn't mach id provided in self signed certificate
Checking self signed certificate - OK
The APK is not configured correctly.
BUT if I remove the string signingConfig signingConfigs.release the validator finds no problems:
Checking com.mirrorlink.android.app.LAUNCH intent - OK
Checking com.mirrorlink.android.app.TERMINATE intent - OK
Checking com.mirrorlink.android.service.ACCESS_PERMISSION permission - OK
Checking DEVELOPER entity - INCONCLUSIVE. DEVELOPER entity not found
Checking if developer certificate exists for serverID="" - INCONCLUSIVE. DEVELOPER entity not found
Checking application id - OK
Checking self signed certificate - OK
The APK is correctly configured as a MirrorLink Aware application.
Well, guys, I found the issue :)
I have Crashlytics in the project, and it creates file crashlytics-build.properties that is slightly changed on every build.
And yeah, this file is counted by Mirrorlink's tool certificategenerator-android-studio.jar that generates appID with certificate. I have done some reverse-engineering and checked what is happening inside of this tool: it only skips assets/self-signed.ccc.crt file and META-INF/ content.
So, I had slightly different APKs on EVERY assemble... Disabling Crashlytics plugin solves the issue.
You can either disable Crashlytics plugin (bad idea), or use ext.alwaysUpdateBuildId = false param to skip creating unique build ID. Read more here.

How is possible build apk in terminal with different SIGN credentials

I have build.gradle that can have signingConfigs, but I want TO ignore this setting and use other credentials. I don't want to edit or replace values in build.gradle.
Does gradle have same command like gradle assemble -storeFile='PATH' -storePassword='password' -keyAlias='alias' -keyPassword='password'?
If it's no way create signed apk with other signingConfigs, is it possible to create unsigned apk?
There is no gradle build command which takes sign configs.
You have two options based on the requirement you mentioned in your question.
1.Edit the build.gradle to create multiple build flavors and provide different signing details for each build flavor.
android {
signingConfigs {
abc {
keyAlias 'abc'
keyPassword 'yyy'
storeFile file('keystore/astro.keystore')
storePassword 'zzz'
}
xyz {
keyAlias 'xxx'
keyPassword 'xxx'
storeFile file('keystore/sample.keystore')
storePassword 'xxx'
}
//add another block for new customer
}}
Create multiple copies of keystore properties file with different signing config and when you want to use one particular copy of keystore.properties file, rename it to "keystore.properties".
def keystorePropertiesFile = rootProject.file("keystore.properties")
https://developer.android.com/studio/publish/app-signing#secure-shared-keystore
I suggest you using the solution reported by #Ranjan. It is the cleaner and a standard solution.
However if you would like to use the command line command, all properties passed to gradle in the command line via -P parameter are accessible in the project variable in your gradle script.
You can do something like that:
gradle assembleRelease -PmyKeyPassword='xxx' -PmyStorePassword='xxx' -PmyKeyAlias='xxx' -PmyStoreFile='...xxx.keystore'
and then define in your build.gradle.
signingConfigs {
release {
storeFile project.mystoreFile
storePassword project.myStorePassword
keyAlias project.myKeyAlias
keyPassword project.myKeyPassword
}
}
Pay attention because it can cause errors if you don't specify the keys in the gradle command (not so good in my point of view).
You can mitigate the issue doing a check on the parameter (using the project.hasProperty(xxx) method) and defining the default value in the build.gradle.
Something like that:
signingConfigs {
release {
storeFile project.hasProperty('myStoreFile') ? project.myStoreFile : 'default'
//..
}
}

Store android sign certificate in version control

I've been playing for a while with android. Now that I have my application and been able to generate my signed release (testing purposes) I came with the question that I bring to you: Should I save this certificate in my repo?
Usually I prefer not to include any sensitive information in them, but when I was about to commit changes, I see that AndroidStudio modified build.graddle with storeFile and storePassword in it (I stored my certificate at /home/user as wasn't expecting any of this)
I'll love to hear your thoughts
what i do is.. i separate the app gradle into 3 part.
build.gradle --> main gradle
import this 3 gradle into build.gradle
dependencies.gradle --> for list of dependencies
signing.gradle --> for app signing keystore
function.gradle --> for method call
in signing.gradle only contains like this
def alias = project.findProperty('APP_KEY_ALIAS') ?: EHALAL_KEY_ALIAS
def key_password = project.findProperty('APP_KEY_PASSWORD') ?: EHALAL_KEY_PASSWORD
def store_password = project.findProperty('APP_STORE_PASSWORD') ?: EHALAL_STORE_PASSWORD
def store_file = project.findProperty('APP_KEY_STORE_FILE') ?: EHALAL_KEY_STORE_FILE
if (alias && key_password && store_password && file(store_file).exists()) {
android {
signingConfigs {
release {
keyAlias alias
keyPassword key_password
storeFile file(store_file)
storePassword store_password
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
}
with this, i can exclude only the signing gradle part in .gitignore, not the whole build.gradle part.
im suggesting you that you need to move all sensitive key into gradle.properties because its only in your local. refer here
You’d better not add the certificate in version control.
You can use .gitignore to ignore the file (build.graddle) if they are in git repository directory since the certificate is sensitive data.
And if you committed the file in version control before, you should remove the file from verson control by git rm build.graddle --cached.

How to create a release signed apk file using Gradle?

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 build.gradle/build.gradle.kts 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?
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
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.
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
}
}
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']
}
}
}
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!
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
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
(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
}
}
...
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 {
}
}
}
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"
In newer Android Studio, there is a GUI way which is very easy and it populates Gradle file as well.
File -> Project Structure
Module -> Choose the main module ('app' or other custom name)
Signing tab -> Plus image to add new configuration
Fill data on the right side
OK and Gradle file is automatically created
You will manually have to add a line signingConfig signingConfigs.NameOfYourConfig inside builtTypes{release{}}
Images:
Two important(!) notes:
(EDIT 12/15)
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
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.
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
}
}
}
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.
For Kotlin Script (build.gradle.kts)
You should not put your signing credentials directly in the build.gradle.kts file. Instead the credentials should come from a file not under version control.
Put a file signing.properties where the module specific build.gradle.kts is found. Don't forget to add it to your .gitignore file!
signing.properties
storeFilePath=/home/willi/example.keystore
storePassword=secret
keyPassword=secret
keyAlias=myReleaseSigningKey
build.gradle.kts
android {
// ...
signingConfigs {
create("release") {
val properties = Properties().apply {
load(File("signing.properties").reader())
}
storeFile = File(properties.getProperty("storeFilePath"))
storePassword = properties.getProperty("storePassword")
keyPassword = properties.getProperty("keyPassword")
keyAlias = "release"
}
}
buildTypes {
getByName("release") {
signingConfig = signingConfigs.getByName("release")
// ...
}
}
}
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!
#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.
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
}
}
}
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.
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
For Groovy (build.gradle)
You should not put your signing credentials directly in the build.gradle file. Instead the credentials should come from a file not under version control.
Put a file signing.properties where the module specific build.gradle is found. Don't forget to add it to your .gitignore file!
signing.properties
storeFilePath=/home/willi/example.keystore
storePassword=secret
keyPassword=secret
keyAlias=myReleaseSigningKey
build.gradle
android {
// ...
signingConfigs{
release {
def props = new Properties()
def fileInputStream = new FileInputStream(file('../signing.properties'))
props.load(fileInputStream)
fileInputStream.close()
storeFile = file(props['storeFilePath'])
storePassword = props['storePassword']
keyAlias = props['keyAlias']
keyPassword = props['keyPassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
// ...
}
}
}
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.
Android Studio
Go to File -> Project Structure or press Ctrl+Alt+Shift+S
See The Image
Click Ok
Then the signingConfigs will generate on your build.gradle file.
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.
This is another answer for Kotlin build scripts (build.gradle.kts) different from Willi Mentzel's answer.
It tries to read from local.properties file, falling back to the OS environment variables. It can be especially useful in CIs like GitHub Actions (you can create environment secrets in your repository settings).
Note that I'm using Kotlin 1.6.10 and Gradle 7.4.2 and Android Gradle Plugin (AGP) 7.0.4.
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
// ...
val environment = System.getenv()
fun getLocalProperty(key: String) = gradleLocalProperties(rootDir).getProperty(key)
fun String.toFile() = File(this)
android {
signingConfigs {
create("MySigningConfig") {
keyAlias = getLocalProperty("signing.keyAlias") ?: environment["SIGNING_KEY_ALIAS"] ?: error("Error!")
storeFile = (getLocalProperty("signing.storeFile") ?: environment["SIGNING_STORE_FILE"] ?: error("Error!")).toFile()
keyPassword = getLocalProperty("signing.keyPassword") ?: environment["SIGNING_KEY_PASSWORD"] ?: error("Error!")
storePassword = getLocalProperty("signing.storePassword") ?: environment["SIGNING_STORE_PASSWORD"] ?: error("Error!")
enableV1Signing = true
enableV2Signing = true
}
}
buildTypes {
release {
signingConfig = signingConfigs["MySigningConfig"]
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
As said, you can either have a local.properties file at the root of your project with values for the properties:
signing.keyAlias=My key
signing.keyPassword=zyxwvuts
signing.storePassword=abcdefgh
signing.storeFile=C\:\\Users\\Mahozad\\keystore.jks
... or you can set/create environment variables on your OS; for example to create an environment variable called SIGNING_KEY_ALIAS run:
Windows Command Prompt: setx SIGNING_KEY_ALIAS "My key"
Linux Terminal: export SIGNING_KEY_ALIAS="My key"
NOTE: As mentioned by other answers, do NOT add your local.properties file to your version control system (like Git), as it exposes your secret information like passwords etc. to the public (if it's a public repository).
Generate your APK with either of the 3 ways that this answer mentioned.
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.
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 {
}
}
}
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();
}
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.
Adding my way to do it in React-Native using react-native-config package.
Create a .env file:
RELEASE_STORE_PASSWORD=[YOUR_PASSWORD]
RELEASE_KEY_PASSWORD=[YOUR_PASSWORD]
note this should not be part of the version control.
in your build.gradle:
signingConfigs {
debug {
...
}
release {
storeFile file(RELEASE_STORE_FILE)
storePassword project.env.get('RELEASE_STORE_PASSWORD')
keyAlias RELEASE_KEY_ALIAS
keyPassword project.env.get('RELEASE_KEY_PASSWORD')
}
}
In my case, I was uploading the wrong apk, to another app's release.

Categories

Resources