How to apply plugin to only one flavor in gradle?
Asked Answered
C

7

76

I have a multi-flavored, multi-build-typed android project and I want to integrate the NewRelic plugin. But I have to apply it only for one of the customers, thus only for one product flavor.
NewRelic uses instrumentation and the plugin would generate code in other flavors if I applied the plugin there, and that is not permitted for us.

So my question is: How can I use the apply plugin: something command in the gradle file to be applied to only one of my flavors?

Cuirbouilli answered 13/7, 2015 at 9:31 Comment(0)
S
61

Use this code:

if (!getGradle().getStartParameter().getTaskRequests()
        .toString().contains("Develop")){
    apply plugin: 'com.google.gms.google-services'
}

getGradle().getStartParameter().getTaskRequests().toString() returns something like [DefaultTaskExecutionRequest{args=[:app:generateDevelopDebugSources],projectPath='null'}] so as stated in the comments Develop must start with an uppercase.

Spermatophyte answered 11/4, 2017 at 4:34 Comment(10)
This code work. But you need to pay attention that first letter of flavor name should be in UppercaseSensitivity
Didn't worked when clicked assemble from the right side gradle menu... When installed the app manually..Prefect
this almost works for me, but I noticed when type ./gradlew assembleDe that the value in getTaskRequests is also assembleDe - when I expected it to be already expanded to assembleDebugDistichous
The code doesn't work. This prints an empty array "[]" println("${getGradle().getStartParameter().getTaskRequests().toString()}")Wabble
I confirmed @Wabble comment. Seems to work from within Android Studio but not when run from command line. This is all I get: [DefaultTaskExecutionRequest{args=[build],projectPath='null'}]Aylsworth
Not working for me, when I do clean, rebuild, the value that I get is [defaulttaskexecutionrequest{args=[],projectpath='null'}]Aubade
@Distichous did you find a solution to the problem? E.g. running ./gradlew asF instead of ./gradlew assembleFlavor fails the solution proposed by this answer: the task request string contains "asF" but not assembleFlavor. That is a problem when trying to match e.g. "Flavor"!Cotterell
Nope, I got tired of dealing with firebase and now distribute Apks with slackDistichous
Unfortunately, this doesn't seem to work when running tests.Chang
also if you give multiple sets in one command like: ./gradlew assembleFlavor assembleFlavor2, the same inclusion(exclusion is applied to bothLighten
M
17

Tried different solutions, but none of them worked for me. This is what I came up with and seems to work as far as I tested:

build.gradle

productFlavors {
    someFlavorWithGoogleGcm {
        dimension "type"
        applicationId "com.example.withGcm"
        ext.useGoogleGcm = true
    }
    someFlavorWithoutGoogleGcm {
        dimension "type"
        applicationId "com.example.withoutGcm"
    }
}

And outside the configuration, inside the build.gradle file:

android.productFlavors.each { flavor ->
    if (getGradle().getStartParameter().getTaskRequests().toString().toLowerCase().contains(flavor.name) && flavor.ext.useGoogleGcm) {
        println("Building flavor with Google GCM [${flavor.name}] - applying plugin")
        apply plugin: 'com.google.gms.google-services'
    }
}
Manilla answered 21/11, 2018 at 9:15 Comment(6)
This was the only solution that worked for me. However, I changed your if a little bit to if (getGradle().getStartParameter().getTaskNames().stream().filter { it.toLowerCase().contains(flavor.name) }.count() > 0 && flavor.ext.useGoogleGcm)Katharinekatharsis
It does not seem to be executing for me. I don't get the logs somehow and the plugin is just not applied. Added extra logs before the if statement, still no joy.Symer
Seems that using .all instead of .each fixes it.Symer
Failed for me with Gradle 7.0.2, the error was Cannot get property 'shouldMinify' on extra properties extension as it does not exist. So I needed to add the ext.shouldMinify property to all flavors (and set to according values)Sculpin
this 'kinda' works, yes it does only apply the plugin when the ext is present, but for some reason apply plugin: 'com.google.gms.google-services' doesn't generate R.string.default_web_client_idSadomasochism
My guess is the 'com.google.gms.google-services' plugin runs even before any actual build is running to generate R.string.default_web_client_id.Sadomasochism
P
16

I simply used apply plugin: 'com.google.gms.google-services' inside the flavor in app level build.gradle and it works just fine.

productFlavors {
    ..... your other flavors ....
    yourFlv {
        ....
        ....
        apply plugin: 'com.google.gms.google-services'
    }
}

No extra step needed.

Paedo answered 29/8, 2020 at 13:24 Comment(8)
I would suggest others use thisActually
Wow, it really is that simple!Bier
I used it for exact this use case. It worked for me.Instate
Thanks for the complements. If it really helped you, you may go ahead and hit vote up button. That will help others find it easily.Paedo
This works for builds through Android Studio, but didn't work for builds with Jenkins.Alcazar
This is a syntax cheat, the plugin is still got involved when build other product flavor, tested with android gradle plugin version 4.2.0Yodle
good solution simple and easy to use #android I recommend this solution for you allUta
This didn't work for me - plugin applied for all flavors when placed here.Dextrogyrate
I
10
  1. Define variable - def fl
  2. Initialize variable in you Flavours (and/or builds)

        productFlavors {
    
                freeFlavour {
                    (...)
                    fl = "free"
                }
    
                paidFlavour {
                    (...)
                    fl = "paid"
                }
            }
    
  3. Use if statement -

    if (fl == "free") { apply plugin: something }

Irruptive answered 20/9, 2016 at 17:53 Comment(2)
This doesn't seem to work. In my case (let's say I'm calling assembleFree), both blocks are executed so the value of fl is the name of the last declared flavour. Any other ideas?Impi
This will be resolved in configuration time, and since this needs to go all over it, the fl will contain the last value.Beeler
C
6

I found a solution, but it is not the best so far. So I'm not sure anymore, that what I wanted to do initially is possible. The gradle file evaluation and the choosing of the right flavor and build type is in different phases of the gradle build, so what I've done is:

I use a build parameter from the command line. When that paramerer is true, I apply the plugin, when it is not even there, I also apply it (for IDE build). I use Jenkins, so I could write that parameter in the build job.

build.gradle file:

// First we have to attach a task to the project, which will be running first
gradle.projectsEvaluated {
    preBuild.dependsOn(applyNewRelicByProperty)
}

// Then check on the parameter, which comes from the command line
task applyNewRelicByProperty {
    if(!project.hasProperty('compileNewRelic')) {
        // NewRelic on: 'compileNewRelic' property not set, so running from IDE.
        apply plugin: 'newrelic'
    } else if(project.hasProperty('compileNewRelic') && project.getProperties().get('compileNewRelic').equals('true')) {
        // NewRelic on: 'compileNewRelic' property is set and it is 'true'.
        apply plugin: 'newrelic'
    } else {
        // NewRelic off
        println("No NewRelic")
    }
}

And you have to run the gradle build by this:

assembleYourApp -PcompileNewRelic=true
Cuirbouilli answered 15/7, 2015 at 12:26 Comment(1)
This does not work for me as of today. Apparently, the build.gradle parser looks for apply statements before even evaluating project, hence nullifying the if checks.Telly
T
2

After upgrading to Gradle 4.2, the approach by Tarps stopped working, so I ended up combining it with Erik's answer.

Set ext.useGoogleGcm for each flavour in your build.gradle:

productFlavors {
    a {
        ...
        ext.useGoogleGcm = true
    }
    b {
        ...
        ext.useGoogleGcm = false
    }
}

Then at the bottom of the file:

apply plugin: 'com.google.gms.google-services'

afterEvaluate {
    android.productFlavors.each { flavor ->
        tasks.matching {
            it.name.contains('GoogleServices') && it.name.contains(flavor.name.capitalize())
        }*.enabled = flavor.ext.useGoogleGcm
    }
}

In the output for your assembleRelease task, you should see tasks with "GoogleServices" in the name have run for those that are true and skipped for those that are false. If your build complains about toCapitalize, you could use toLowerCase on both it.name and flavor.name.

Tauto answered 3/8, 2021 at 9:40 Comment(0)
C
1

In the case of the Google Services Gradle plugin, the following works.

apply plugin: 'com.google.gms.google-services'

afterEvaluate {
    tasks.matching { it.name.contains("GoogleServices") && !it.name.contains(yourFlavorName) }*.enabled = false
}

where yourFlavorName is a capitalised string containing the name of your flavor that must apply the plugin; all other flavors don't use the plugin.

Note that the plugin is still applied to other flavors; this solution just disables the *GoogleServices* task(s) for them. That assumes that the Google Services Gradle plugin only applies changes by adding a task containing substring "GoogleServices", which might not work in the future.

To check that this works, you can check the dependencies, e.g. like so:

./gradlew app:dependencyInsight --configuration yourFlavorNameDebugCompileClasspath --dependency google | grep -i services

That should show some dependencies for yourFlavorName but not for other flavor names:

./gradlew app:dependencyInsight --configuration otherFlavorNameDebugCompileClasspath --dependency google | grep -i services

Cotterell answered 21/6, 2021 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.