Подпишите APK, не помещая информацию о хранилище ключей в сборку.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
}
}
}
он работает отлично, но я не должен поместите значения для storePassword
и keyPassword
в моем репозитории. Я бы предпочел не ставить storeFile
и keyAlias
там.
есть ли способ изменить build.gradle
Так что он получит пароли из какого-либо внешнего источника (например, файл, который находится только на моем компьютере)?
и конечно, измененное build.gradle
должен использоваться на любом другом компьютере (даже если компьютер не имеет доступа к паролям).
Я использую Android Studio и в Mac OS X Maverics, если это имеет значение.
10 ответов
хорошая вещь о Groovy заключается в том, что вы можете свободно смешивать Java-код, и его довольно легко прочитать в файле ключа/значения, используя java.util.Properties
. Возможно, есть еще более простой способ использования идиоматического Groovy, но Java все еще довольно прост.
создать keystore.properties
file (в этом примере в корневом каталоге вашего проекта рядом с settings.gradle
, хотя вы можете поместить его куда угодно:
storePassword=...
keyPassword=...
keyAlias=...
storeFile=...
добавьте это в ваш 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']
}
}
}
кроме того, если вы хотите применить ответ Скотта Барты более похожим на автоматически сгенерированный код gradle, вы можете создать keystore.properties
файл в корневой папке проекта:
storePassword=my.keystore
keyPassword=key_password
keyAlias=my_key_alias
storeFile=store_file
и измените код 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']
}
}
...
}
вы можете сохранить этот файл свойств в корне вашего модуля, в этом случае просто опустите rootProject
, и вы также можете изменить этот код, чтобы иметь несколько наборов свойств для разных хранилищ ключей и псевдонимов ключей.
самый простой способ создать .
ANDROID_STORE_PASSWORD=hunter2
ANDROID_KEY_PASSWORD=hunter2
затем ваш build.gradle
файл может выглядеть так:
android {
signingConfigs {
release {
storeFile file('yourfile.keystore')
storePassword ANDROID_STORE_PASSWORD
keyAlias 'youralias'
keyPassword ANDROID_KEY_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
после прочтения нескольких ссылок:
http://blog.macromates.com/2006/keychain-access-from-shell/ http://www.thoughtworks.com/es/insights/blog/signing-open-source-android-apps-without-disclosing-passwords
поскольку вы используете Mac OSX, вы можете использовать Keychain Access для хранения паролей.
потом в 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]
}
используйте так:
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
}
}
}
вот как я это делаю. Использовать Переменные Среды
signingConfigs {
release {
storeFile file(System.getenv("KEYSTORE"))
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
принято отвечать использовать файл который ключей для подписи APK, который находится в той же корневой папке проекта. Когда мы используем vcs как Git, может быть плохо, когда мы забываем добавить файл свойств в игнор лист. Потому что мы раскроем миру наш пароль. Проблемы по-прежнему сохраняются.
вместо того, чтобы делать файл свойств в том же каталоге в нашем проекте, мы должны сделать это снаружи. Мы делаем это снаружи использование gradle.файл свойств.
вот шаги:
1.Редактировать или создавать gradle.свойства в корневом проекте и добавьте следующий код, не забудьте отредактировать путь самостоятельно:
AndroidProject.signing=/your/path/androidproject.properties
2.Создайте androidproject.свойства в /your/ path /и добавьте к нему следующий код, не забудьте изменить/your/path/to / android.хранилище ключей к пути хранилища ключей:
STORE_FILE=/your/path/to/android.keystore
STORE_PASSWORD=yourstorepassword
KEY_ALIAS=yourkeyalias
KEY_PASSWORD=yourkeypassword
3.В сборке модуля приложения.gradle (не ваша корневая сборка проекта.Gradle в) Добавить следующий код, если он не существует или не настроен на него:
signingConfigs {
release
}
buildTypes {
debug {
debuggable true
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
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
}
}
этот код будет искать AndroidProject.подписание свойства в gradle.свойства С Шаг 1. Если свойство найдено, оно переведет значение свойства как путь к файлу, который указывает на androidproject.свойства, которые мы создаем в Шаг 2. Тогда все значение свойства из него будет использоваться как конфигурация подписи для нашей сборки.градля.
теперь нам не нужно беспокоиться о риске разоблачения нашего пароля хранилища ключей.
подробнее на подписание Android apk без размещения keystore информации в сборке.Gradle в
для тех, кто хочет поместить свои учетные данные во внешний файл JSON и прочитал, что из gradle это то, что я сделал:
на my_project/учетные данные.в 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
// ...
}
}
}
// ...
}
причина, по которой я выбрал .json
тип файла, а не .properties
тип файла (как в принятом ответе), потому что я хотел также сохранить другие данные (другие пользовательские свойства, которые мне нужны) в том же файле (my_project/credentials.json
), и все еще есть gradle анализировать информацию подписи из этого файла, а также.
можно взять любой существующий проект Android Studio gradle и построить / подписать его из командной строки без редактирования файлов. Это делает его очень хорошим для хранения вашего проекта в управлении версиями, сохраняя ваши ключи и пароли отдельно, а не в вашей сборке.файл 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
этот вопрос получил много действительных ответов, но я хотел поделиться своим кодом, который может быть полезен для мейнтейнеров библиотека, потому что оставляет оригиналы build.gradle
довольно чистый!--12-->.
добавить папку в каталог модуля, который я gitignore
. Выглядит это так:
/signing
/keystore.jks
/signing.gradle
/signing.properties
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]
и оригинал 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 ...
}
как вы можете видеть, Вам не нужно указывать buildTypes вообще, если пользователь имеет доступ к действительному signing
каталог, он просто помещает его в модуль, и он может создать действительное подписанное приложение выпуска, иначе он просто работает для него, как обычно.
вы можете запросить пароли из командной строки:
...
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
}
...
}
...
этот ответ ранее появлялся:https://stackoverflow.com/a/33765572/3664487