73

我很想将我的项目迁移到 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

所以我认为productFlavorsGradle 脚本的 .* 部分不是放置代码签名配置的正确位置。

4

6 回答 6

97

您可以signing config为每个flavorin声明buildType。这是我的 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块之后,我的意思是顺序很重要。

于 2016-01-28T09:27:10.153 回答
51

根据用户指南,支持风格的签名配置。

这里的问题与 signingConfigs 对象的范围有关。我只是将它分配给productFlavors块内的变量,但在flavor1风味块之外以解决问题:

productFlavors {
    def flavor1SigningVariable = signingConfigs.flavor1

    flavor1 {
        ...
        signingConfig flavor1SigningVariable
        ...
    }
于 2013-06-12T20:24:39.847 回答
9

Android 的 gradle 插件仅支持每种构建类型的签名,而不是每种风格的签名。这样做的原因是任何给定的变体(构建类型 + 风味)只能由一个密钥签名,但可以是多个风味组的组合。例如,您的风味组可能是 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只是告诉 gradlerelease-beta应该是release构建类型的副本,仅使用不同的密钥签名。

于 2013-06-11T12:59:22.510 回答
3

也许是另一个有趣的解决方案,具有动态风味签名配置和其他优势

  • 我可以在 gradle 中定义风格的应用程序 ID 和应用程序名称(很清楚,每种风格只有 2 行),但我不想定义单独的签名配置(添加风格时 gradle 文件会太长)
  • 我也不想因为提交而将敏感的签名信息放在 gradle 中
  • 额外的好处是调试版本有另一个应用程序 ID 和应用程序名称。

.gitignore

...
/keystore.properties

.keystore.properties

storeFile=../mystore.jks
storePassword=...

keyAliasFlavor1=...
keyPasswordFlavor1=...

keyAliasFlavor2=...
keyPasswordFlavor2=...

应用程序/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)
    }
}

应用程序/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    ...
    <application android:label="${appNameBase}${appNameSuffix}" ...>
        ...
    </application>
</manifest>
于 2021-01-20T14:35:37.017 回答
0

Gms在和Hms构建之间拆分签名配置

Gms只是为了将来的参考,如果有人必须在和Hms构建之间拆分他们的签名配置。

这增加了此处列出的答案:
也许是另一个有趣的解决方案,具有动态风味签名配置和其他优势


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

于 2022-02-04T11:46:23.460 回答
0

这是ashakirov答案的 Kotlin DSL 等效项:

// See https://stackoverflow.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"]
            //     }
            // }
        }
    }
}
于 2022-02-18T13:40:26.943 回答