在不将密钥库信息放入build.gradle文件的情况下签署APK

197

我正在尝试设置签名流程,使得密钥库、密码和密钥密码不会存储在项目的build.gradle文件中。

目前我的build.gradle文件中有以下内容:

android {
    ...
    signingConfigs {
        release {
            storeFile file("my.keystore")
            storePassword "store_password"
            keyAlias "my_key_alias"
            keyPassword "key_password"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release            
        }
    }
}

它的功能完美,但我不能storePasswordkeyPassword的值放在我的存储库中。我也不想把storeFilekeyAlias放在那里。

是否有一种方法可以修改build.gradle文件,以便它可以从某些外部来源(例如仅驻留在我的计算机上的文件)获取密码?

当然,修改后的build.gradle文件应该在任何其他计算机上可用(即使该计算机没有访问密码)。

我正在使用Android Studio,在Mac OS X Mavericks上使用,如果这很重要。


当然,修改后的build.gradle应该可以在任何其他计算机上使用(即使计算机没有访问密码)。如果数据不在build.gradle中,则必须有其他东西来代替build.gradle,无论是环境变量的调整(根据一个答案),属性文件(根据另一个答案)还是其他一些手段。如果您不愿意在build.gradle之外拥有任何东西,那么根据定义,所有签名信息都必须buid.gradle内部。 - CommonsWare
2
@CommonsWare 您说得对。虽然我没有明确说明我想要在build.gradle中严格限制任何内容,但我确实说过build.gradle可以从某些外部来源(比如仅驻留在我的计算机上的文件)获取密码。 - Bobrovsky
可能是重复的问题:如何使用Gradle创建签名发布APK文件? - user2768
我已将其标记为重复问题,链接为https://dev59.com/HWMl5IYBdhLWcg3wiXZ7,基于http://meta.stackoverflow.com/questions/311044/internal-link-only-answers-are-advisable/。 - user2768
15个回答

1

In `keystore.properties

    STORE_FILE = app.keystore
    KEY_ALIAS = app_alias
    STORE_PASSWORD = your_password
    KEY_PASSWORD = your_password

app/build.gradle.kts 中添加

...

android {
  ...
  signingConfigs {
    create("release") {
    // Load keystore
    val keystoreProperties = Properties().apply{
        load(File("keystore.properties").reader())
    }
    storeFile = File(keystoreProperties.getProperty("STORE_FILE"))
    storePassword = keystoreProperties.getProperty("STORE_PASSWORD")
    keyAlias = keystoreProperties.getProperty("KEY_ALIAS")
    keyPassword= keystoreProperties.getProperty("KEY_PASSWORD")
   }
  }
  buildTypes {
    release {
      signingConfig signingConfigs.release
    }
  }
}

1

除非您使用CI工具,否则在文本文件中以明文存储凭据是一个坏主意,即使该文件不在版本控制下。

我知道这是常见做法(甚至官方文档也提到了),但您甚至不会想到将个人电子邮件的密码存储在文本文件中,为什么要用您的应用程序呢?

我的方法是有一个简单的命令来查询两个密码并构建发布,同时尽可能保持我的build.gradle干净。例如:

Key store password:
Key password:

我看了其他答案,但它们要么 a) 明文存储凭据,要么 b) 不起作用,或者 c) 过于复杂。


  • 将此签名配置添加到 build.gradle 文件中:

    android {
        ...
        signingConfigs {
            release {
                storeFile file(findProperty('keystore_path') ?: '默认路径')
                storePassword findProperty('keystore_pw')
                keyAlias findProperty('key_alias')
                keyPassword findProperty('key_pw')
            }
        }
        ...
    
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }
    
  • 在项目目录中运行以下命令(编辑 /PATH/TO/KEYSTORE.jksKEY_ALIAS):

    echo -n 密钥库密码: && read -s storepw && echo && \
    echo -n 密钥密码: && read -s keypw && echo && \
    ./gradlew assembleRelease -Pkeystore_path='/PATH/TO/KEYSTORE.jks' -Pkeystore_pw=$storepw -Pkey_alias='KEY_ALIAS' -Pkey_pw=$keypw
    

  • 0

    您可以通过命令行请求密码:

    ...
    
    signingConfigs {
      if (gradle.startParameter.taskNames.any {it.contains('Release') }) {
        release {
          storeFile file("your.keystore")
          storePassword new String(System.console().readPassword("\n\$ Enter keystore password: "))
          keyAlias "key-alias"
          keyPassword new String(System.console().readPassword("\n\$ Enter keys password: "))
        } 
      } else {
        //Here be dragons: unreachable else-branch forces Gradle to create
        //install...Release tasks.
        release {
          keyAlias 'dummy'
          keyPassword 'dummy'
          storeFile file('dummy')
          storePassword 'dummy'
        } 
      }
    }
    
    ...
    
    buildTypes {
      release {
    
        ...
    
        signingConfig signingConfigs.release
      }
    
      ...
    }
    
    ...
    

    这个答案之前已经出现过:https://dev59.com/HWMl5IYBdhLWcg3wiXZ7#33765572


    虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅链接的答案可能会失效。- 来自审查 - mkobit
    1
    @mkobit,这是Stack Overflow上的内容链接!当然,我可以复制并粘贴链接内容,但那会导致重复内容。因此,我认为,如果我错了,请纠正我,发布链接是最好的解决方案。任何“链接页面会更改”的论点都应该被驳回,因为这里的内容也可能会更改。我强烈反对你删除的解决方案!因为链接内容提供了一个很好的解决方案。 - user2768
    我认为问题在于这仍然是一个“仅链接”答案。我认为解决方案是将其发布为评论,标记问题为重复,或在此处编写新答案以解决问题。 - mkobit
    在某些情况下,应该鼓励“仅链接”回答。尽管如此,我已经遵循了您的建议并复制了内容。(复制的内容显然存在问题,因为某些内容可能会更新,而其余内容可能不会更新。) - user2768
    确实,我刚刚更新了答案,重复内容正在引起问题!如果有反对仅链接回答的政策,那么应该适应考虑这种边缘情况。 - user2768
    显示剩余2条评论

    0

    这是另一个关于 Kotlin构建脚本 (build.gradle.kts) 的答案,不同于 Anand Damodaran的回答

    它尝试从 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 "My key"
    • Linux 终端: export SIGNING_KEY_ALIAS="My key"

    0

    我的密码包含一个特殊字符,即美元符号$,我不得不在gradle.properties文件中进行转义。之后,签名就可以正常工作了。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接