Как создать файл с подписанным релизом apk, используя Gradle?

514

Я хотел бы иметь мою сборку Gradle для создания релиза подписанный файл apk с использованием Gradle.

Я не уверен, что код правильный или мне не хватает параметра при выполнении gradle build?

Вот часть кода в моем файле Gradle:

android {
    ...
    signingConfigs {
          release {
              storeFile file("release.keystore")
              storePassword "******"
              keyAlias "******"
              keyPassword "******"
         }
     }
}

Gradle сборки завершается успешно, и в моей build/apkпапке я только увидеть ...-release-unsigned.apkи ...-debug-unaligned.apkфайлы.

Любые предложения о том, как решить эту проблему?

Ян-Терье Соренсен
источник
подписать с версией v1 (подпись jar) или v2 (полная подпись apk) из файла Gradle? решение здесь: stackoverflow.com/questions/57943259/…
user1506104
stackoverflow.com/a/61028214/5733853
Вахид Хосейни

Ответы:

430

Проще, чем предыдущие ответы:

Поместите это в ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Измените ваш app/build.gradleи добавьте это внутри android {блока кода:

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

Тогда вы можете запустить gradle assembleRelease


Также см. Ссылку на signingConfigsGradle DSL.

Давид Вавра
источник
12
Лучший способ, если вы спросите меня. Ничего не сохраняет в папке моего проекта / SVN, и я могу оформить 10 версий своих проектов, не беспокоясь о ключах.
Фрэнк
8
Если вы используете gradlew в Windows, вы должны быть уверены, что GRADLE_USER_HOME определен как переменная среды, чтобы эта работа работала. Я установил его на один каталог выше каталога моего проекта и положил туда свое хранилище ключей. Путь к вашему хранилищу ключей в gradle.properties должен использовать косую черту (/) или двойную (\\), а не Windows. Чтобы создать хранилище ключей из командной строки Windows, см. Stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
Anachronist
3
Путь относительно того, где находится файл build.gradle, или относительно корневого каталога машины?
Прем
1
@Prem, file()всегда предполагает относительные пути. Используйте, new File(path)если хотите, чтобы это воспринималось как абсолютное.
ars-longa-vita-brevis
4
Это сработало для меня и самое простое. В свойствах gradle.properties укажите storeFile относительно вашего модуля build.gradle, например RELEASE_STORE_FILE = .. / mykeystore. Не добавляйте цитаты, иначе Gradle Mangles путь
Lakshman Chilukuri
263

Мне удалось решить это, добавив этот код и собрав gradle build:

android {
    ...
    signingConfigs {
        release {
            storeFile file("release.keystore")
            storePassword "******"
            keyAlias "******"
            keyPassword "******"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

Это создает подписанный релиз apk-файл.

Ян-Терье Соренсен
источник
33
Есть ли способ заставить его запрашивать пароли? Или другие предложения, чтобы сохранить пароли из моего репозитория git?
user672009
3
Я редактирую свой build.gradle так, чтобы он выглядел как ваш, но при запуске «Built> Generate signature APK ...» все равно выдается диалоговое окно («Подробную информацию см. В Руководстве пользователя Gradle» и т. Д.) И отсутствует APK.
Семантик
3
@Semanticer Выполнить gradle buildили gradlew buildв терминале / запросить команду
Филипп Камикадзе
12
@ user672009 вы можете поместить пароли в файл свойств и исключить его из репозитория с помощью .gitignore. Вы можете увидеть эту ссылку. gist.github.com/gabrielemariotti/6856974
Габриэле Мариотти
1
@GabrieleMariotti Это все еще оставляет неполное хранилище. Лучшим способом было бы создать скелет signature.properties и после совершения выдать команду «git update-index --assume-неизмененный signature.properties». Однако это не позволяет редактировать футуру. Что-то вроде первого варианта, предложенного sdqali, кажется даже лучше.
user672009
67

Обратите внимание, что скрипт @ sdqali будет (по крайней мере, при использовании Gradle 1.6) запрашивать пароль каждый раз, когда вы вызываете любую задачу gradle. Поскольку вам это нужно только при выполнении gradle assembleRelease(или подобном), вы можете использовать следующий прием:

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

Обратите внимание, что я также должен был добавить следующее (под Android), чтобы это работало:

buildTypes {
    release {
        signingConfig signingConfigs.release
    }
}
jclehner
источник
После реализации этого installReleaseисчезли из списка задач ... Почему?
Каарел
1
@caspase Жаль, что я не воспринял ваш комментарий об этих поддельных "storePassword" и "keyPassword" более серьезно. Без инициализации этих свойств (например, "") подписанный * -release.apk не создается, ошибка не отображается, и вы остаетесь полностью озадаченным только * -release-unsigned.apk в каталоге PROJECT_NAME / build / apk / , Мужик ...: /
vizZ
Спасибо за примечание о добавлении signatureConfig в buildTypes -> Release. Это решило автоматическую подпись для меня!
mm2001
1
Я сделал простой плагин Gradle, который запрашивает пароли при создании релиза apk (используя mathod, описанный в этом посте, но вам не нужно будет определять поддельные storePassword & keyPassword). Это также доступно в maven центральном. github.com/alexvasilkov/AndroidGradleSignPlugin
Алекс Васильков
Это замечательно. Помните, что переменная окружения KEYSTOREдолжна быть определена даже для отладочных сборок и для «gradle sync» внутри Android Studio, иначе это приведет к ошибке, когда путь будет нулевым.
Jerry101
63

Если вы хотите избежать жесткого кодирования вашего хранилища ключей и пароля в build.gradle , вы можете использовать файл свойств, как описано здесь: ОБРАБОТКА ПОДПИСАННЫХ КОНФИГОВ С GRADLE

В принципе:

1) создайте файл myproject.properties по адресу /home/[username]/.signing с таким содержимым:

keystore=[path to]\release.keystore
keystore.password=*********
keyAlias=***********
keyPassword=********

2) создайте файл gradle.properties (возможно, в корне каталога вашего проекта) с содержимым:

MyProject.properties=/home/[username]/.signing/myproject.properties

3) обратитесь к нему в вашем build.gradle следующим образом:

    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']
        }
    }
}
IgorGanapolsky
источник
1
Работает отлично! Спасибо. Этот код должен быть добавлен перед разделом buildTypes {}, а раздел должен объявить signatureConfig signatureConfigs.release как обычно.
theczechsensation
Наконец я нашел решение этой проблемы. Единственное, что действительно помогло мне! Это должен быть принятый ответ ...
devnull69
39

