ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 Gradle 创建发布签名的 apk 文件?

我想让我的 Gradle 构建使用 Gradle 创建一个发布签名的 apk 文件。

我不确定代码是否正确,或者我在执行 gradle build 时是否缺少参数?

这是我的 gradle 文件中的一些代码:

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

Gradle 构建完成SUCCESSFUL,在我的 build/apk 文件夹中,我只看到 ...-release-unsigned.apk...-debug-unaligned.apk 文件。

关于如何解决这个问题的任何建议?

使用 gradle 文件中的 v1(jar 签名)或 v2(完整 apk 签名)版本签名?此处的解决方案:stackoverflow.com/questions/57943259/…

T
Torello

比以前的答案更简单的方法:

将其放入 ~/.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

Also see the reference for the signingConfigs Gradle DSL


如果你问我最好的方法。在我的项目文件夹/SVN 中没有保存任何内容,我可以签出 10 个版本的项目,而不必担心密钥。
如果您在 Windows 上使用 gradlew,则需要确保将 GRADLE_USER_HOME 定义为环境变量以使其正常工作。我将它设置为项目目录上方的一个目录,并将我的密钥库放在那里。 gradle.properties 中密钥库的路径应使用正斜杠 (/) 或双反斜杠 (\\),而不是 Windows 单反斜杠。要从 Windows 命令提示符创建密钥库,请参阅 stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
路径是相对于 build.gradle 文件所在的位置,还是相对于机器根目录?
这对我有用,也是最简单的。在 gradle.properties 中指定相对于你的模块 build.gradle 的 storeFile,就像 RELEASE_STORE_FILE=../mykeystore 一样。不要添加引号,否则 gradle 会破坏路径
为什么要将它放在您的主 .gradle 目录中?这不会将这些设置应用到您的所有 Android 项目而不是特定项目吗?如果您有两个或更多具有两个或更多密钥库的项目会发生什么?
J
Jan-Terje Sørensen

我设法通过添加此代码并使用 gradle build 进行构建来解决它:

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

这会生成一个签名的发布 apk 文件。


有没有办法让它提示我输入密码?或其他建议将密码排除在我的 git 存储库之外?
我将 build.gradle 编辑为看起来像您的,但运行“构建 > 生成签名的 APK...”仍然给我那个对话框(“请参阅 Gradle 用户指南以获取更多信息。”等)并且没有 APK。
@Semanticer 在终端/提示命令中执行 gradle buildgradlew build
@user672009 您可以将密码放在属性文件中,并使用 .gitignore 将其从存储库中排除。您可以看到此链接。gist.github.com/gabrielemariotti/6856974
@GabrieleMariotti 那仍然留下一个不完整的存储库。更好的方法是创建一个骨架signing.properties,并在提交“git update-index --assume-unchanged signing.properties”之后。但是,这会阻止提交 Futura 编辑。像 sdqali 建议的第一个选项似乎更好。
j
jclehner

请注意,@sdqali 的脚本将(至少在使用 Gradle 1.6 时)在您调用 any 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
    }
}

实施后,installRelease 从任务列表中消失了……为什么?
@caspase 希望我更认真地对待您对假“storePassword”和“keyPassword”的评论。如果不初始化这些属性(例如“”),则不会创建已签名的 *-release.apk,不会显示任何错误,并且您对 PROJECT_NAME/build/apk/ 目录中的 *-release-unsigned.apk 完全感到困惑.男人... :/
感谢您在 buildTypes -> Release 下添加signingConfig 的说明。这为我解决了自动签名问题!
我制作了一个简单的 gradle 插件,在构建发布 apk 时要求输入密码(使用本文中描述的方法,但您不需要定义假的 storePassword 和 keyPassword)。它也可以在 maven Central 中使用。 github.com/alexvasilkov/AndroidGradleSignPlugin
这很棒。请注意,即使是调试版本和 Android Studio 中的“gradle sync”,也需要定义环境变量 KEYSTORE,否则它会给出关于路径为空的错误。
I
IgorGanapolsky

