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

How to create a release signed apk file using Gradle?

提问人:Jan-Terje Sørensen 提问时间:8/20/2013 最后编辑:Amanda MartinJan-Terje Sørensen 更新时间:6/5/2023 访问量:375549

问:

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

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

这是我的 / 文件中的一些代码:build.gradlebuild.gradle.kts

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

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

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

Android Gradle APK 发布 android-gradle-plugin

评论

5赞 LF00 6/7/2017
developer.android.com/studio/publish/......
0赞 user1506104 9/16/2019
使用 Gradle 文件中的 v1(jar 签名)或 v2(完整 apk 签名)版本签名?解决方案在这里:stackoverflow.com/questions/57943259/...
0赞 VahidHoseini 4/4/2020
stackoverflow.com/a/61028214/5733853
0赞 Mahozad 4/15/2022
可能相关:使用 gradle 对产品口味进行签名
0赞 KenIchi 6/27/2023
build.gradle.kts解决方案:stackoverflow.com/a/61188101/1562087

答:

286赞 Jan-Terje Sørensen 8/20/2013 #1

我设法解决了它,添加了此代码,并使用以下命令进行构建:gradle build

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

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

评论

36赞 user672009 9/19/2013
有没有办法让它提示我输入密码?或者其他建议将密码排除在我的 git 存储库之外?
4赞 Semanticer 10/6/2013
我编辑了我的build.gradle,使其看起来像您的,但运行“Built > Generate signed APK...“仍然提供我的那个对话框(”有关更多信息,请参阅 Gradle 用户指南“等),但没有 APK。
3赞 Phillip Kamikaze 10/6/2013
@Semanticer 执行或终端/提示命令gradle buildgradlew build
12赞 Gabriele Mariotti 10/7/2013
@user672009,您可以将密码放在属性文件中,并使用 .gitignore 将其从存储库中排除。您可以看到此链接。gist.github.com/gabrielemariotti/6856974
1赞 user672009 10/7/2013
@GabrieleMariotti 这仍然留下了一个不完整的存储库。更好的方法是创建一个框架 signing.properties,并在提交后发出“git update-index --assume-unchanged signing.properties”。但是,这会阻止提交 futura 编辑。像 sdqali 建议的第一个选项似乎更好。
19赞 AChep 10/6/2013 #2

这是对 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 {

        }
    }

}

评论

0赞 user672009 10/11/2013
有没有办法有一些默认值?我的密钥库通常是一样的。storePassword 通常与 keyPassword 相同,keyAlias 通常为小写的项目名称。
0赞 AChep 10/14/2013
@user672009,您始终可以在脚本中使用 Java 代码。
1赞 Alex Semeniuk 2/11/2014
您可能希望使用类似这样的东西:以确保在输入过程中不显示您的密码keyPassword new String(console.readPassword("Enter key password: "))
0赞 SqAR.org 5/8/2020
这不再起作用了,请参阅 github.com/gradle/gradle/issues/1251
72赞 jclehner 10/14/2013 #3

请注意,@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
    }
}

评论

0赞 Kaarel 10/18/2013
实现此功能后,从任务列表中消失了......为什么?installRelease
1赞 vizZ 12/3/2013
@caspase 希望我能更认真地对待你对那个假的“storePassword”和“keyPassword”的评论。如果不初始化这些属性(例如“”),则不会创建已签名的 *-release.apk,不会显示任何错误,并且您对 PROJECT_NAME/build/apk/ 目录中的 *-release-unsigned.apk完全感到困惑。男人。。。:/
0赞 mm2001 12/14/2013
感谢您关于在 buildTypes -> Release 下添加 signingConfig 的说明。这为我解决了自动签名问题!
1赞 Alex Vasilkov 2/28/2014
我制作了一个简单的 gradle 插件,在构建发布 apk 时要求输入密码(使用本文中描述的 mathod,但您不需要定义假 storePassword 和 keyPassword)。它也可以在 maven central 中使用。github.com/alexvasilkov/AndroidGradleSignPlugin
0赞 Jerry101 3/31/2014
这太棒了。请注意,即使是调试版本和 Android Studio 中的“gradle 同步”也需要定义环境变量,否则它会给出路径为 null 的错误。KEYSTORE
68赞 IgorGanapolsky 10/26/2013 #4

如果你想避免在build.gradle中对你的密钥库和密码进行硬编码,你可以使用一个属性文件,如下所述: 使用 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']
        }
    }
}

评论

