gradle set absolute path value for a keystore file

I'd like to save my keystore outside the project directory. I don't want to store filepaths inside the repository so I delegated the values to appropriate gradle variables in ~/.gradle/gradle.properties I can't get gradle to accept an absolute path like: /Users/username/.gradle/keystores/project/release.key or ~/.gradle/keystores/project/release.key

I tried: storeFile file(RELEASE_STORE_FILE) and storeFile new File(RELEASE_STORE_FILE)

none of them seems to work, however.

How can I pass an absolute path value to the keystore file through RELEASE_STORE_FILE variable?

android {
    signingConfigs {
        release {
            storeFile file(RELEASE_STORE_FILE)
            storePassword RELEASE_STORE_PASS
            keyAlias RELEASE_ALIAS
            keyPassword RELEASE_KEY_PASS
        }
    }
}

and the ~/.gradle/gradle.properties file:

RELEASE_STORE_FILE=/Users/username/.gradle/keystores/project/release.key
RELEASE_STORE_PASS=******
RELEASE_ALIAS=******
RELEASE_KEY_PASS=******

In short: I want to pass an absolute path value to gradle.

Upvotes: 11

Views: 14204

Answers (6)

JanH
JanH

Reputation: 21

By chance I ended up implementing something similar to Mikhail Avdeev's answer, but in order to provide an example for Kotlin based buildscripts, too, here's my solution anyway:

Add id("com.sidneysimmons.gradle-plugin-external-properties") version "2.0.1" apply false to your project-level build.gradle.kts (plugin source here)

For your module-level build.gradle.kts, use this:

import com.android.build.api.dsl.ApkSigningConfig

plugins {
    // [... all your other plugins]
    id("com.sidneysimmons.gradle-plugin-external-properties")
}

externalProperties {
    propertiesFileResolver(file("signing.properties"))
}

android {
    signingConfigs {
        named("debug") {
            if (checkExternalSigningConfig()) {
                applyExternalSigningConfig()
            } else {
                // Use the default debug keystore if no configuration has been specified
                defaultConfig.signingConfig
            }
        }
        create("release") {
            if (checkExternalSigningConfig()) {
                applyExternalSigningConfig()
                // automatically add the signingConfig to your
                // build config if the configuration file is valid
                android.buildTypes.getByName("release").signingConfig = this
            }
        }
    }
}

fun ApkSigningConfig.checkExternalSigningConfig(): Boolean {
    return props.exists("$name.keyStore") &&
            file(props.get("$name.keyStore")).exists() &&
            props.exists("$name.storePassword") &&
            props.exists("$name.keyAlias") &&
            props.exists("$name.keyPassword")
}

fun ApkSigningConfig.applyExternalSigningConfig() {
    storeFile = file(props.get("$name.keyStore"))
    storePassword = props.get("$name.storePassword")
    keyAlias = props.get("$name.keyAlias")
    keyPassword = props.get("$name.keyPassword")
}

Place a file called signing.properties in your module directory (app or whatever), where you can happily use absolute paths (Windows example in this case):

debug.keyStore=\\C:\\Path\\to\\keystore\\file
debug.storePassword=your_password
debug.keyAlias=your_keyAlias
debug.keyPassword=your_password

release.keyStore=\\C:\\Path\\to\\keystore\\file
release.storePassword=your_password
release.keyAlias=your_keyAlias
release.keyPassword=your_password

Upvotes: 0

Martin Lockett
Martin Lockett

Reputation: 2599

I use this on a Mac

signingConfigs {
    debug {
        storeFile file(System.env.HOME + '/.android/debug.keystore')
        storePassword 'android'
        keyAlias 'androiddebugkey'
        keyPassword 'android'
    }
}

Upvotes: 1

FIL
FIL

Reputation: 1218

In my case (macOS) with my local_store.keystore saved in Users/<username> and the path to the keystore configured in the gradle.properties file as:

RELEASE_STORE_FILE=Users/<username>/local_store.keystore

I was getting the following error:

> Keystore file 
'/Users/<username>/Documents/MyProject/android/app/Users/<username>/local_store.keystore' 
not found for signing config 'release'.

so the path set in the gradle.properties was added to the relative path of the build.gradle file (notice duplicated /Users/<username>).

I fixed that by specifying the path to the keystore with a few ../ to point to the right location in the Users/<username> folder.

This is how it should look in the gradle.properties file:

RELEASE_STORE_FILE=../../../../../local_store.keystore

No modifications are required to the build.gradle file.

Upvotes: 1

Mikhail Avdeev
Mikhail Avdeev

Reputation: 41

Found solution there: https://gist.github.com/gabrielemariotti/6856974

Briefly, you should parse file that contains path to keystore properly. Modify yours module's gradle with next lines. First, this is how to create signingConfigs based on keystore.properties file content:

signingConfigs
    {
        release
        {
            def Properties props = new Properties()
            def propFile = new File('path/to/your/keystore.properties') //absolute path to keystore.properties
            if (propFile.canRead())
            {
                props.load(new FileInputStream(propFile))

            if (props != null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
                    props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD'))
            {
                android.signingConfigs.release.storeFile = file(props['STORE_FILE']) 
                android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
                android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
                android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
            }
            else
            {
                println 'keystore.properties found but some entries are missing'
                android.buildTypes.release.signingConfig = null
            }
        }
        else
        {
            println 'keystore.properties not found'
            android.buildTypes.release.signingConfig = null
        }
    }
}

And then add signingConfig to yours release buildType:

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

Example of keystore.properties file for this solution:

STORE_FILE=absolute//path//to//store
STORE_PASSWORD=yourPass
KEY_PASSWORD=keysPass
KEY_ALIAS=aliasName

This has worked for me (Android Studio 3.0.1, Gradle 4.1, Windows 10).

Upvotes: 4

amit
amit

Reputation: 1413

I got around this by using a symlink

  1. Create symlink keystore.lnk in the app module

    ln -s [path-to-keystore] keystore.lnk

  2. Then use keystore.lnk in gradle.properties

    RELEASE_STORE_FILE=keystore.lnk (don't use quotes)

Now your gradle instructions will work.

Upvotes: 3

I ended up using an interesting solution from this site.

The idea is to keep variables in a separate folder which is stored on a remote repository.

In ~/.gradle/gradle.properties file you put:

Keys.repo=/Users/username/.signing

where Keys.repo is the local path to your remote repository.

Later on in /Users/username/.signing/YourProjectName.properties you have:

RELEASE_STORE_FILE=/YourProjectName/release.keystore //in fact it's a relative path
RELEASE_STORE_PASS=xxxxx
RELEASE_ALIAS=xxxxx
RELEASE_KEY_PASS=xxxxx

You need to store release.keystore file in /Users/username/.signing/YourProjectName/release.keystore path

The configuration is used in the following way:

android {
    signingConfigs {
        debug { /* no changes - usual config style */ }
        release {
            if (project.hasProperty("Keys.repo")) {
                def projectPropsFile = file(project.property("Keys.repo") + "/YourProjectName.properties")
                if (projectPropsFile.exists()) {
                    Properties props = new Properties()
                    props.load(new FileInputStream(projectPropsFile))

                    storeFile file(file(project.property("Keys.repo") + props['RELEASE_STORE_FILE']))
                    storePassword props['RELEASE_STORE_PASS']
                    keyAlias props['RELEASE_ALIAS']
                    keyPassword props['RELEASE_KEY_PASS']
                }
            } else {
                println "======================================================="
                println "[ERROR] - Please configure release-compilation environment - e.g. in ~/.signing  directory"
                println "======================================================="
            }
        }
    }
}

Upvotes: 3

Related Questions