如果您想避免硬编码您的密钥库和build.gradle 中的密码,您可以使用此处说明的属性文件:HANDLING SIGNING CONFIGS WITH GRADLE

基本上:

1) 在 /home/[username]/.signing 中创建一个 myproject.properties 文件,其中包含以下内容:

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']
        }
    }
}

效果很好!谢谢你。必须在 buildTypes {} 部分之前添加此代码,并且该部分必须像往常一样声明signingConfig signingConfigs.release。
最后我找到了解决这个问题的方法。唯一真正帮助我的东西!这应该是公认的答案...
如何在 build.gradle 文件中使用它?
n
not2qubit

使用 git 时使用 Gradle 自动签署应用程序

令人惊讶的是有多少复杂的方法可以做到这一点。这是我自己的方式,我尝试遵守 Google 自己的 recommendation。但是,它们的解释并不完全清楚,因此我将详细描述 Linux 的过程。

描述:

默认 Google instructions 用于在构建期间自动签署应用程序,而不在应用程序开发 (GIT) 路径中保留密码和签名文件,这是相当模糊的。以下是如何执行此操作的明确分步说明。

初步假设:

您在由以下路径指定的目录中有一个名为“MyApp”的应用程序:$HOME/projects/mydev/MyApp。但是,MyApp 目录是由 GIT 使用和控制的。

https://i.stack.imgur.com/ZmPTT.png

问题

我们显然不希望在 GIT 控制的目录中的任何地方都有我们的签名或密码文件,即使我们非常能够使用 .gitignore 等,仍然太冒险并且容易出错。所以我们想要我们的密钥库和签名文件在外面。

解决方案

我们需要做三 (3) 件事:

创建供 Android Studio 使用的密码文件 创建签名密钥文件 编辑模块 build.gradle 文件以使用 (1) 和 (2)。

对于此示例,我们将两个文件命名为:

keystore.properties MyApp-release-key.jks

我们可以把这两个文件放在这里:

cd $HOME/projects/mydev/

(1) 创建keystore密码文件

第一个文件包含使用的明文密码;以及 (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
            ...
        }
    }
}

现在从 shell,您可以使用以下命令重新构建您的应用程序:

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

这应该会生成一个可以在 Google Play 中使用的正确签名的应用程序。

更新:2019-04-02

keytoolsomething 的更新版本告诉您应该使用基于 PKCS12 的密钥文件,而不是我上面使用的原始/默认值。 他们然后继续告诉您应该转换为新的开放式 PKCS12 格式。但是,Android 开发工具似乎还没有为此做好准备,因为如果这样做,您将收到以下奇怪的错误:

com.android.ide.common.signing.KeytoolException:无法从存储“F:\XXX\XXX.jks”读取密钥 XXX:获取密钥失败:给定最终块未正确填充。如果在解密期间使用了错误的密钥,则可能会出现此类问题。

所以不要使用转换后的密钥!


签名配置是否保存在 apk 中,然后任何用户都可以对其进行反编译以获取密码,或者它不会出现在 apk 中?
像魅力一样工作。谢谢,这应该是公认的答案
如果您只想要构建服务器上的密钥库和密码怎么办?使用上面的解决方案,团队中的每个开发人员都需要在他们的本地机器上拥有密钥库。否则 Gradle 项目同步将失败:keystore.properties(没有这样的文件或目录)。
您可以将虚拟 keystore.properties 文件提交到源代码管理,因此在开发机器上构建工作。我已经描述了构建服务器设置 here
关于您上次关于 keytool 生成 PKCS12 密钥库的更新的说明:您可以在 keytool 命令中传递 -storetype JKS 以将密钥库类型设置为 Android 工具所需的 JKS。
P
Paul Verest

就像@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 assembleReleasegradle build