1赞 theczechsensation 6/23/2014
效果很好!谢谢。此代码必须添加到 buildTypes {} 部分之前,并且该部分必须正常声明 signingConfig signingConfigs.release。
0赞 devnull69 5/3/2016
最后,我找到了解决这个问题的方法。唯一真正帮助我的事情!这个灵魂是公认的答案......
0赞 Bhoomi Zalavadiya 11/1/2021
如何在build.gradle文件中使用它?
570赞 David Vávra 1/9/2014 #5

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

把这个放进去~/.gradle/gradle.properties

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

修改 ,并在代码块中添加以下内容:app/build.gradleandroid {

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


另请参阅 signingConfigs Gradle DSL 的参考

评论

17赞 Frank 1/21/2014
如果你问我,最好的方法。在我的项目文件夹/SVN 中不保存任何内容,我可以签出项目的 10 个版本,而不必担心密钥。
9赞 Anachronist 2/7/2014
如果您在 Windows 上使用 gradlew,则需要确保将 GRADLE_USER_HOME 定义为环境变量才能完成此操作。我将其设置为项目目录上方的一个目录,并将我的密钥库放在那里。gradle.properties 中密钥库的路径应使用正斜杠 (/) 或双反斜杠 (\\),而不是 Windows 单反斜杠。要从 Windows 命令提示符创建密钥库,请参阅 stackoverflow.com/questions/3997748/how-can-i-create-a-keystore
5赞 Prem 3/19/2014
路径是相对于 build.gradle 文件所在的位置,还是相对于计算机根目录?
5赞 Lakshman Chilukuri 10/7/2015
这对我有用,也是最简单的。在 gradle.properties 中,指定相对于模块 build.gradle 的 storeFile,如下所示 RELEASE_STORE_FILE=.。/mykeystore。不要添加引号,否则 gradle 会破坏路径
2赞 Joshua Pinter 9/7/2017
为什么要把它放在你的主目录中?这难道不会将这些设置应用于您的所有 Android 项目而不是特定项目吗?如果您有两个或多个项目,其中包含两个或多个密钥库,会发生什么情况?.gradle
2赞 Botond Kopacz 1/21/2014 #6

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

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

很容易犯这个错误。

28赞 jonbo 2/1/2014 #7

(回复上文 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
      }
  }

  ...

评论

0赞 Amio.io 9/6/2014
你能说得更具体一点吗?我无法让它运行:“无法解析符号签名配置”。
0赞 dev 2/20/2015
如果我在 build.gradle 中包含“signing.gradle”——我被迫在 git 存储库中有一个(否则我会收到错误“signing.gradle 不存在”)。如果我把'signing.gradle'放在git中,它就违背了目的。我怎样才能使包含signing.gradle成为可选的?
12赞 JP Ventura 3/19/2014 #8
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
        }
    }
}

评论

0赞 JP Ventura 3/19/2014
使用 Android Studio 0.5.1、Gradle 1.11 和 Gradle 插件 0.9。
1赞 JP Ventura 3/26/2014
按需创建属性(又称动态属性)已弃用,并计划在 Gradle 2.0 中移除
7赞 naufraghi 3/24/2014 #9

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

我提出了一个简单的解决方案,它使用 Python Keyring 模块(主要是配套的控制台脚本)和围绕 Groovy 功能的最小包装器:keyring['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

祝您发布愉快!

10赞 Andy Shiue 8/5/2014 #10

您也可以使用 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 用户指南

4赞 argenkiwi 8/19/2014 #11

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

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 构建类型并运行应用程序,而不必使用命令行。

评论

1赞 cesards 10/22/2014
Gradle 不使用这个进行编译:props = new Properties();无法设置只读属性“props”的值
0赞 argenkiwi 10/22/2014
你是对的@m3n0R。我编辑了一行回复,以反映我们必须在应用程序中引入的修复程序,以便它仍然可以使用最新版本的 Gradle 进行编译。基本上,props 必须声明为局部变量。
0赞 sirvon 11/9/2014
如何使用云 CI/CD 工具采用....../path/to/keystore 和 /path/to/secure.props 把我扔了......不过谢谢你。
37赞 Gal Bracha 8/20/2014 #12

就像@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
        }
    }
}
....

然后你可以运行 ORgradle assembleReleasegradle build

评论

0赞 reza_khalafi 4/11/2020
如何在 Windows 中设置路径:密钥库的路径
0赞 reza_khalafi 4/11/2020
storeFile file(“C:\\Users\\xxxx\\Documents\\yyyy\\mykey.jks”) 对吗?
1赞 dessalines 3/10/2022
if 语句至关重要,除非您希望 CI 构建失败。
6赞 user2288580 9/13/2014 #13

