gradle 动态生成产品风味

63lcw9qa  于 2022-11-14  发布在  其他
关注(0)|答案(4)|浏览(160)

我创建了一个Android应用程序,需要在许多(30+)口味的建设。
我的想法是直接从我的src目录中的文件夹结构生成不同的productFlavors,因为配置总是非常相似的(基本上只是另一个packageName、一个新的启动器图标和一些字符串更改)。
src文件夹如下所示:

└── src
    ├── flavor1
    │   ├── flavor2.keystore
    │   ├── res
    ├── flavor2
    │   ├── res
    │   ├── flavor2.keystore    
    └── main
        ├── AndroidManifest.xml
        ├── java
        └── res

如果我必须手动创建gradle属性,它看起来会像这样:

android {

    ....

    productFlavors {
        flavor1 {
            packageName 'com.example.flavor1'
        }
        flavor2 {
            packageName 'com.example.flavor2'
        }
    }

}

每次我尝试在创建productFlavors配置后更改它时,要么会出现错误,要么更改/添加的内容会被忽略。
这可能是我造成的问题,因为我的Gradle / Groovy经验非常有限,或者这是不可能的。
我通常会得到错误,说GroupableProductFlavorDsl_Decorated不能按我想要的方式操作。
我尝试归档的内容应如下所示:

android {

    ....

    def flavors = getMyFlavorsFromFileSystem()

    productFlavors {

    }

    flavors.each { name, config ->
        productFlavors[name] << config
    }

}

**注意:**我知道这个问题基本上是一个老问题的duplicate,遗憾的是这个问题从未得到回答。由于Gradle对Android世界来说是一个新的问题,我希望从上次提出这个问题以来得到更多的答案,因为现在有更多的开发人员在使用Gradle。
更新日期:

这里我尝试了一些非常简单的方法:

变量1:

android {

    productFlavors {

    }

    productFlavors['flavor1'] << {
        packageName "com.example.flavor1"
    }

    productFlavors['flavor2'] << {
        packageName "com.example.flavor2"
    }
}

/*

A problem occurred evaluating root project 'MyProject'.
> GroupableProductFlavorDsl with name 'flavor1' not found.

*/

变体2:

android {

    productFlavors {

    }

    productFlavors['flavor1'] = {
        packageName "com.example.flavor1"
    }

    productFlavors['flavor2'] = {
        packageName "com.example.flavor2"
    }
}

/*

no error, but does not work

*/

变体3:

android {

    productFlavors {

    }

    productFlavors['flavor1'] = [packageName: "com.example.flavor1"]

    productFlavors['flavor2'] = [packageName: "com.example.flavor2"]
}

/*

no error, but does not work

*/

所有这些都是Gist

rlcwz9us

rlcwz9us1#

通过反复试验解决:

android {

    // let's assume these are return by a function which reads the filesystem
    def myFlavors = [
        flavor1: [
            packageName: "com.example.flavor1"
        ],
        flavor2: [
            packageName: "com.example.flavor2"
        ]
    ]

    productFlavors {
        myFlavors.each { name, config ->
            "$name" {
                packageName config.packageName
            }
        }
    }

}
oipij1gg

oipij1gg2#

我知道这个问题已经有了答案,但我把邹春义的方法和TheHippo结合起来,并加入了我自己的方法。
基本上,在处理flavors时,我们通常使用包含资源的/app/src/下的不同目录。由于目录名与包名相同,因此我只列出了该文件夹下的目录(不包括“main”和“androidTest”)。
下面是我完整的工作脚本:

def map = [:]

new File("./app/src").eachFile() { file->

    def fileName = file.getName()
    if( fileName == "main" || fileName == "androidTest") {
        return
    }

    map.put(fileName, 'com.mypackagename.' + fileName )

}
productFlavors {
    map.each { flavorName, packagename ->
        "$flavorName" {
            applicationId packagename
        }
    }
}

编辑:

  • 还想补充的是,com.mypackagename基本上是所有风格的根路径。
  • 我有一个单独的脚本,它将一个flavor目录复制粘贴到/app/src/文件夹中。