Автоматическая подпись приложения с помощью Gradle при использовании git

Удивительно, как много запутанных способов сделать это. Вот мой собственный путь, где я стараюсь придерживаться собственной рекомендации Googles . Однако их объяснение не до конца понятно, поэтому я опишу процедуру для Linux подробнее.


Описание:

Инструкции Google по умолчанию для автоматической подписи приложения во время сборки без сохранения паролей и файлов подписи в пути разработки приложения (GIT) довольно неясны. Вот поясненные пошаговые инструкции, как это сделать.

Исходные предположения:

У вас есть приложение под названием «MyApp» в директории , заданной по следующему пути: $HOME/projects/mydev/MyApp. Однако каталог MyApp используется и управляется с помощью GIT.

введите описание изображения здесь

проблема

Мы, очевидно, не хотим, чтобы наши файлы сигнатур или паролей находились где-либо в каталоге, контролируемом GIT, даже если мы очень способны их использовать и .gitignoreт. Д., Все равно слишком рискованно и легко допустить ошибку. Таким образом, мы хотим, чтобы наше хранилище ключей и файлы подписи снаружи.

Решение

Нам нужно сделать три (3) вещи:

  1. Создайте файл паролей для использования Android Studio
  2. Создать файл ключа подписи
  3. Отредактируйте build.gradleфайл модуля, чтобы использовать (1) и (2).

Для этого примера мы назовем два файла:

  1. keystore.properties
  2. MyApp-release-key.jks

Мы можем поместить оба этих файла здесь:

cd $HOME/projects/mydev/

(1) Создайте файл паролей хранилища ключей

Первый файл содержит пароли в виде открытого текста, используемые в; и пути к файлу ключа разблокировки в (2). Начните с заполнения, так как это сделает операцию копирования вставкой проще для следующего шага.

cd $HOME/projects/mydev/

Отредактируйте keystore.propertiesтак, чтобы это было:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myKeyAlias
storeFile=myStoreFileLocation

Единственная сложная часть здесь, это myStoreFileLocation. Это путь, как видно изbuild.gradle файла модуля во время сборки. Как правило , это означает , что путь похож и по отношению к: $HOME/projects/mydev/MyApp/app/build.gradle. Итак, чтобы указать на MyApp-release-key.jks файл, нам нужно поместить здесь:

../../../MyApp-release-key.jks

Здесь мы также выбрали псевдоним "myapp" для ключа. Тогда финальный файл должен выглядеть так:

storePassword=myStorePassword
keyPassword=mykeyPassword
keyAlias=myapp
storeFile=../../../MyApp-release-key.jks

(2) Создайте файл подписи

Второй файл генерируется автоматически при создании ключа подписи. Если у вас нет других приложений и это ваше единственное хранилище ключей, то создайте файл с:

cd $HOME/projects/mydev/
keytool -genkeypair -v -keystore MyApp-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myapp

Это попросит вас ввести два пароля и кучу информации. (То же самое, что и в Android Studio.) Теперь скопируйте / вставьте ранее выбранные пароли.

(3) Отредактируйте файл модуля, gradle.buildчтобы использовать вышеуказанное

Следующие части должны присутствовать в файле сборки вашего приложения / модуля Gradle. Сначала добавьте следующие строки снаружи и перед вашим android {}блоком.