我在弄清楚这个问题时玩得很开心。这是我的演练。

关于如何在 IntelliJ 中创建 gradle 构建文件的 A 到 Z 演练 (v.13.1.4) 本演练假定您知道如何创建密钥库文件。 要使本教程正常工作,您需要将密钥库文件位于应用程序文件夹中,并且需要将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 个字段中输入您的密钥库信息(设置密钥库路径,即应用程序文件夹下的路径)。

在“Build Types”下,在 name 字段中输入值“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 任务。您可以通过选择“视图”/“工具窗口”/“Gradle”来访问此窗口。 从这里您可以双击“assembleAssembleRelease”。这应该会生成可部署的 APK。

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

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

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

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

将其放在您的 Android DSL 容器中将导致在 build 文件夹(直接在您的应用程序文件夹下)中生成一个错误文件,文件名应类似于“lint-results-release-fatal.html”,此文件将告诉您发生错误的类。将生成的另一个文件是一个 XML 文件,其中包含与 lint 错误关联的“问题 ID”。文件名应类似于“lint-results-release-fatal.xml”。在文件顶部附近的某个地方,你会看到一个节点“issue”,其中你会看到类似于“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-Root\sdk”

完成此操作后,返回 Gradle tasks 窗口,然后双击 assembleAssembleRelease。

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

评论

0赞 Raz Tourgman 6/17/2015
+1 表示努力和: 'lintOptions { abortOnError false }'
1赞 cprcrack 12/29/2014 #14

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

7赞 mkjeldsen 1/26/2015 #15

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

这是@jonbo答案的变体。该答案允许特定于项目的设置,但它会带来一些开发人员开销。具体来说,将定义移动到一个单独的文件中需要大量的样板 - 特别是当你需要为多个项目这样做时,这是选择这个解决方案而不是 Destil 解决方案的主要原因。这可以通过包括线来在一定程度上缓解signingConfigs

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.signingext.signingsigning.gradle

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

当然,VCS应该忽略。signing.gradle

1赞 ayyb1988 4/7/2015 #16

我在 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 {

        }
    }

}

评论

0赞 Antônio Medeiros 6/11/2018
恕我直言,这似乎是最好的解决方案,但不幸的是,它停止了在较新版本的 Gradle 上工作:返回 .System.console()null
17赞 sandalone 6/18/2015 #17

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

  1. File -> Project Structure

  2. Module ->选择主模块(“应用”或其他自定义名称)

  3. Signingtab -> 加图片添加新配置

  4. 在右侧填充数据

  5. 确定并自动创建 Gradle 文件

  6. 您必须手动在里面添加一行signingConfig signingConfigs.NameOfYourConfigbuiltTypes{release{}}

图像:

enter image description here

enter image description here

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

(编辑 12/15)

  1. 要创建已签名的APK,您必须打开Android Studio(主界面底部)的终端选项卡并发出命令./gradlew assembleRelease

  2. 如果您忘记了(我经常发生的情况),则必须启动该过程并查看别名密钥的名称。keyAliasBuild -> Generate Signed APK

评论

2赞 Joshua Pinter 9/7/2017
不过,这会将您的密码硬编码到文件中,不是吗?build.gradle
0赞 Lance Samaria 7/29/2023
Android Studio 中的布局已更改。就是现在File > Project Structure > Modules(located in right pane) > app(located in center pane under Modules) > Signing Configs
1赞 davidpetter 7/27/2015 #18

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

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

评论

0赞 user2768 11/18/2015
以下方法在我看来更可取: stackoverflow.com/a/19130098/3664487 这两种方法如何比较?
1赞 user2768 11/18/2015 #19

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

...

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
  }

  ...
}

...

该块可防止在构建版本时请求密码。尽管无法访问该分支,但它会诱使 Gradle 创建任务。if-then-elseelseinstall...Release

背景故事。正如 https://stackoverflow.com/a/19130098/3664487 所指出的,“Gradle 脚本可以使用 System.console().readLine 方法提示用户输入。不幸的是,Gradle 总是会要求输入密码,即使您正在构建调试版本(参见如何使用 Gradle 创建发布签名的 apk 文件?幸运的是,正如我上面所展示的,这是可以克服的。

评论

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

如果您像我一样通过命令行构建 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"

评论

