Android 签署 APK 而不将密钥库信息放入 build.gradle
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20562189/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sign APK without putting keystore info in build.gradle
提问by Bobrovsky
I am trying to setup signing process so that keystore password and key password are notstored in the project's build.gradle
file.
我正在尝试设置签名过程,以便密钥库密码和密钥密码不存储在项目build.gradle
文件中。
Currently I have the following in the build.gradle
:
目前我有以下内容build.gradle
:
android {
...
signingConfigs {
release {
storeFile file("my.keystore")
storePassword "store_password"
keyAlias "my_key_alias"
keyPassword "key_password"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
It works perfectly fine but I must notput the values for the storePassword
, and keyPassword
in my repository. I would prefer to not put storeFile
and keyAlias
there either.
它工作得很好,但我不能将storePassword
, 和的值keyPassword
放在我的存储库中。我也不想把storeFile
和放在keyAlias
那里。
Is there a way to alter the build.gradle
so that it will obtain passwords from some external source (like a file that resides on my computer only)?
有没有办法改变build.gradle
它,以便它从某些外部来源(例如仅驻留在我的计算机上的文件)获取密码?
And of course, the altered build.gradle
should be usable on any other computer (even if the computer doesn't have access to passwords).
当然,更改后的内容build.gradle
应该可以在任何其他计算机上使用(即使该计算机无法访问密码)。
I am using Android Studio and in Mac OS X Maverics if it does matter.
如果确实重要,我正在使用 Android Studio 和 Mac OS X Maverics。
采纳答案by Scott Barta
The nice thing about Groovy is that you can freely mix Java code, and it's pretty easy to read in a key/value file using java.util.Properties
. Perhaps there's an even easier way using idiomatic Groovy, but Java is still pretty simple.
Groovy 的好处在于您可以自由混合 Java 代码,并且使用java.util.Properties
. 也许使用惯用的 Groovy 有更简单的方法,但 Java 仍然非常简单。
Create a keystore.properties
file (in this example, in the root directory of your project next to settings.gradle
, though you can put it wherever you like:
创建一个keystore.properties
文件(在此示例中,在项目的根目录中 旁边settings.gradle
,但您可以将其放在任何您喜欢的位置:
storePassword=...
keyPassword=...
keyAlias=...
storeFile=...
Add this to your build.gradle
:
将此添加到您的build.gradle
:
allprojects {
afterEvaluate { project ->
def propsFile = rootProject.file('keystore.properties')
def configName = 'release'
if (propsFile.exists() && android.signingConfigs.hasProperty(configName)) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
android.signingConfigs[configName].storeFile = file(props['storeFile'])
android.signingConfigs[configName].storePassword = props['storePassword']
android.signingConfigs[configName].keyAlias = props['keyAlias']
android.signingConfigs[configName].keyPassword = props['keyPassword']
}
}
}
回答by CurlyCorvus
Alternatively, if you want to apply Scott Barta's answer in a way more similar to the auto generated gradle code, you can create a keystore.properties
file in your project root folder:
或者,如果您想以更类似于自动生成的 gradle 代码的方式应用 Scott Barta 的答案,您可以keystore.properties
在项目根文件夹中创建一个文件:
storePassword=my.keystore
keyPassword=key_password
keyAlias=my_key_alias
storeFile=store_file
and modify your gradle code to:
并将您的gradle代码修改为:
// Load keystore
def keystorePropertiesFile = rootProject.file("keystore.properties");
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
...
android{
...
signingConfigs {
release {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
...
}
You can store this properties file in the root of your module, in which case just omit rootProject
, and you can also modify this code to have several sets of properties for different keystores and key aliases.
您可以将此属性文件存储在模块的根目录中,在这种情况下只需省略rootProject
,您还可以修改此代码以针对不同的密钥库和密钥别名设置多组属性。
回答by Dan Fabulich
The easiest way is to create a ~/.gradle/gradle.properties
file.
最简单的方法是创建一个~/.gradle/gradle.properties
文件。
ANDROID_STORE_PASSWORD=hunter2
ANDROID_KEY_PASSWORD=hunter2
Then your build.gradle
file can look like this:
然后你的build.gradle
文件看起来像这样:
android {
signingConfigs {
release {
storeFile file('yourfile.keystore')
storePassword ANDROID_STORE_PASSWORD
keyAlias 'youralias'
keyPassword ANDROID_KEY_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
回答by Jared Burrows
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
http://blog.macromates.com/2006/keychain-access-from-shell/ http://www.thoughtworks.com/es/insights/blog/signing-open-source-android-apps-without-disclosure-密码
Since you are using Mac OSX, you can use the Keychain Access to store your passwords.
由于您使用的是 Mac OSX,您可以使用 Keychain Access 来存储您的密码。
Then in your gradle scripts:
然后在你的 gradle 脚本中:
/* 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")
getPassword(当前用户,“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
}
}
}
回答by Madhur Ahuja
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")
}
回答by Wayne Piekarski
It is possible to take any existing Android Studio gradle project and build/sign it from the command line without editing any files. This makes it very nice for storing your project in version control while keeping your keys and passwords separate and not in your build.gradle file:
可以使用任何现有的 Android Studio gradle 项目并从命令行构建/签署它,而无需编辑任何文件。这使得将您的项目存储在版本控制中非常好,同时将您的密钥和密码分开而不是在您的 build.gradle 文件中:
./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
回答by ??? ???? ????
The accepted answer use a file to controls which keystore to use to sign the APK that resides in the same root folder of project. When we using vcslike Git, could be a bad thing when we forget to add the properties file to ignore list. Because we will disclose our password to the world. The problems still persist.
接受的答案使用一个文件来控制使用哪个密钥库来签署驻留在项目的同一根文件夹中的 APK。当我们使用像Git这样的vcs时,当我们忘记将属性文件添加到忽略列表时可能是一件坏事。因为我们会向全世界公开我们的密码。问题仍然存在。
Instead making properties file in the same directory within our project, we should make it outside. We make it outside by using gradle.properties file.
而不是在我们的项目中的同一目录中制作属性文件,我们应该把它放在外面。我们通过使用 gradle.properties 文件将其放在外面。
Here the steps:
这里的步骤:
1.Edit or create gradle.properties on your root project and add the following code, remember to edit the path with your own:
1.在你的根项目上编辑或创建gradle.properties并添加如下代码,记得用自己的路径编辑:
AndroidProject.signing=/your/path/androidproject.properties
2.Create androidproject.properties in /your/path/ and add the following code to it, don't forget to change /your/path/to/android.keystore to your keystore path:
2.在/your/path/中创建androidproject.properties并添加如下代码,不要忘记将/your/path/to/android.keystore改成你的keystore路径:
STORE_FILE=/your/path/to/android.keystore
STORE_PASSWORD=yourstorepassword
KEY_ALIAS=yourkeyalias
KEY_PASSWORD=yourkeypassword
3.In your app module build.gradle (not your project root build.gradle) add the following code if not exist or adjust to it:
3.在你的应用模块build.gradle(不是你的项目根build.gradle)中添加以下代码,如果不存在或调整它:
signingConfigs {
release
}
buildTypes {
debug {
debuggable true
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
4.Add the following code below the code in step 3:
4.在第3步的代码下面添加如下代码:
if (project.hasProperty("AndroidProject.signing")
&& new File(project.property("AndroidProject.signing").toString()).exists()) {
def Properties props = new Properties()
def propFile = new File(project.property("AndroidProject.signing").toString())
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 'androidproject.properties found but some entries are missing'
android.buildTypes.release.signingConfig = null
}
} else {
println 'androidproject.properties file not found'
android.buildTypes.release.signingConfig = null
}
}
This code will search for AndroidProject.signing property in gradle.propertiesfrom step 1. If the property found, it will translate property value as file path which pointing to androidproject.properties that we create in step 2. Then all the property value from it will be used as signing configuration for our build.gradle.
该代码将搜索AndroidProject.signing物业gradle.properties从第1步。如果找到该属性,它会将属性值转换为指向我们在第 2 步中创建的 androidproject.properties 的文件路径。然后它的所有属性值将用作我们的 build.gradle 的签名配置。
Now we don't need to worry again of risk of exposing our keystore password.
现在我们不必再担心暴露我们的密钥库密码的风险。
Read more at Signing Android apk without putting keystore info in build.gradle
回答by SudoPlz
For the ones looking to put their credentials in an external JSON fileand read that from the gradle this is what I did:
对于那些希望将他们的凭据放在外部JSON 文件中并从 gradle 中读取的人,这就是我所做的:
my_project/credentials.json:
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
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.
我选择.json
文件类型而不是.properties
文件类型(如已接受的答案中)的原因是因为我还想将其他数据(我需要的其他自定义属性)存储到同一个文件 ( my_project/credentials.json
),并且仍然让 gradle 解析也从该文件中签署信息。
回答by Micha? K
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.
这个问题已经收到了许多有效的答案,但我想分享我的代码,这可能对库维护者有用,因为它使原始代码build.gradle
非常干净。
I add a folder to the module directory which I gitignore
. It looks like this:
我在模块目录中添加了一个文件夹gitignore
。它看起来像这样:
/signing
/keystore.jks
/signing.gradle
/signing.properties
keystore.jks
and signing.properties
should be self explanatory. And signing.gradle
looks like this:
keystore.jks
并且signing.properties
应该是不言自明的。而且signing.gradle
是这样的:
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
和原来的 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.
如您所见,您根本不必指定 buildTypes,如果用户有权访问有效signing
目录,他只需将其放入模块中,他就可以构建一个有效的签名发布应用程序,否则它只适用于他它通常会这样做。
回答by Yogendra Ghatpande
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.
我的密码包含一个特殊字符,它是美元符号$,我必须在 gradle.properties 文件中转义它。在那之后,签名对我有用。