如何在 Windows 中设置路径:密钥库的路径
storeFile file("C:\\Users\\xxxx\\Documents\\yyyy\\mykey.jks") 对吗?
除非您希望 CI 构建失败,否则 if 语句至关重要。
C
Community

(回复上面的user672009。)

如果您想将密码保存在 git 存储库之外,这是一个更简单的解决方案;然而,想要将你的 build.gradle 包含在其中,甚至可以很好地与产品风格一起使用,那就是创建一个单独的 gradle 文件。我们称它为“signing.gradle”(将其包含在您的 .gitignore 中)。就好像它是您的 build.gradle 文件减去与登录无关的所有内容一样。

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

然后在你的 build.gradle 文件中,在“apply plugin: 'android'”下面包含这一行

 apply from: 'signing.gradle'

如果您没有或使用多种口味,请将上面的“flavor1”重命名为“release”,您应该完成了。如果您使用口味继续。

最后将你的风格链接到你的 build.gradle 文件中正确的signingConfig,你应该完成了。

  ...

  productFlavors {

      flavor1 {
          ...
          signingConfig signingConfigs.flavor1
      }

      flavor2 {
          ...
          signingConfig signingConfigs.flavor2
      }
  }

  ...

能不能具体一点。我无法让它运行:“无法解析符号签名配置”。
如果我在 build.gradle 中包含“signing.gradle” - 我被迫在 git 存储库中有一个(否则我收到错误“signing.gradle 不存在”)。如果我将“signing.gradle”放在 git 中,它就达不到目的。我怎样才能让signing.gradle成为可选的?
j
janpio

如果您已经拥有密钥库文件,则可以像在构建命令中添加一些参数一样简单:

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


C
Community

这是对 user672009 的回复和对 sdqali's post 的补充(他的代码将在通过 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 {

        }
    }

}

有没有办法有一些默认值?我的密钥库通常是相同的。 storePassword 通常与 keyPassword 相同,而 keyAlias 通常是小写的项目名称。
@user672009 您始终可以在脚本中使用 Java 代码。
您可能想使用类似这样的东西:keyPassword new String(console.readPassword("Enter key password: ")) 以确保您的密码在输入过程中不显示
这不再起作用,请参阅 github.com/gradle/gradle/issues/1251
C
Community

在较新的 Android Studio 中,有一种非常简单的 GUI 方式,它也可以填充 Gradle 文件。

文件 -> 项目结构模块 -> 选择主模块('app' 或其他自定义名称) 签名选项卡 -> 加图像以添加新配置 在右侧填写数据 OK 并自动创建 Gradle 文件 您将必须手动添加builtTypes{release{}} 内的行 signingConfig signingConfigs.NameOfYourConfig

图片:

https://i.stack.imgur.com/IjzTD.png

https://i.stack.imgur.com/qPuAT.png

两个重要的(!)注意事项:

(编辑 12/15)

要创建签名的 APK,您必须打开 Android Studio 的终端选项卡(主界面底部)并发出命令 ./gradlew assembleRelease 如果您忘记了 keyAlias(我经常发生这种情况),您将不得不启动 Build -> Generate Signed APK 启动进程并查看 Alias 密钥的名称。


不过,这会将您的密码硬编码到 build.gradle 文件中,不是吗?
J
JonasVautherin

如果您像我一样通过命令行构建 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 文件。
J
JP Ventura
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
        }
    }
}

使用 Android Studio 0.5.1、Gradle 1.11 和 Gradle 插件 0.9。
按需创建属性(又名动态属性)已被弃用,并计划在 Gradle 2.0 中删除
A
Andy Shiue

您还可以使用 gradle 的 -P 命令行选项来帮助签名。在你的 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 user guide


W
Willi Mentzel

对于 Kotlin 脚本 (build.gradle.kts)

您不应将签名凭据直接放在 build.gradle.kts 文件中。相反,凭据应该来自不受版本控制的文件。

