How to create a release signed apk file using Gradle?

前端 未结 30 1439
既然无缘
既然无缘 2020-11-22 13:48

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

相关标签:
30条回答
  • 2020-11-22 14:10

    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")
                // ...
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 14:12

    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:

    1. Create a password file to be used by Android Studio
    2. Create signature key file
    3. Edit the module build.gradle file to use (1) and (2).

    For this example we name the two files:

    1. keystore.properties
    2. 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!

    0 讨论(0)
  • 2020-11-22 14:13

    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

    0 讨论(0)
  • 2020-11-22 14:13

    @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.

    0 讨论(0)
  • 2020-11-22 14:17

    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

    0 讨论(0)
  • 2020-11-22 14:17

    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();
    }
    
    0 讨论(0)
提交回复
热议问题