如何在Gradle中获取当前的flavor

83

我的应用有两种产品味道:

productFlavors {
    europe {
        buildConfigField("Boolean", "BEACON_ENABLED", "false")
    }

    usa {
        buildConfigField("Boolean", "BEACON_ENABLED", "true")
    }
}

现在我想在一个任务中获取当前口味名称(我在Android Studio中选择的哪一个),以更改路径:

task copyJar(type: Copy) {
    from('build/intermediates/bundles/' + FLAVOR_NAME + '/release/')
}

如何在Gradle中获取FLAVOR_NAME?

谢谢


没有“当前风味”。Gradle构建文件正在构建构建过程的对象模型。它不是一个解释脚本,只有在进行构建并知道“当前风味”时才会使用。 - CommonsWare
2
一定有一种方法可以检索该值,因为它会在buildDir中更改路径。 - Giulio Bider
你需要按照azertiti的回答所示进行操作:配置所有的构建变体。 - CommonsWare
12
@CommonWare,您一直在告诉人们这个问题。使用Android Studio和Gradle使人们认为他们的任务应该能够知道当前选择的值,并且在Gradle构建完其模型后可以被任务使用。是的,这个问题有缺陷,如果你想要严谨的话,它不是Gradle,看到你对此的回答现在很滑稽,所以,请利用您广泛的Gradle知识,超越这个问题的缺陷,当一个任务,在.gradle文件中定义时,如何知道选定了哪个变量当运行任务/命令?我相信这就是问题所在。 \o/ - Hunter-Orionnoir
1
@CommonsWare(我并不是说你的回应很滑稽!在重新阅读我的评论后,我发现它可能有攻击性。但这不是我的意图。在学习将Gradle集成到Android Studio中时,由于其中已经包含了代码,因此解释/期望状态变得非常普遍和令人沮丧,以至于现在对我来说已经是滑稽可笑的了。:P我已经读了它100次,但直到我正面与它搏斗并接受它,我不知道大多数人是否会明白,除非他们也亲身感受到了这道难关。 - Hunter-Orionnoir
显示剩余2条评论
14个回答

107

如何获取当前口味名称

我开发了以下函数,可以返回当前口味名称:

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern

    if( tskReqStr.contains( "assemble" ) ) // to run ./gradlew assembleRelease to build APK
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else if( tskReqStr.contains( "bundle" ) ) // to run ./gradlew bundleRelease to build .aab
        pattern = Pattern.compile("bundle(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else
    {
        println "NO MATCH FOUND"
        return ""
    }
}

您还需要

import java.util.regex.Matcher
import java.util.regex.Pattern

在您的脚本开始处。

在Android Studio中,通过编译“Make Project”或“Debug App”按钮实现此功能。

如何获取当前构建变体

def getCurrentVariant() {
    Gradle gradle = getGradle()
    String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern

    if (tskReqStr.contains("assemble"))
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher(tskReqStr)

    if (matcher.find()){
        return matcher.group(2).toLowerCase()
    }else{
        println "NO MATCH FOUND"
        return ""
    }
}

如何获取当前风味的applicationId

一个类似的问题可能是:如何获取applicationId?在这种情况下,没有直接的方法来获取当前风味的applicationId。然后我开发了一个gradle函数,使用上面定义的getCurrentFlavor函数,如下所示:

def getCurrentApplicationId() {
    def currFlavor = getCurrentFlavor()

    def outStr = ''
    android.productFlavors.all{ flavor ->

        if( flavor.name==currFlavor )
            outStr=flavor.applicationId
    }

    return outStr
}

就是这样了。


3
有没有可能获取当前的applicationId - Volodymyr
2
@Igor:我认为你完全没有理解这个脚本的作用。许多开发人员每天都使用此脚本来获取当前的flavor。没有直接的方法可以获取当前的flavor;调用_getGradle().getStartParameter().getTaskRequests()_会得到类似于_generateEuropeDebugSources_或_generateEuropeReleaseSources_(如果_europe_是当前的flavor),具体取决于当前的构建类型;然后Pattern类提取flavor名称,而不是构建类型。在回复之前,请仔细研究脚本中Pattern类的作用。 - Poiana Apuana
2
我应该在gradle.build文件的哪里调用这个函数?如果我尝试为选择性地应用某些插件调用它,它不起作用。 - rraallvv
2
如果从命令行运行“gradlew build”,似乎无法正常工作。tskReqStr为[DefaultTaskExecutionRequest {args = [build],projectPath ='null'}]。如果从Android Studio构建,则可以正常工作。 - AlanKley
1
同样的问题:tskReqStr = [DefaultTaskExecutionRequest{args=[],projectPath='null'}] - matdev
显示剩余13条评论

28

我使用这个

${variant.getFlavorName()}.apk

格式化文件名输出


14

你应该使用 ${variant.productFlavors[0].name},它可以在IDE和命令行中都获取到productFlavors。


8
如何在具体的口味块中获取“variant”变量? - mohax
3
这段代码需要嵌套在applicationVariants.all { variant ->循环内部。它返回第一个flavor,在执行单个输出构建时才相关。 - Abandoned Cart

7

以下是我之前使用的方法,希望最新的Gradle插件仍然适用。基本上,我遍历了所有的变体,并设置了一个新的输出文件,这与您试图实现的类似。

applicationVariants.all { com.android.build.gradle.api.ApplicationVariant variant ->
    for (flavor in variant.productFlavors) {
        variant.outputs[0].outputFile = file("$project.buildDir/${YourNewPath}/${YourNewApkName}.apk")
    }
}

6
我的解决方案是解析gradle输入参数。
Gradle gradle = getGradle()

Pattern pattern = Pattern.compile(":assemble(.*?)(Release|Debug)");
Matcher matcher = pattern.matcher(gradle.getStartParameter().getTaskRequests().toString());
println(matcher.group(1))

3
java.lang.IllegalStateException: No match found翻译:java.lang.IllegalStateException:没有找到匹配项。 - IgorGanapolsky

5

由于我的风格有些大写字母,因此我稍微修改了Poiana Apuana的答案。

原因
gradle.getStartParameter().getTaskRequests().toString()包含您当前的flavor名称,但第一个字符是大写字母。
然而,通常flavor名称以小写字母开头。因此,我强制将第一个字符更改为小写字母。

def getCurrentFlavor() {
    Gradle gradle = getGradle()
    String taskReqStr = gradle.getStartParameter().getTaskRequests().toString()
    Pattern pattern
    if (taskReqStr.contains("assemble")) {
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    } else {
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
    }
    Matcher matcher = pattern.matcher(taskReqStr)
    if (matcher.find()) {
        String flavor = matcher.group(1)
        // This makes first character to lowercase.
        char[] c = flavor.toCharArray()
        c[0] = Character.toLowerCase(c[0])
        flavor = new String(c)
        println "getCurrentFlavor:" + flavor
        return flavor
    } else {
        println "getCurrentFlavor:cannot_find_current_flavor"
        return ""
    }
}

4
请问为什么我在应用的 build.gradle 文件中使用 gradle.getStartParameter().getTaskRequests().toString() 获取到的值为空,即 [ ]? - gaurav24

4

使用:

${variant.baseName}.apk"

这个函数返回当前口味的名称。

android.applicationVariants.all { variant ->
    variant.outputs.all {
        outputFileName = "${variant.baseName}.apk"
    }
}

4

在 gradle 同步完成后,从 .iml 文件中获取 SELECTED_BUILD_VARIANT。您可以使用 xml 解析器来加载它,或者更不可取但可能更快实现的方法是使用正则表达式来查找。

<facet type="android" name="Android">
  <configuration>
    <option name="SELECTED_BUILD_VARIANT" value="your_build_flavorDebug" />
        ...

(未经测试,大致如下:)

/(?=<name="SELECTED_BUILD_VARIANT".*value=")[^"]?/

非常感谢。这真的救了我的命。 - Rada Bogdan

2

您可以使用 gradle.startParameter.taskNames[0]


gradle.startParameter.taskNames[0].contains("debug") - 无法在 null 对象上调用 contains() 方法 - user924
这在同步时会失败,所以必须用一些 if 包装起来。 - Alex Cohn
由于您可以调用“./gradlew aD”来为“flavor”“assembleDebug”进行编译,因此未按预期工作,在这种情况下返回的“flavor”是“aD”,而不是“assembleDebug”。 - mtrakal

2
只需在您的build.gradle应用级别)中添加以下内容。
def getCurrentFlavour() {
  Gradle gradle = getGradle()
  String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
  print(tskReqStr.toString())

  Pattern pattern;
  if( tskReqStr.contains( "assemble" ))
    pattern = Pattern.compile("assemble(\\w+)(Release|Staging|Debug)")
  else
    pattern = Pattern.compile("generate(\\w+)(Release|Staging|Debug)")
  Matcher matcher = pattern.matcher( tskReqStr )
  if( matcher.find() ) {
    def value = matcher.group(1).toLowerCase()
    return value
  } else {
    return "";
  }
}

现在在android标签内部,
android {  
// android tag starts
 defaultConfig {
  - - - - - - - - 
  - - - - - - - - 
 }
 - - - - - - - - 
 - - - - - - - - 
 
 def flavourName = getCurrentFlavour()
  if (flavourName == "Dev") {
    println("This is Dev")
   } else if (flavourName == "Staging") {
    println("This is Staging")
   } else if (flavourName == "Production") {
    println("This is Production")
   } else {
    println("NA")
   }
// android tag ends
}

现在,同步并构建您的项目。

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