在找到模块特定的 build.gradle.kts 的位置放置一个文件 signing.properties。不要忘记将它添加到您的 .gitignore 文件中!

签名.properties

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

构建.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")
            // ...
        }
    }
}

n
naufraghi

现在几乎所有平台都提供某种密钥环,因此没有理由留下明文密码。

我提出了一个使用 Python Keyring module(主要是伴随控制台脚本 keyring)和 Groovy ['do', 'something'].execute() feature 的最小包装器的简单解决方案:

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

发布快乐!


C
Community

如果您可以在所有项目中重用相同的配置,@Destil 的答案就很好。或者,Android Studio 附带了一个 local.properties 文件,可以使用它来代替,但它应该是 IDE 生成的,我找不到从 Android Studio 中扩展它的方法。

这是 @jonbo's answer 的变体。该答案允许特定于项目的设置,但会带来一些开发人员开销。具体来说,将 signingConfigs 定义移动到单独的文件中需要大量样板文件——特别是如果您需要为多个项目这样做,这是选择此解决方案而不是 Destil 的主要原因。这可以通过 also 来缓解,包括该行

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 属性的值与调试版本无关。要启用发布版本,请将 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 忽略。


S
SRC

扩展 David Vavra 的答案,创建一个文件 ~/.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
      }
    }
  }

A
Abhinav Gupta

弄清楚这一点我玩得很开心。这是我的演练。

关于如何在 IntelliJ (v.13.1.4) 中创建 gradle 构建文件的 A 到 Z 演练本演练假设您知道如何制作密钥库文件。要使本教程正常工作,您需要将密钥库文件放在 app 文件夹中,并且需要将 zipalign.exe 文件放在“SDK-ROOT\tools”中。该文件通常位于“SDK-ROOT\build-tools”中,在此文件夹下,它将位于最高的 api 文件夹中(alpha 或 beta,我推荐 alpha 版本)。

对于那些希望直接进入这里的人来说,是 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(App)。从这里您将看到选项卡:“属性”、“签名”、“风味”、“构建类型”和“依赖项”,在本演练中,我们将只使用“签名”和“构建类型”。在“构建类型”下(在名称部分)输入您希望识别构建类型配置的任何名称,并在其他 4 个字段中输入您的密钥库信息(将密钥库路径设置为您的应用程序文件夹下的那个)。

在“构建类型”下,在名称字段中输入值“assembleRelease”,“Debuggable”应设置为 false,“Jni Debug Build”应为 false,将“Run Proguard”设置为 true,“Zip Align”设置为 true。这将生成构建文件,但不像上面描述的那样,之后您必须在构建文件中添加一些东西。此处的 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 容器('dependencies')应该在配置文件的底部,而不是在 android DSL 容器内。为了从 IntelliJ 菜单构建依赖项容器,请选择:文件/项目结构。从那里再次选择 Facets,然后选择 Android-Gradle(app)。您将看到与上述相同的 5 个选项卡。选择“依赖项”选项卡并添加所需的依赖项。

完成所有这些操作后,您应该会看到一个类似于本演练顶部的文件的 Gradle 构建文件。要构建签名的 zip 对齐版本,您需要打开 Gradle 任务。您可以通过选择 View/Tool Windows/Gradle 进入此窗口。从这里你可以双击'assembleAssembleRelease.这应该会生成您的可部署 APK。

编译您的版本时可能出现的潜在问题是(但不限于): 您的 Gradle 构建文件位于错误的位置。有两个 Gradle 构建文件;一个在您的应用程序根文件夹中,另一个在应用程序根目录下的 app 文件夹中。您必须使用后者。

您可能还会遇到棉绒问题。 (注意:Android Developer Studio 在发现 Lint 问题方面比 IntelliJ 好得多,当您尝试从菜单选项生成签名 APK 时会注意到这一点)

要解决 lint 问题,您需要将以下 DSL 容器放入 android 容器中(在顶部):

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