0赞 Vlad 5/12/2018
哪个是 ?顶级?请添加更多代码build.gradle
0赞 Egis 5/13/2018
澄清一下,这是我正在谈论的文件。app/build.gradle
6赞 SRC 1/17/2017 #21

扩展 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
      }
    }
  }
49赞 not2qubit 4/5/2017 #22

使用 git 时使用 Gradle 自动对应用进行签名

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


描述:

用于自动为应用签名的默认 Google 说明 在构建过程中,不保留密码和签名文件 在您的应用程序开发 (GIT) 路径中,是相当晦涩难懂的。以下是 阐明了如何执行此操作的分步说明。

初始假设:

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

enter image description here

问题

我们显然不希望将我们的签名或密码文件放在任何地方 GIT控制的目录,即使我们非常能够使用等,它仍然太冒险,容易出错。因此,我们希望我们的密钥库和签名文件在外面。.gitignore

溶液

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

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

在此示例中,我们将这两个文件命名为:

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

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

cd $HOME/projects/mydev/

(1) 创建密钥库密码文件

第一个文件包含用于的明文密码;以及 (2) 中 release-key 文件的路径。首先填写此内容,因为它将使下一步的复制粘贴操作更容易。

cd $HOME/projects/mydev/

编辑,使其内容为:keystore.properties

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

这里唯一棘手的部分是.这是在构建期间模块文件中看到的路径。这通常意味着与以下路径相似且相对: 。因此,为了指向该文件,我们需要在此处放置的是:myStoreFileLocationbuild.gradle$HOME/projects/mydev/MyApp/app/build.gradleMyApp-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

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

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

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

评论

0赞 JavierSegoviaCordoba 8/29/2017
signingConfigs 是否保存在 apk 中,然后任何用户都可以反编译以获取密码,或者它没有出现在 apk 中?
2赞 pratham kesarkar 9/5/2017
像魅力一样工作。谢谢,这应该是公认的答案
0赞 Diana Farin 9/8/2017
如果您只需要构建服务器上的密钥库和密码,该怎么办?使用上述解决方案,团队中的每个开发人员都需要在其本地计算机上拥有密钥库。否则,Gradle 项目同步将失败:keystore.properties(没有此类文件或目录)。
1赞 dskrvk 10/22/2017
可以将虚拟文件提交到源代码管理,以便在开发计算机上进行生成工作。我在这里描述了一个构建服务器设置。keystore.properties
2赞 Trevor Halvorson 1/4/2020
关于上次更新的有关生成 PKCS12 密钥库的说明:您可以传入命令,将密钥库类型设置为 Android 工具所需的 JKS。keytool-storetype JKSkeytool
35赞 janpio 11/18/2017 #23

如果您已经有密钥库文件,那么只需向构建命令添加几个参数即可:

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

评论

0赞 alex 7/24/2023
这个解决方案非常优雅。谢谢朋友
4赞 Ahamadullah Saikat 12/12/2017 #24

Android 工作室 转到“文件”-“项目结构”>或按 Ctrl+Alt+Shift+S

查看图片

enter image description here

单击“确定”

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

enter image description here

评论

0赞 not2qubit 12/15/2018
而这正是你不想做的。这样一来,你的所有密码都是明文的,并且是你项目的一部分,并且很容易被意外地包含,即使在你的分布式版本中也是如此。
5赞 user1506104 9/16/2019 #25

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

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

我原来的问题:如何从build.gradle文件中使用V1(Jar签名)或V2(完整APK签名)

0赞 chenop 2/17/2020 #26

使用 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')
        }
    }
0赞 Dewsworld 2/24/2020 #27

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

6赞 Willi Mentzel 4/13/2020 #28

对于 Groovy (build.gradle)

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

将文件signing.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
            // ...
        }
    }
}
14赞 Willi Mentzel 4/13/2020 #29

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

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

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

signing.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")
            // ...
        }
    }
}
3赞 Mahozad 4/15/2022 #30

这是 Kotlin 构建脚本 (build.gradle.kts) 的另一个答案。

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

请注意,我使用的是 Kotlin 1.6.10 和 Gradle 7.4.2 以及 Android Gradle 插件 (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

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

  • Windows 命令提示符:setx SIGNING_KEY_ALIAS "My key"
  • Linux 终端:export SIGNING_KEY_ALIAS="My key"

注意:正如其他答案所提到的,不要将 local.properties 文件添加到您的版本控制系统(如 Git)中,因为它会将您的秘密信息(如密码等)暴露给公众(如果它是公共存储库)。

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