I am trying to setup signing process so that keystore password and key password are not stored in the project\'s build.gradle
file.
Cur
This question has received many valid answers, but I wanted to share my code which may be useful for library maintainers, because it leaves the original build.gradle
quite clean.
I add a folder to the module directory which I gitignore
. It looks like this:
/signing
/keystore.jks
/signing.gradle
/signing.properties
keystore.jks
and signing.properties
should be self explanatory. And signing.gradle
looks like this:
def propsFile = file('signing/signing.properties')
def buildType = "release"
if (!propsFile.exists()) throw new IllegalStateException("signing/signing.properties file missing")
def props = new Properties()
props.load(new FileInputStream(propsFile))
def keystoreFile = file("signing/keystore.jks")
if (!keystoreFile.exists()) throw new IllegalStateException("signing/keystore.jks file missing")
android.signingConfigs.create(buildType, {
storeFile = keystoreFile
storePassword = props['storePassword']
keyAlias = props['keyAlias']
keyPassword = props['keyPassword']
})
android.buildTypes[buildType].signingConfig = android.signingConfigs[buildType]
And the original build.gradle
apply plugin: 'com.android.application'
if (project.file('signing/signing.gradle').exists()) {
apply from: 'signing/signing.gradle'
}
android {
compileSdkVersion 27
defaultConfig {
applicationId ...
}
}
dependencies {
implementation ...
}
As you can see, you don't have to specify the buildTypes at all, if user has access to a valid signing
directory, he just puts it in the module and he can build a valid signed release application, otherwise it just works for him like it would normally do.
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
}
...
}
...
This answer previously appeared: https://stackoverflow.com/a/33765572/3664487
My password contained a special character which dollar sign $ and I had to escape that in gradle.properties file. After that, signing worked for me.
After reading a few links:
http://blog.macromates.com/2006/keychain-access-from-shell/ http://www.thoughtworks.com/es/insights/blog/signing-open-source-android-apps-without-disclosing-passwords
Since you are using Mac OSX, you can use the Keychain Access to store your passwords.
Then in your gradle scripts:
/* Get password from Mac OSX Keychain */
def getPassword(String currentUser, String keyChain) {
def stdout = new ByteArrayOutputStream()
def stderr = new ByteArrayOutputStream()
exec {
commandLine 'security', '-q', 'find-generic-password', '-a', currentUser, '-gl', keyChain
standardOutput = stdout
errorOutput = stderr
ignoreExitValue true
}
//noinspection GroovyAssignabilityCheck
(stderr.toString().trim() =~ /password: '(.*)'/)[0][1]
}
Use like this:
getPassword(currentUser, "Android_Store_Password")
/* Plugins */
apply plugin: 'com.android.application'
/* Variables */
ext.currentUser = System.getenv("USER")
ext.userHome = System.getProperty("user.home")
ext.keystorePath = 'KEY_STORE_PATH'
/* Signing Configs */
android {
signingConfigs {
release {
storeFile file(userHome + keystorePath + project.name)
storePassword getPassword(currentUser, "ANDROID_STORE_PASSWORD")
keyAlias 'jaredburrows'
keyPassword getPassword(currentUser, "ANDROID_KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
This is how I do it. Use Environment Variables
signingConfigs {
release {
storeFile file(System.getenv("KEYSTORE"))
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
For the ones looking to put their credentials in an external JSON file and read that from the gradle this is what I did:
my_project/credentials.json:
{
"android": {
"storeFile": "/path/to/acuity.jks",
"storePassword": "your_store_password",
"keyAlias": "your_android_alias",
"keyPassword": "your_key_password"
}
}
my_project/android/app/build.gradle
// ...
signingConfigs {
release {
def credsFilePath = file("../../credentials.json").toString()
def credsFile = new File(credsFilePath, "").getText('UTF-8')
def json = new groovy.json.JsonSlurper().parseText(credsFile)
storeFile file(json.android.storeFile)
storePassword = json.android.storePassword
keyAlias = json.android.keyAlias
keyPassword = json.android.keyPassword
}
...
buildTypes {
release {
signingConfig signingConfigs.release //I added this
// ...
}
}
}
// ...
}
The reason I chose a .json
file type, and not a .properties
file type (as in the accepted answer), is because I wanted to also store other data (other custom properties I needed) to that same file (my_project/credentials.json
), and still have gradle parse the signing information from within that file as well.