//def keystorePropertiesFile = rootProject.file("$HOME/.android/keystore.properties")
def keystorePropertiesFile = rootProject.file("../../keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))

Затем, внутри в android {}блоке, добавьте:

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

Теперь из оболочки вы можете пересобрать свое приложение с помощью:

cd $HOME/projects/mydev/MyApp/app/
./gradlew clean build

Это должно создать правильно подписанное приложение, которое можно использовать в Google Play.


ОБНОВЛЕНИЕ: 2019-04-02

Более поздние версии keytoolи кое-что говорят вам, что вы должны использовать файл ключей на основе PKCS12 вместо оригинального / default, как я использую выше. Затем они все время говорят вам, что вам следует перейти на новый открытый формат PKCS12. Однако, похоже, что инструменты разработки Android еще не совсем готовы к этому, потому что если вы это сделаете, вы получите следующие странные ошибки:

com.android.ide.common.signing.KeytoolException:Не удалось прочитать ключ XXX из хранилища "F: \ XXX \ XXX.jks": Ошибка получения ключа: данный последний блок заполнен неправильно. Такие проблемы могут возникнуть, если при расшифровке используется плохой ключ.

Так что не используйте конвертированный ключ!

not2qubit
источник
Сохраняется ли signatureConfigs внутри apk, и затем любой пользователь может его декомпилировать для получения паролей или его нет в apk?
ХавьерСеговияКордоба
2
Работает как шарм. Спасибо, это должен быть принятый ответ
pratham kesarkar
Что если вам нужно только хранилище ключей и пароли на сервере сборки? При использовании вышеуказанного решения каждому разработчику в команде необходимо иметь хранилище ключей на своей локальной машине. В противном случае произойдет сбой синхронизации проекта Gradle: keystore.properties (такого файла или каталога нет).
Диана Фарин,
1
Вы можете передать фиктивный keystore.propertiesфайл в систему управления версиями, поэтому сборка работает на машинах разработчиков. Я описал настройку сервера сборки здесь .
dskrvk
1
Замечание о вашем последнем обновлении о keytoolгенерации PKCS12 хранилища ключей: вы можете передать -storetype JKSв keytoolкоманде , чтобы установить тип хранилища ключей JKS , который необходим в Android инструментами.
Тревор Халворсон
35

Как сказал @Destil, но позвольте другим, у кого нет ключа для сборки: проще, чем предыдущие ответы:

Поместите это в ~/.gradle/gradle.properties

RELEASE_STORE_FILE={path to your keystore}
RELEASE_STORE_PASSWORD=*****
RELEASE_KEY_ALIAS=*****
RELEASE_KEY_PASSWORD=*****

Измените ваш, build.gradleкак это:

...    
if(project.hasProperty("RELEASE_STORE_FILE")) {
    signingConfigs {    
       release {
           storeFile file(RELEASE_STORE_FILE)
           storePassword RELEASE_STORE_PASSWORD
           keyAlias RELEASE_KEY_ALIAS
           keyPassword RELEASE_KEY_PASSWORD
       }
    }
}

buildTypes {
    if(project.hasProperty("RELEASE_STORE_FILE")) {
        release {
            signingConfig signingConfigs.release
        }
    }
}
....

Тогда вы можете запустить gradle assembleRelease ИЛИ gradle build

Гал Брача
источник
Как установить путь в Windows: путь к вашему хранилищу ключей
reza_khalafi
Файл storeFile ("C: \\ Users \\ xxxx \\ Documents \\ yyyy \\ mykey.jks") это правильно?
reza_khalafi
28

(В ответ на user672009 выше.)

Еще более простое решение, если вы хотите сохранить свои пароли в хранилище git; тем не менее, хотите включить в него свой build.gradle, который прекрасно работает даже с различными вариантами продуктов, - это создать отдельный файл gradle. Давайте назовем это «signature.gradle» (включите его в ваш .gitignore). Так же, как если бы это был ваш файл build.gradle, за вычетом всего, что не относится к входу в него.

android {
    signingConfigs { 
        flavor1 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
        flavor2 {
            storeFile file("..")
            storePassword ".."
            keyAlias ".."
            keyPassword ".."
        }
    }
}

Затем в вашем файле build.gradle включите эту строку прямо под "применить плагин: 'android'"

 apply from: 'signing.gradle'

Если у вас нет или вы используете несколько ароматов, переименуйте «flav1» в «release» выше, и все будет готово. Если вы используете ароматизаторы, продолжайте.

Наконец, свяжите ваши варианты с его правильным signatureConfig в вашем файле build.gradle, и вы должны закончить.

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...
jonbo
источник
Можете ли вы быть немного более конкретным. Я не могу заставить его работать: "не могу разрешить символ signatureConfig".
Amio.io
Если я включаю «signature.gradle» в build.gradle - я вынужден иметь его в git-репозитории (иначе я получаю ошибку «signature.gradle не существует»). И если я добавлю «signature.gradle» в git, это побеждает цель. Как я могу сделать включение подписания. Gradle необязательным?
Ягуар
21

Если у вас уже есть файл хранилища ключей, это может быть так же просто, как добавить несколько параметров в вашу команду сборки:

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

Не требуется постоянных изменений в вашем проекте Android.

Источник: http://www.tinmith.net/wayne/blog/2014/08/gradle-sign-command-line.htm

janpio
источник
18

Это ответ на user672009 и дополнение к сообщению sdqali (его код падает при сборке отладочной версии при нажатии кнопки «Выполнить» в IDE):

Вы можете использовать следующий код:

final Console console = System.console();
if (console != null) {

    // Building from console 
    signingConfigs {
        release {
            storeFile file(console.readLine("Enter keystore path: "))
            storePassword console.readLine("Enter keystore password: ")
            keyAlias console.readLine("Enter alias key: ")
            keyPassword console.readLine("Enter key password: ")
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}
AChep
источник
Есть ли способ иметь некоторые значения по умолчанию? Мой склад ключей обычно такой же. StorePassword обычно совпадает с keyPassword, а keyAlias ​​- обычно имя проекта в нижнем регистре.
user672009
@ user672009 вы всегда можете использовать код Java внутри скрипта.
AChep
1
Вы можете использовать что-то вроде этого: keyPassword new String(console.readPassword("Enter key password: "))чтобы убедиться, что ваш пароль не отображается во время ввода
Алекс Семенюк
Это больше не работает, см github.com/gradle/gradle/issues/1251
SqAR.org
16

В более новой Android Studio есть графический интерфейс, который очень прост, и он также заполняет файл Gradle.

  1. File -> Project Structure

  2. Module -> Выберите основной модуль («приложение» или другое пользовательское имя)

  3. Signing вкладка -> Плюс изображение для добавления новой конфигурации

  4. Заполните данные на правой стороне

  5. ОК и Gradle файл создается автоматически

  6. Вам придется вручную добавить строку signingConfig signingConfigs.NameOfYourConfigвнутриbuiltTypes{release{}}

Картинки:

введите описание изображения здесь

введите описание изображения здесь

Два важных (!) Примечания:

(РЕДАКТИРОВАТЬ 12/15)

  1. Чтобы создать подписанный APK, вам нужно открыть вкладку «Терминал» в Android Studio (внизу основного интерфейса) и выполнить команду ./gradlew assembleRelease

  2. Если вы забыли keyAlias(что часто случается со мной), вам нужно будет Build -> Generate Signed APKзапустить процесс и увидеть имя ключа Alias.

sandalone
источник
2
Это жестко кодирует ваши пароли в build.gradleфайл, не так ли?
Джошуа Пинтер
16

Если вы собираете apk через командную строку, как я, тогда вы можете указать конфигурацию подписи в качестве аргументов.

Добавьте это к вашему build.gradle

def getStore = { ->
    def result = project.hasProperty('storeFile') ? storeFile : "null"
    return result
}

def getStorePassword = { ->
    def result = project.hasProperty('storePassword') ? storePassword : ""
    return result
}

def getKeyAlias = { ->
    def result = project.hasProperty('keyAlias') ? keyAlias : ""
    return result
}

def getKeyPassword = { ->
    def result = project.hasProperty('keyPassword') ? keyPassword : ""
    return result
}

Сделай signingConfigsтак

signingConfigs {
    release {
        storeFile file(getStore())
        storePassword getStorePassword()
        keyAlias getKeyAlias()
        keyPassword getKeyPassword()
    }
}

Затем вы выполняете, gradlewкак это

./gradlew assembleRelease -PstoreFile="keystore.jks" -PstorePassword="password" -PkeyAlias="alias" -PkeyPassword="password"
эгида
источник
Что есть build.gradle? Верхний уровень? Пожалуйста, добавьте больше кода
Влад
Чтобы уточнить, это app/build.gradleфайл, о котором я говорю.
Egis
11
android {
    compileSdkVersion 17
    buildToolsVersion "19.0.3"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 18
    }

    File signFile = rootProject.file('sign/keystore.properties')
    if (signFile.exists()) {
        Properties properties = new Properties()
        properties.load(new FileInputStream(signFile))
        signingConfigs {
            release {
                storeFile rootProject.file(properties['keystore'])
                storePassword properties['storePassword']
                keyAlias properties['keyAlias']
                keyPassword properties['keyPassword']
            }
        }
    }

    buildTypes {
        release {
            runProguard true
            zipAlign true
            proguardFile rootProject.file('proguard-rules.cfg')
            signingConfig signingConfigs.release
        }
        debug {
            runProguard false
            zipAlign true
        }
    }
}
JP Ventura
источник
Использование Android Studio 0.5.1, Gradle 1.11 и плагина Gradle 0.9.
JP Ventura
1
Создание свойств по требованию (или динамических свойств) устарело и должно быть удалено в Gradle 2.0
JP Ventura
10

Вы также можете использовать опцию командной строки -P команды gradle, чтобы помочь подписанию. В свой build.gradle добавьте singingConfigs вот так:

signingConfigs {
   release {
       storeFile file("path/to/your/keystore")
       storePassword RELEASE_STORE_PASSWORD
       keyAlias "your.key.alias"
       keyPassword RELEASE_KEY_PASSWORD
   }
}

Затем вызовите gradle build следующим образом:

gradle -PRELEASE_KEYSTORE_PASSWORD=******* -PRELEASE_KEY_PASSWORD=****** build

Вы можете использовать -P для установки storeFile и keyAlias, если хотите.

Это в основном решение Destil, но с параметрами командной строки.

Для получения более подробной информации о свойствах gradle, обратитесь к руководству пользователя gradle .

Энди Шиуэ
источник
7

Ответ @ Destil хорош, если вы можете использовать одну и ту же конфигурацию во всех проектах. В качестве альтернативы Android Studio поставляется с local.propertiesфайлом, который можно использовать вместо этого, но он предположительно генерируется IDE, и я не могу найти способ расширить его из Android Studio.

Это вариант ответа @ jonbo . Этот ответ допускает специфичные для проекта настройки, но требует от разработчика некоторых накладных расходов. В частности, для переноса signingConfigsопределения в отдельный файл требуется значительный шаблон - особенно если вам нужно сделать это для нескольких проектов, что является основной причиной выбора этого решения вместо Destil's. Это может быть несколько облегчено также включая линию

apply plugin: 'com.android.application'

в файле учетных данных, так как это позволит завершить IDE.

Наконец, большинство решений здесь не позволяют строить проект в режиме отладки - который обрабатывает отладку-подпись автоматически - без предоставления синтаксически, если не семантически правильного signingConfigsопределения. Если вам не нужно производить сборку релиза с данного компьютера, этот дополнительный шаг можно рассматривать как ненужное препятствие. С другой стороны, это может помочь против невежественных или ленивых коллег, использующих отладочные сборки в производстве.

Это решение позволит отлаживать сборки, не беспокоясь об учетных данных, но для создания сборок выпусков потребуются действительные учетные данные, а для этого требуется очень мало стандартного образца. Однако, как недостаток, это может побудить других заменить фиктивные значения реальными учетными данными, и от этого не существует способа защиты.

// 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
            ...
        }
    }
}