把它放在你的 android DSL 容器中会导致在构建文件夹中生成一个错误文件(直接在你的应用程序文件夹下)文件名应该类似于“lint-results-release-fatal.html”这个文件会告诉你发生错误的类。将生成的另一个文件是一个 XML 文件,其中包含与 lint 错误关联的“问题 ID”。文件名应该类似于“lint-results-release-fatal.xml”。在文件顶部附近的某处,您会看到一个节点“问题”,在该节点中您会看到类似于“id="IDOfYourLintProblem"”的内容

要更正此问题,请打开项目中“lint-results-assembleRelease-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}

请注意,抑制 lint 错误并不总是最好的想法,您最好更改导致 lint 错误的代码。

另一个可能发生的问题是,如果您没有为 Gradle HOME 环境变量设置环境变量。此变量名为“GRADLE_HOME”,应设置 gradle 主目录的路径,例如“C:\gradle-1.12”有时您可能还想为“ANDROID_HOME”设置环境变量,将其设置为“YOUR-” SDK-根\sdk'

完成后返回 Gradle 任务窗口并双击 assembleAssembleRelease。

如果一切顺利,您应该能够转到文件夹 app\build\apk 并找到可部署的 APK 文件。


+1 的努力和:'lintOptions { abortOnError false }'
a
argenkiwi

解决同一问题的另一种方法。由于不建议在源代码中存储任何类型的凭据,我们决定在单独的属性文件中设置密钥存储和密钥别名的密码,如下所示:

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

永远不要忘记手动将signingConfig分配给发布构建类型(出于某种原因,我有时会假设它会被自动使用)。此外,启用 proguard 不是强制性的,但值得推荐。

与使用环境变量或请求用户输入相比,我们更喜欢这种方法,因为它可以从 IDE 中完成,通过切换到 realease 构建类型并运行应用程序,而不必使用命令行。


Gradle 不使用这个编译: props = new Properties();无法设置只读属性“props”的值
你是对的@m3n0R。我编辑了我的回复,以反映我们必须在我们的应用程序中引入的修复,因此它仍然可以使用最新版本的 Gradle 进行编译。基本上, props 必须声明为局部变量。
使用云 CI/CD 工具如何实现这一点……/path/to/keystore 和 /path/to/secure.props 让我感到震惊……不过,谢谢。
A
Ahamadullah Saikat

Android Studio 转到文件 -> 项目结构或按 Ctrl+Alt+Shift+S

查看图片

https://i.stack.imgur.com/OqYoz.png

点击确定

然后,signingConfigs 将在您的 build.gradle 文件中生成。

https://i.stack.imgur.com/bzHTd.png


这正是你不想做的。这样,您的所有密码都是明文形式并且是项目的一部分,并且很容易意外包含,即使在您的分布式构建中也是如此。
u
user1506104

现在是 2019 年,我需要使用 V1(jar 签名)或 V2(完整 APK 签名)对 APK 进行签名。我用谷歌搜索“生成签名的 apk gradle”,它把我带到了这里。所以我在这里添加我的原始解决方案。

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

我原来的问题:How to use V1 (Jar signature) or V2 (Full APK signature) from build.gradle file


W
Willi Mentzel

对于 Groovy (build.gradle)

您不应将签名凭据直接放在 build.gradle 文件中。相反,凭据应该来自不受版本控制的文件。

在找到模块特定的 build.gradle 的位置放置一个文件 signing.properties。不要忘记将它添加到您的 .gitignore 文件中!

签名.properties

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

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

B
Botond Kopacz

我有几个问题,我把下面这行放在错误的地方:

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

确保将 signingConfigs 部分放在 android 部分中:

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

代替

android
{
    ....
}

signingConfigs {
   release {
        ...
   }
}

很容易犯这个错误。


c
cprcrack

为了补充其他答案,您还可以将 gradle.properties 文件与 build.gradle 一起放在您自己的模块文件夹中,以防您的密钥库特定于一个项目。