2guxujil

2guxujil3#

由于问题的作者不想分享他阅读文件的代码,我将写我所做的。我把所有的变量名放在一个名为“app/build_variants. txt”的文件中,每个变量一行,如下所示:

flavor1
flavor2
flavor3
flavor4
flavor5

在“app/build.gradle”中:

//...other configs...

android {
    productFlavors {
        new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } }
    }
}

//...other configs

这将产生与以下代码相同的结果:

//...other configs...

android {
    productFlavors {
        flavor1 { resValue "string", "build_variant_name", "flavor1" } 
        flavor2 { resValue "string", "build_variant_name", "flavor2" } 
        flavor3 { resValue "string", "build_variant_name", "flavor3" } 
        flavor4 { resValue "string", "build_variant_name", "flavor4" } 
        flavor5 { resValue "string", "build_variant_name", "flavor5" } 
    }
}

//...other configs

这里的关键是new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } }行。它读取文件“app/build_variants.txt”,并为每一行生成一个产品风味,名称在它读取的行中。$it是它传入的行。它只是groovy的闭包语法。如果你想更深入地理解。我强烈推荐观看@丹尼尔Lew关于groovy和gradle的视频。它太棒了!

tquggr8v

tquggr8v4#

这个答案很晚才给出,但可能对某些人有用。我们有200多种口味,我们只通过一个.json文件来管理它们。
1.在app文件夹中创建 keystoresprojects_info 文件夹。现在在projects_info文件夹中创建projects_info.json文件,并插入每种风格的信息。

  • 将密钥库文件放入密钥库文件夹中。
  • src文件夹中创建不同风格的文件夹,并放置相应的代码/资源。
{
  "projectsInfoJSONArray": [
    {
      "projectVariantName": "project1",
      "versionCode": 1,
      "versionName": "1.0",
      "applicationId": "com.project1",
      "storeFile": "keystores/MyKeyStore1.jks",
      "storePassword": "yourStorePassword",
      "keyAlias": "yourKeyAlias",
      "keyPassword": "yourKeyPassword",
      "isLive": 1
    },
    {
      "projectVariantName": "project2",
      "versionCode": 2,
      "versionName": "1.2",
      "applicationId": "com.project2",
      "storeFile": "keystores/MyKeyStore2.jks",
      "storePassword": "yourStorePassword",
      "keyAlias": "yourKeyAlias",
      "keyPassword": "yourKeyPassword",
      "isLive": 1
    }
  ]
}

1.将此代码添加到应用级别的build.gradle文件中,并将项目与gradle同步。

def applicationDefinitions = []

def projectsInfoFile = file('projects_info/projects_info.json')
def projectsInfoJSON = new JsonSlurper().parseText(projectsInfoFile.text)
def projectsInfoArray = projectsInfoJSON.projectsInfoJSONArray
def projectsInfoMap = [:]
projectsInfoArray.each { projectInfo ->
    projectsInfoMap[projectInfo.projectVariantName] = projectInfo

    applicationDefinitions.add(['name': projectInfo.projectVariantName, 'applicationId': projectInfo.applicationId])
}

applicationDefinitions.each { applicationDefinition ->
    def signingConfig = projectsInfoMap[applicationDefinition['name']]
    if (signingConfig.isLive == 1) android.productFlavors.create(applicationDefinition['name'], { flavor ->
        flavor.applicationId = applicationDefinition['applicationId']
        flavor.versionCode = signingConfig.versionCode
        flavor.versionName = signingConfig.versionName

        flavor.signingConfig = android.signingConfigs.create(applicationDefinition['name'])
        flavor.signingConfig.storeFile = file(signingConfig.storeFile)
        flavor.signingConfig.storePassword = signingConfig.storePassword
        flavor.signingConfig.keyAlias = signingConfig.keyAlias
        flavor.signingConfig.keyPassword = signingConfig.keyPassword
    }) else println "===> " + signingConfig.projectVariantName + " is Not LIVE. Excluding it from build."
}

相关问题