How to create a release signed apk file using Grad

2018-12-31 20:56发布

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 gradle 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?

26条回答
谁念西风独自凉
2楼-- · 2018-12-31 21:35

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.

查看更多
明月照影归
3楼-- · 2018-12-31 21:36

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.

查看更多
柔情千种
4楼-- · 2018-12-31 21:36

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();
}
查看更多
低头抚发
5楼-- · 2018-12-31 21:40

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
    }
}
查看更多
泛滥B
6楼-- · 2018-12-31 21:40

(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
      }
  }

  ...
查看更多
路过你的时光
7楼-- · 2018-12-31 21:42

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']
        }
    }
}
查看更多
登录 后发表回答