a
ayyb1988

我在 Ubuntu14.04 工作。 vim ~/.bashrc 并添加 export ANDROID_KEYSTORE= export 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 {

        }
    }

}

恕我直言,这似乎是最好的解决方案,但不幸的是 it stopped working on newer versions of Gradle: System.console() 返回 null
I
Intrications

另一种方法是定义一个仅在发布版本上运行的任务。

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

以下对我来说似乎更可取:stackoverflow.com/a/19130098/3664487这两种方法如何比较?
C
Community

您可以从命令行请求密码:

...

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 将始终要求输入密码,即使您正在构建调试版本(参见 How to create a release signed apk file using Gradle?)。幸运的是,正如我上面所展示的,这是可以克服的。


由于stackoverflow.com/questions/33897802/…,我之前的回答遇到了问题。我已经修改了我的答案以消除这个问题。
@Haroon,它从 15 年 11 月 24 日开始工作。社区或许可以帮助您解决问题,但您需要提供更多详细信息。
我喜欢这个解决方案,因为它避免将密码以明文形式放在文本文件中,但 System.console().readLine 由于 this 烦人的问题在 gradle 中不起作用。
@morpheus,我从来没有遇到过问题。以上对我有用。
我认为您从 IDE 中运行脚本。如果脚本是从终端运行的,您将看到错误。但感谢这个答案。这就是我一直在寻找的。
M
Mahozad

这是与 Willi Mentzel's answer 不同的 Kotlin build scripts (build.gradle.kts) 的另一个答案。

它尝试从 local.properties 文件中读取,回退到操作系统环境变量。它在 GitHub Actions 等 CI 中特别有用(您可以在存储库设置中创建环境机密)。

请注意,我使用的是 Kotlin 1.6.10 和 Gradle 7.4.2 以及 Android Gradle Plugin (AGP) 7.0.4。

import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
// ...

val environment = System.getenv()
fun getLocalProperty(key: String) = gradleLocalProperties(rootDir).getProperty(key)
fun String.toFile() = File(this)

android {
    signingConfigs {
        create("MySigningConfig") {
            keyAlias = getLocalProperty("signing.keyAlias") ?: environment["SIGNING_KEY_ALIAS"] ?: error("Error!")
            storeFile = (getLocalProperty("signing.storeFile") ?: environment["SIGNING_STORE_FILE"] ?: error("Error!")).toFile()
            keyPassword = getLocalProperty("signing.keyPassword") ?: environment["SIGNING_KEY_PASSWORD"] ?: error("Error!")
            storePassword = getLocalProperty("signing.storePassword") ?: environment["SIGNING_STORE_PASSWORD"] ?: error("Error!")
            enableV1Signing = true
            enableV2Signing = true
        }
    }

    buildTypes {
        release {
            signingConfig = signingConfigs["MySigningConfig"]
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

如前所述,您可以在项目的根目录中拥有一个 local.properties 文件,其中包含属性值:

signing.keyAlias=My key
signing.keyPassword=zyxwvuts
signing.storePassword=abcdefgh
signing.storeFile=C\:\\Users\\Mahozad\\keystore.jks

...或者您可以在您的操作系统上设置/创建环境变量;例如创建一个名为 SIGNING_KEY_ALIAS 的环境变量运行:

Windows 命令提示符:setx SIGNING_KEY_ALIAS "我的密钥"

Linux 终端:export SIGNING_KEY_ALIAS="我的密钥"

注意:如其他答案所述,请勿将 local.properties 文件添加到版本控制系统(如 Git),因为它会将密码等秘密信息公开(如果它是公共存储库)。

使用此答案提到的 3 种方式之一生成您的 APK。


c
chenop

使用 react-native-config 包在 React-Native 中添加我的方法。
创建一个 .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')
        }
    }

D
Dewsworld

就我而言,我将错误的 apk 上传到另一个应用程序的版本。