使用 gradle 签署产品风味
Posted
技术标签:
【中文标题】使用 gradle 签署产品风味【英文标题】:Signing product flavors with gradle 【发布时间】:2013-06-07 02:08:47 【问题描述】:我很想将我的项目迁移到 gradle。我的一个项目有多种产品风格,每个产品都必须在其发布版本中使用不同的signingConfig
签名。所以这是我到目前为止所尝试的:
buildscript
...
apply plugin: 'android'
android
compileSdkVersion 17
buildToolsVersion '17'
signingConfigs
flavor1
storeFile file("keystore")
storePassword "secret"
keyAlias "aliasForFlavor1"
keyPassword "secretFlavor1"
flavor2
storeFile file("keystore")
storePassword "secret"
keyAlias "aliasForFlavor2"
keyPassword "secretFlavor2"
productFlavors
flavor1
signingConfig signingConfigs.flavor1
flavor1
signingConfig signingConfigs.flavor2
dependencies
...
当我运行gradle build
时,我收到groovy.lang.MissingFieldException
和以下错误消息:
No such field: signingConfigs for class: com.android.build.gradle.internal.dsl.GroupableProductFlavorFactory
所以我假设 Gradle 脚本的 productFlavors
.* 部分不是放置代码签名配置的正确位置。
【问题讨论】:
解决方案在这里运行良好:***.com/a/40124853/3256989 【参考方案1】:您可以为buildType
中的每个flavor
声明signing config
。这是我的 gradle 文件,用于使用不同的密钥库发布签名风格。
android
signingConfigs
configFirst
keyAlias 'alias'
keyPassword 'password'
storeFile file('first.keystore')
storePassword 'password'
configSecond
keyAlias 'alias'
keyPassword 'password'
storeFile file('second.keystore')
storePassword 'password'
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig
minSdkVersion 14
targetSdkVersion 23
productFlavors
flavor1
applicationId "com.test.firstapp"
flavor2
applicationId "com.test.secondapp"
buildTypes
release
productFlavors.flavor1.signingConfig signingConfigs.configFirst
productFlavors.flavor2.signingConfig signingConfigs.configSecond
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
buildTypes
块应该放在productFlavors
块之后,我的意思是顺序很重要。
【讨论】:
@almaz_from_kazan 我最初是这样做的,有一个debug productFlavors.flavor1.signingConfig signingConfigs.configFirst
,但它没有接收到signingConfigs,所以我在没有productFlavors.flavor1.signingConfig signingConfigs.configFirst
的情况下切换到debug.initWith(buildTypes.release) debug
,并且签名现在可以按预期进行调试构建。谢谢!
Android 为调试版本添加了默认的signingConfig
。通过传递null
将其删除,如下所示:buildTypes debug signingConfig null
。通过这样做,您将signingConfig
委托给产品风味。
好答案,值得注意的是buildTypes
必须在 productFlavors
之后。
运行良好...确保从您的发布配置中删除“signingConfig signingConfigs.release”,否则其他配置不会覆盖它...我认为他们会覆盖它,我可以使用它作为默认值。
这还能用吗?如果我之后迭代 applicationVariants
,所有构建类型都具有在最后一个构建类型中指定的相同签名配置。【参考方案2】:
根据user guide,支持flavors 的signingConfigs。
这里的问题与 signingConfigs 对象的范围有关。我只是将它分配给 productFlavors
块内的变量,但在 flavor1
风味块之外解决问题:
productFlavors
def flavor1SigningVariable = signingConfigs.flavor1
flavor1
...
signingConfig flavor1SigningVariable
...
【讨论】:
这真的不应该是必需的。我提交了code.google.com/p/android/issues/detail?id=64701 来跟踪这个。 解决方案似乎在 Gradle v2.4 中被破坏 在我的情况下,添加 android.buildTypes.debug.signingConfig = null;和 android.buildTypes.relese.signingConfig = null;清除基础签名。这意味着 buildTypes 中的signingConfig 会以某种方式覆盖signingConfig。甚至是 Android 自动创建的默认值。例如,您可以通过打印 android.buildTypes.debug.signingConfig 来检查它 如果你想用两种不同的签名配置来获得这种风格怎么办?发布/调试?我认为这种方式更优雅:***.com/a/35057525/2557258 感谢android.buildTypes.debug.signingConfig = null;
,我浪费了整个下午才看到那条小评论。可能值得将其添加到主要响应中。【参考方案3】:
Android 的 gradle 插件仅支持按构建类型签名,而不支持按风味签名。这样做的原因是任何给定的 variant(构建类型 + 风味)只能由一个密钥签名,但可以是多个风味组的组合。例如,您的风味组可以是 cpu (x86/arm) 和版本(免费/付费),这就是四种不同的变体。
您正在寻找的解决方案是为您的不同发行版本创建单独的构建类型。例如,您的构建类型可能是debug
、release
、release-beta
,如下所示:
...
android
...
buildTypes
debug
signingConfig signingConfigs.debug
release
signingConfig signingConfigs.release
release-beta
initWith release
signingConfig signingConfigs.release-beta
上面的 initWith
只是告诉 gradle release-beta
应该是 release
构建类型的副本,仅使用不同的密钥签名。
【讨论】:
您实际上可以将buildTypes
放在productFlavors
中(不过我不确定这是否是新事物)
@pjco 将 buildTypes
放入 productFlavors
听起来像是我的这个问题的有用解决方案 - ***.com/q/30898611/383414 - 如果你有时间看看
@pjco 是的,我做到了builtTypes release productFlavors.pro.versionCode 1
【参考方案4】:
也许是另一个有趣的解决方案,具有动态风味签名配置和其他优势
我可以在 gradle 中定义风格的应用程序 ID 和应用程序名称(很清楚,每种风格只有 2 行),但我不想定义单独的签名配置(添加风格时 gradle 文件会太长) 我也不希望因为提交敏感签名信息而将其放在 gradle 中 额外优势是调试版本具有另一个应用 ID 和应用名称。.gitignore
...
/keystore.properties
.keystore.properties
storeFile=../mystore.jks
storePassword=...
keyAliasFlavor1=...
keyPasswordFlavor1=...
keyAliasFlavor2=...
keyPasswordFlavor2=...
app/build.gradle
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(rootProject.file('keystore.properties')))
android
...
buildTypes
debug
...
manifestPlaceholders = [appNameSuffix: " Dev"]
applicationIdSuffix ".dev"
release
...
manifestPlaceholders = [appNameSuffix: ""]
productFlavors.all flavor ->
flavor.signingConfig = android.signingConfigs.create("$flavor.name")
flavor.signingConfig.storeFile = rootProject.file(keystoreProperties["storeFile"])
flavor.signingConfig.storePassword = keystoreProperties["storePassword"]
flavor.signingConfig.keyAlias = keystoreProperties["keyAlias$flavor.name"]
flavor.signingConfig.keyPassword = keystoreProperties["keyPassword$flavor.name"]
productFlavors
Flavor1
applicationId "..."
manifestPlaceholders = [appNameBase: "MyApp 1"]
Flavor2
applicationId "..."
manifestPlaceholders = [appNameBase: "MyApp 2"]
// ... and many other flavors without taking care about signing configs
// (just add two lines into keystore.properties for each new flavor)
app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
...
<application android:label="$appNameBase$appNameSuffix" ...>
...
</application>
</manifest>
【讨论】:
动态创建signingConfig正是我想要的!谢谢 正是我需要的。我们使用它在 GMS 和 HMS 之间拆分我们的签名配置 ---> productFlavors.all flavor -> if (flavour.name.toLowerCase() == "gms") signingConfig signingConfigs.debug if (flavour.name. toLowerCase() == "hms") signingConfig signingConfigs.releaseHms 【参考方案5】:在Gms
和Hms
构建之间拆分签名配置
如果有人必须在 Gms
和 Hms
构建之间拆分他们的签名配置,仅供将来参考。
这增加了此处列出的答案:可能是另一个有趣的解决方案,具有动态风味签名配置和其他优势
build.gradle
选项 1
gradle.startParameter.getTaskNames().each()
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
signingConfigs
release
storeFile file(keystoreProperties["RELEASE_STORE_FILE"])
storePassword keystoreProperties["RELEASE_STORE_PASSWORD"]
keyAlias keystoreProperties["RELEASE_KEY_ALIAS"]
keyPassword keystoreProperties["RELEASE_KEY_PASSWORD"]
releaseHms
storeFile file(keystoreProperties["RELEASE_HMS_STORE_FILE"])
storePassword keystoreProperties["RELEASE_STORE_PASSWORD"]
keyAlias keystoreProperties["RELEASE_KEY_ALIAS"]
keyPassword keystoreProperties["RELEASE_KEY_PASSWORD"]
debug
// use default debug key to sign
buildTypes
release
...
gradle.startParameter.getTaskNames().each task ->
if (task.toLowerCase().contains("gms"))
signingConfig signingConfigs.release
if (task.toLowerCase().contains("hms")
signingConfig signingConfigs.releaseHms
debug
...
gradle.startParameter.getTaskNames().each task ->
if (task.toLowerCase().contains("gms"))
signingConfig signingConfigs.debug
if (task.toLowerCase().contains("hms")
signingConfig signingConfigs.releaseHms
flavorDimensions "serviceplatform"
productFlavors
hms
dimension "serviceplatform"
applicationIdSuffix ".huawei"
versionNameSuffix "-huawei"
gms
dimension "serviceplatform"
applicationIdSuffix ".android"
sourceSets
main
res.srcDirs = [
"src/main/res",
"src/main/res/layout/toolbar",
"src/main/res/layout/fragment",
"src/main/res/layout/activity"
]
gms
java.srcDir("src/gms/java")
hms
java.srcDir("src/hms/java")
选项 2
productFlavors.gms.signingConfig
确保您的 flavorDimensions
在 buildTypes
之前
flavorDimensions "serviceplatform"
productFlavors
hms
...
gms
...
buildTypes
release
...
productFlavors.gms.signingConfig signingConfigs.release
productFlavors.hms.signingConfig signingConfigs.releaseHms
debug
...
productFlavors.gms.signingConfig signingConfigs.debug
productFlavors.hms.signingConfig signingConfigs.releaseHms
【讨论】:
【参考方案6】:这是 ashakirov 答案的 Kotlin DSL 等价物:
// See https://***.com/q/60474010
fun getLocalProperty(key: String) = gradleLocalProperties(rootDir).getProperty(key)
fun String?.toFile() = file(this!!)
// Could also use System.getenv("VARIABLE_NAME") to get each variable individually
val environment: Map<String, String> = System.getenv()
android
signingConfigs
create("MyFirstConfig")
keyAlias = getLocalProperty("signing.keyAlias") ?: environment["SIGNING_KEY_ALIAS"]
storeFile = (getLocalProperty("signing.storeFile") ?: environment["SIGNING_STORE_FILE"]).toFile()
keyPassword = getLocalProperty("signing.keyPassword") ?: environment["SIGNING_KEY_PASSWORD"]
storePassword = getLocalProperty("signing.storePassword") ?: environment["SIGNING_STORE_PASSWORD"]
enableV1Signing = true
enableV2Signing = true
create("MySecondConfig")
keyAlias = getLocalProperty("signing.keyAlias2") ?: environment["SIGNING_KEY_ALIAS2"]
storeFile = (getLocalProperty("signing.storeFile2") ?: environment["SIGNING_STORE_FILE2"]).toFile()
keyPassword = getLocalProperty("signing.keyPassword2") ?: environment["SIGNING_KEY_PASSWORD2"]
storePassword = getLocalProperty("signing.storePassword2") ?: environment["SIGNING_STORE_PASSWORD2"]
enableV1Signing = true
enableV2Signing = true
productFlavors
create("flavor1")
// ...
create("flavor2")
// ...
buildTypes
getByName("release")
productFlavors["flavor1"].signingConfig = signingConfigs["MyFirstConfig"]
productFlavors["flavor2"].signingConfig = signingConfigs["MySecondConfig"]
// OR alternative notation
// productFlavors
// getByName("flavor1")
// signingConfig = signingConfigs["MyFirstConfig"]
//
// getByName("flavor2")
// signingConfig = signingConfigs["MySecondConfig"]
//
//
【讨论】:
以上是关于使用 gradle 签署产品风味的主要内容,如果未能解决你的问题,请参考以下文章
在 gradle 中设置 applicationId 以获得组合的产品风味
Android Gradle flavor —— 打造不同风味的app
Android Gradle flavor —— 打造不同风味的app