Подпишите 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.Создайте андроидпроект.свойства в /your / path/ и добавьте к нему следующий код, не забудьте изменить /your/path/на/android.хранилище ключей к вашему пути хранилища ключей:
STORE_FILE=/your/path/to/android.keystore STORE_PASSWORD=yourstorepassword KEY_ALIAS=yourkeyalias KEY_PASSWORD=yourkeypassword
3.In сборка модуля вашего приложения.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 без размещения информации о хранилище ключей в сборке.gradle
для тех, кто хочет поместить свои учетные данные во внешний JSON file и прочитал, что из 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 ... }
как вы можете видеть, Вам не нужно указывать типы зданий вообще, если пользователь имеет доступ к действительному
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