Это создает фиктивное свойство, которое служит исключительно для создания синтаксически правильного файла сборки. Значения, присвоенные ext.signingсвойствам `s, не имеют значения, насколько идут отладочные сборки. Чтобы включить релиз сборки, копию ext.signingв signing.gradleи заменить значения фиктивных с действительными учетными данными.

// signing.gradle
ext.signing = [
        storeFilePath : 'real/keystore',
        storePassword : 'real keystore password',
        keyAlias : 'real key alias',
        keyPassword : 'real key password',
]

Конечно, signing.gradleдолжен быть проигнорирован VCS.

mkjeldsen
источник
6

Почти все платформы теперь предлагают какие-то брелоки, поэтому нет смысла оставлять пароли с открытым текстом.

Я предлагаю простое решение , которое использует модуль Python Keyring ( в основном компаньон консоль сценарий keyring) и минимальную оболочку вокруг Groovy ['do', 'something'].execute() функции :

def execOutput= { args ->
    def proc = args.execute()
    proc.waitFor()
    def stdout = proc.in.text
    return stdout.trim()
}

Используя эту функцию, signingConfigsраздел становится:

signingConfigs {
    release {
        storeFile file("android.keystore")
        storePassword execOutput(["keyring", "get", "google-play", storeFile.name])
        keyAlias "com.example.app"
        keyPassword execOutput(["keyring", "get", "google-play", keyAlias])
    }
}

Перед запуском gradle assembleReleaseвы должны установить пароли в связке ключей только один раз:

$ keyring set google-play android.keystore # will be prompted for the passwords
$ keyring set google-play com.example.app

Счастливые релизы!

naufraghi
источник
5

Расширяя ответ Дэвида Вавра, создайте файл ~ / .gradle / gradle.properties и добавьте

RELEASE_STORE_FILE=/path/to/.keystore
RELEASE_KEY_ALIAS=XXXXX
RELEASE_STORE_PASSWORD=XXXXXXXXX
RELEASE_KEY_PASSWORD=XXXXXXXXX

Потом в build.gradle

  signingConfigs {
    release {
    }
  }

  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true

    }
  }

  // make this optional
  if ( project.hasProperty("RELEASE_KEY_ALIAS") ) {
    signingConfigs {
      release {
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
      }
    }
    buildTypes {
      release {
        signingConfig signingConfigs.release
      }
    }
  }
SRC
источник
5

Мне было очень весело выяснить это. Вот мой проход.

Краткое руководство по созданию файла сборки gradle в IntelliJ (v.13.1.4). В этом пошаговом руководстве предполагается, что вы знаете, как создать файл хранилища ключей. Чтобы этот учебник работал, вам потребуется, чтобы файл хранилища ключей находился в папке вашего приложения, а файл zipalign.exe должен находиться в папке «SDK-ROOT \ tools». Этот файл обычно находится в 'SDK-ROOT \ build-tools', и в этой папке он находится в самой высокой папке API (альфа или бета, я рекомендую альфа-версию).

Для тех из вас, кто хочет прыгнуть прямо сюда, есть файл сборки gradle.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
}
android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        playstore {
            keyAlias 'developers4u'
            keyPassword 'thisIsNotMyRealPassword'
            storeFile file('developers4u.keystore')
            storePassword 'realyItIsNot'
        }
    }
    buildTypes {
        assembleRelease {
            debuggable false
            jniDebugBuild false
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
            zipAlign true
            signingConfig signingConfigs.playstore
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

Вы можете собрать часть этого файла сборки (см. Выше) из пункта меню: Структура файла / проекта. Здесь выберите Facets и нажмите «Android-Gradle (приложение)». Отсюда вы увидите вкладки: «Свойства», «Подписание», «Ароматы», «Типы сборки» и «Зависимости», для этого пошагового руководства мы просто будем использовать «Подписывание» и «Типы сборки». В разделе «Типы сборки» (в разделе «Имя») введите любое имя, которое вы хотите идентифицировать для своей конфигурации типа сборки, а в других 4 полях введите информацию о вашем хранилище ключей (задав путь к хранилищу ключей, который находится в папке вашего приложения).

Под полем «Типы сборки» введите значение «assemblyRelease» в поле имени, для «Debuggable» должно быть установлено значение «ложь», для «Jni Debug Build» должно быть значение «ложь», для параметра «Запустить Proguard» - значение «истина», а для параметра «Zip Align» - значение «истина». Это создаст файл сборки, но не так, как показано выше, вам придется добавить несколько вещей в файл сборки позже. Расположение файла ProGuard здесь будет установлено вручную в файле сборки Gradle. (как показано выше)

Контейнеры DSL, которые вы должны будете добавить после этого:

android {
    ....
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    ....
}

Вы также должны будете добавить:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:20.0.0'
    implementation 'com.android.support:appcompat-v7:20.0.0'
}

обратите внимание, что указанный выше контейнер DSL («зависимости») должен находиться внизу файла конфигурации, но не внутри контейнера DSL android. Чтобы построить контейнер зависимостей из меню IntelliJ, выберите: File / Project Structure. Оттуда снова выберите Facets, а затем Android-Gradle (приложение). Вы увидите те же 5 вкладок, как указано выше. Выберите вкладку «Зависимости» и добавьте необходимые зависимости.

После того, как все это будет сделано, вы должны увидеть файл сборки Gradle, похожий на файл в верхней части этого пошагового руководства. Чтобы создать подписанный релиз с выравниванием по почтовому индексу, вам нужно открыть задачи Gradle. Вы можете попасть в это окно, выбрав View / Tool Windows / Gradle. Отсюда вы можете дважды щелкнуть по ссылке «AsAsmbleRelease». Это должно создать ваш развертываемый APK.

Потенциальные проблемы, которые могут возникнуть при компиляции вашего релиза: (но не ограничиваясь ими): ваш файл сборки Gradle находится не в том месте. Есть два файла сборки Gradle; один в корневой папке приложения, а другой в папке приложения под корнем приложения. Вы должны использовать последнее.

У вас также могут быть проблемы с ворсом. (Примечание: Android Developer Studio гораздо лучше распознает проблемы с Lint, чем IntelliJ, вы заметите это при попытке создать подписанный APK из параметров меню)

Чтобы обойти проблемы с линтом, вам нужно поместить следующий контейнер DSL внутри контейнера Android (вверху):

android {
        ....
    lintOptions {
        abortOnError false
    }
    ....
}

размещение этого в вашем DSL-контейнере для Android приведет к генерации файла ошибки в папке сборки (непосредственно в папке вашего приложения), имя файла должно быть примерно таким: «lint-results-release-fatal.html», этот файл сообщит вам класс, где произошла ошибка. Другой файл, который будет сгенерирован, - это файл XML, который содержит «идентификатор проблемы», связанный с ошибкой lint. Имя файла должно быть что-то вроде 'lint-results-release-fatal.xml'. Где-то в верхней части файла вы увидите «проблему» узла, внутри которой вы увидите нечто похожее на «id =" IDOfYourLintProblem "'

Чтобы устранить эту проблему, откройте файл в своем проекте, который был указан в файле 'lint-results-assemblyRelease-fatal.html', и введите следующую строку кода в файле класса Java чуть выше имени класса: @SuppressLint ("IDOfYourLintProblem «). Возможно, вам придется импортировать 'android.annotation.SuppressLint;'

Таким образом, ваш файл классов Java должен выглядеть так:

package com.WarwickWestonWright.developers4u.app.CandidateArea;

import android.annotation.SuppressLint;
... other imports

@SuppressLint("IDOfYourLintProblem")
public class SearchForJobsFragment extends Fragment {... rest of your class definition}

Обратите внимание, что подавление ошибок ворса не всегда является лучшей ИДЕЕЙ, вам может быть лучше изменить код, вызвавший ошибки ворса.

Другая проблема, которая может возникнуть, - это если вы не задали переменную среды для переменной среды Gradle HOME. Эта переменная называется «GRADLE_HOME» и должна указывать путь к домашнему каталогу gradle, что-то вроде «C: \ gradle-1.12». Иногда вам также может потребоваться установить переменную среды для «ANDROID_HOME», установив для нее «YOUR- SDK-Root \ SDK»

После того, как это сделано, вернитесь в окно задач Gradle и дважды щелкните по ссылке AsAsmbleRelease.

Если все прошло успешно, вы сможете перейти в папку app \ build \ apk и найти развертываемый APK-файл.

user2288580
источник
+1 за усилия и: 'lintOptions {abortOnError false}}
Раз Тургман
4

Еще один подход к той же проблеме. Поскольку не рекомендуется хранить какие-либо учетные данные в исходном коде, мы решили установить пароли для хранилища ключей и псевдонима ключей в отдельном файле свойств следующим образом:

key.store.password=[STORE PASSWORD]
key.alias.password=[KEY PASSWORD]

Если вы используете git, вы можете создать текстовый файл с именем, например, secure.properties. Вы должны обязательно исключить его из своего хранилища (если вы используете git, добавьте его в файл .gitignore). Затем вам нужно будет создать конфигурацию подписи, как показывают некоторые другие ответы. Разница лишь в том, как вы будете загружать учетные данные:

android {
    ...
    signingConfigs {
        ...
        release {
            storeFile file('[PATH TO]/your_keystore_file.jks')
            keyAlias "your_key_alias"

            File propsFile = file("[PATH TO]/secure.properties");
            if (propsFile.exists()) {
                Properties props = new Properties();
                props.load(new FileInputStream(propsFile))
                storePassword props.getProperty('key.store.password')
                keyPassword props.getProperty('key.alias.password')
            }
        }
        ...
    }

    buildTypes {
        ...
        release {
            signingConfig signingConfigs.release
            runProguard true
            proguardFile file('proguard-rules.txt')
        }
        ...
    }
}

Никогда не забывайте назначать signatureConfig типу сборки релиза вручную (по некоторым причинам я иногда предполагаю, что он будет использоваться автоматически). Также не обязательно включать proguard, но это рекомендуется.

Нам нравится этот подход лучше, чем использование переменных среды или запрос пользовательского ввода, потому что это можно сделать из среды IDE, переключившись на тип сборки realease и запустив приложение, вместо того, чтобы использовать командную строку.

argenkiwi
источник
1
Gradle не компилируется с использованием этого: props = new Properties (); Невозможно установить значение свойства «
props»
Вы правы @ m3n0R. Я отредактировал строку моего ответа, чтобы отразить исправление, которое мы должны были внести в наше приложение, чтобы оно по-прежнему компилировалось с использованием последних версий Gradle. По сути, реквизиты должны быть объявлены как локальные переменные.
argenkiwi
как это может быть адаптировано с помощью облачных инструментов CI / CD ... / path / to / keystore и /path/to/secure.props меня выбрасывают ... хотя спасибо за это.
Сирвон
4

Android Studio Перейдите в Файл -> Структура проекта или нажмите Ctrl + Alt + Shift + S

Посмотреть изображение

введите описание изображения здесь

Нажмите Ok

Затем signatureConfigs сгенерирует ваш файл build.gradle.

введите описание изображения здесь

Ахамадулла Сайкат
источник
И это именно то, что вы не хотите делать. Таким образом, все ваши пароли находятся в открытом виде и являются частью вашего проекта , и их очень легко случайно включить даже в вашу распределенную сборку.
not2qubit
2

У меня было несколько проблем, которые я поставил следующую строку в неправильном месте:

signingConfigs {
    release {
        // We can leave these in environment variables
        storeFile file("d:\\Fejlesztés\\******.keystore")
        keyAlias "mykey"

        // These two lines make gradle believe that the signingConfigs
        // section is complete. Without them, tasks like installRelease
        // will not be available!
        storePassword "*****"
        keyPassword "******"
    }
}

Убедитесь, что вы поместили части signatureConfigs в раздел android:

android
{
    ....
    signingConfigs {
        release {
          ...
        }
    }
}

вместо

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

Легко сделать эту ошибку.

Ботонд Копач
источник
2

Это 2019 год, и мне нужно подписать APK с V1 (подпись jar) или V2 (полная подпись APK). Я погуглил "генерировать подписанный apk gradle", и это привело меня сюда. Поэтому я добавляю свое оригинальное решение здесь.

signingConfigs {
    release {
        ...
        v1SigningEnabled true
        v2SigningEnabled true
    }
}

Мой оригинальный вопрос: Как использовать V1 (подпись Jar) или V2 (полная подпись APK) из файла build.gradle

user1506104
источник
Нет необходимости с запятой; это даст вам ошибку.
Такеши Кага
Это верно. Спасибо. Я отредактировал ответ.
user1506104
1

Чтобы дополнить другие ответы, вы также можете поместить файл gradle.properties в свою папку модуля вместе с build.gradle на тот случай, если ваше хранилище ключей относится к одному проекту.

cprcrack
источник
1

Я работаю в Ubuntu14.04. vim ~ / .bashrc и добавить экспорт ANDROID_KEYSTORE = экспорт ANDROID_KEYALIAS =

а затем в build.gradle установить.

    final Console console = System.console();
if (console != null) {

    // Building from console
    signingConfigs {
        release {
            storeFile file(System.getenv("KEYSTORE"))
            storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
            keyAlias System.getenv("KEY_ALIAS")
            keyPassword new String(System.console().readPassword("\n\$ Enter key password: "))
        }
    }

} else {

    // Building from IDE's "Run" button
    signingConfigs {
        release {

        }
    }

}
ayyb1988
источник
ИМХО, кажется, это лучшее решение, но, к сожалению, оно перестало работать на более новых версиях Gradle : System.console()возвращается null.
Антонио Виниций Менезес Медей
1

Альтернативой является определение задачи, которая выполняется только в сборках выпуска.

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();
}
davidpetter
источник
Мне кажется предпочтительным следующее: stackoverflow.com/a/19130098/3664487 Как соотносятся два подхода?
user2768
1

Вы можете запросить пароли из командной строки:

...

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
  }

  ...
}

...

if-then-elseБлок предотвращает запросы паролей , когда вы создаете релиз. Хотя elseветка недоступна, она заставляет Gradle создать install...Releaseзадачу.

Предыстория . Как отмечается в https://stackoverflow.com/a/19130098/3664487 , « Сценарии Gradle могут запрашивать ввод данных пользователем с помощью System.console (). Метод readLine ». К сожалению, Gradle всегда будет запрашивать пароль, даже когда вы создаете отладочную версию (см. Как создать файл с подписанным выпуском apk с помощью Gradle? ). К счастью, это можно преодолеть, как я показал выше.

user2768
источник
Мой предыдущий ответ столкнулся с проблемами из-за stackoverflow.com/questions/33897802/… . Я пересмотрел свой ответ, чтобы устранить эту проблему.
user2768 24.11.15
@Haroon, это работало с 24 ноября '15. Сообщество может помочь решить вашу проблему, но вам нужно будет предоставить более подробную информацию.
user2768
Мне нравится это решение, так как оно избегает размещения пароля в виде обычного текста в текстовом файле, но System.console (). ReadLine не работает в gradle из-за этой надоедливой проблемы.
Морфеус
@ morpheus, у меня никогда не было проблем. Выше работает для меня.
user2768
Я думаю, что вы запускаете скрипт из IDE. если скрипт запускается из терминала, вы увидите ошибку. но спасибо за этот ответ. это то, что я искал.
Морфеус
0

Добавлю мой способ сделать это в React-Native с помощью пакетаact-native-config .
Создайте файл .env:

RELEASE_STORE_PASSWORD=[YOUR_PASSWORD]
RELEASE_KEY_PASSWORD=[YOUR_PASSWORD]

обратите внимание, что это не должно быть частью контроля версий.

в вашем build.gradle:

signingConfigs {
        debug {
            ...
        }
        release {
            storeFile file(RELEASE_STORE_FILE)
            storePassword project.env.get('RELEASE_STORE_PASSWORD')
            keyAlias RELEASE_KEY_ALIAS
            keyPassword project.env.get('RELEASE_KEY_PASSWORD')
        }
    }
chenop
источник
0

В моем случае я загружал неправильный apk в выпуск другого приложения.

Dewsworld
источник
0

Для Groovy (build.gradle)

Не следует помещать свои учетные данные для подписи непосредственно в файл build.gradle . Вместо этого учетные данные должны исходить из файла, который не контролируется версиями.

Поместите файл signature.properties, где находится модуль build.gradle . Не забудьте добавить его в свой файл .gitignore !

signing.properties

storeFilePath=/home/willi/example.keystore
storePassword=secret
keyPassword=secret
keyAlias=myReleaseSigningKey

build.gradle

android {
    // ...
    signingConfigs{
        release {
            def props = new Properties()

            def fileInputStream = new FileInputStream(file('../signing.properties'))
            props.load(fileInputStream)
            fileInputStream.close()

            storeFile = file(props['storeFilePath'])
            storePassword = props['storePassword']
            keyAlias = props['keyAlias']
            keyPassword = props['keyPassword']
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
            // ...
        }
    }
}
Вилли Ментцель
источник
0

Для Kotlin Script (build.gradle.kts)

Вы не должны помещать свои учетные данные для подписи непосредственно в build.gradle.kts файл . Вместо этого учетные данные должны исходить из файла, который не контролируется версиями.

Поместите файл signature.properties, в котором находится модуль build.gradle.kts для конкретного модуля . Не забудьте добавить его в свой файл .gitignore !

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")
            // ...
        }
    }
}
Вилли Ментцель
источник
-1

если вы не хотите видеть Cannot вызвать метод readLine () для нулевого объекта. Вам нужно сначала написать в gradle.properties .

KEYSTORE_PASS=*****
ALIAS_NAME=*****
ALIAS_PASS=*****
JeasonWong
источник