Sign APK without putting keystore info in build.gradle

后端 未结 12 915
栀梦
栀梦 2020-11-28 17:51

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

相关标签:
12条回答
  • 2020-11-28 18:19

    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.

    0 讨论(0)
  • 2020-11-28 18:19

    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

    0 讨论(0)
  • 2020-11-28 18:19

    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.

    0 讨论(0)
  • 2020-11-28 18:20

    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.

    How to add password in Keychain Access

    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
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 18:24

    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")
        }
    
    0 讨论(0)
  • 2020-11-28 18:25

    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.

    0 讨论(0)
提交回复
热议问题