58

I have several build types: debug, release. I also have two flavors pub and dev.

pub flavored application depends on a pub library, the similar goes for dev flavor. Now I'd like the debug build type app depend on debug build of the library. The following does not work:

pubReleaseCompile project(path: ':common', configuration: "pubRelease")
devReleaseCompile project(path: ':common', configuration: "devRelease")
pubDebugCompile project(path: ':common', configuration: "pubDebug")
devDebugCompile project(path: ':common', configuration: "devDebug")

Note: The library is set up to compile all variants.

Is there a way to specify conditional project dependency based on both flavor and build type?

EDIT: To avoid confusion here follow relevant build.gradle files from the project that I'm currently using.

project/common/build.gradle (the library)

apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.hugo' // annotation-based code generated logs only in debug build

android {
  defaultPublishConfig "pubRelease"
  publishNonDefault true // four variants of the library are built

  buildTypes {
    debug {}
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
    }
  }
  productFlavors {
    pub {
      // custom build config fields
    }
    dev {
      // custom build config fields
    }
  }
}

dependencies {
  // ...
}

project/parent/build.gradle (one of the app modules using the library)

apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.hugo'

android {
  // ...

  signingConfigs {
    release {
      // ...
    }
  }

  buildTypes {
    release {
      signingConfig signingConfigs.release
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
      shrinkResources true
      minifyEnabled true
    }
    debug {
      versionNameSuffix '-debug'
    }
  }
  productFlavors {
    pub {
      // custom res values
    }
    dev {
      // custom res values
    }
  }
}

dependencies {
  // ...
  pubCompile project(path: ':common', configuration: "pubRelease")
  devCompile project(path: ':common', configuration: "devRelease")
}
Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124

4 Answers4

56

Android Plugin for Gradle 3.x.x

Build plugin 3.x.x uses variant-aware dependency resolution so devDebug variant of an app module will automatically use devDebug variant of its library module dependency. To answer the question, this would be enough:

implementation project(':common')

Read more here: https://developer.android.com/studio/build/dependencies.html#variant_aware

Original answer

I was able to find a solution here: https://github.com/JakeWharton/u2020/blob/master/build.gradle

More on why my original code does not suffice is available here: https://code.google.com/p/android/issues/detail?id=162285

Working solution:

configurations {
  pubDebugCompile
  devDebugCompile
  pubReleaseCompile
  devReleaseCompile
}

dependencies {
  pubReleaseCompile project(path: ':common', configuration: "pubRelease")
  devReleaseCompile project(path: ':common', configuration: "devRelease")
  pubDebugCompile project(path: ':common', configuration: "pubDebug")
  devDebugCompile project(path: ':common', configuration: "devDebug")
}
Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • There may be no need in manual configuration in future: https://code.google.com/p/android/issues/detail?id=162285 – Nikita Barishok Mar 03 '16 at 11:26
  • I have a related question here but cannot resolve yet. I have tried what you have suggested and still no luck. http://stackoverflow.com/questions/36156596/gradle-subproject-external-library-dependency-based-on-main-project-module-fla – Wayne Mar 31 '16 at 13:10
  • @Wayne You have to define build types and flavours and then configurations with this name pattern: "Compile". You can't just define random configurations. – Eugen Pechanec Mar 31 '16 at 14:26
  • @Eugen Perchance I am just omitting the ... I am going to try that. thanks for the help. Are you aware of a git project that has an example? – Wayne Mar 31 '16 at 14:37
  • @Wayne If you don't define build types there are implicitly two: `debug` and `release`. You have to define product flavors in your library as well. Say you define `fOne` and `fTwo`, then you can use `fOneCompile` and `fTwoCompile` in your library's dependencies. Then you have to tell the compiler you want all library configurations built (all combinations of flavour and build type). And then your app module can depend on `fOneRelease` etc. **The whole example is laid out for you in the question, just read it carefully.** – Eugen Pechanec Mar 31 '16 at 15:12
  • 1
    3.0.0 link seems broken as of today. This should be the new one: https://developer.android.com/studio/build/dependencies.html#variant_aware – superjos Jun 06 '19 at 15:08
5

First define the various build types:

buildTypes {
    pubRelease {
        //config
    }
    devRelease {
        //config
    }
}

Create a task that will be executed only for a specific buildType and flavor:

task pubReleaseTask << {
    //code
}

task devReleaseTask << {
    //code
}

You can add the dependency dynamically:

tasks.whenTaskAdded { task ->
    if (task.name == 'pubRelease') {
        task.dependsOn pubReleaseTask
    }
    if (task.name == 'devRelease') {
        task.dependsOn devReleaseTask 
    }
}
Mithun
  • 7,747
  • 6
  • 52
  • 68
  • If I did `gradlew clean build` wouldn't this add all the dependencies at once? – Eugen Pechanec Mar 05 '15 at 11:41
  • Two questions: **1)** Re: UPDATE: But still if I'm doing a full build it's going to do all tasks, so the first flavor specific task will get it's own dependency and every consecutive flavor specific task will get it's own plus whatever has already been added. Is this correct or not? **2)** On which tasks should i hook the new ones? – Eugen Pechanec Mar 05 '15 at 17:40
  • @EugenPechanec - Please find the answer updated with more explanation. – Mithun Mar 05 '15 at 18:00
  • So I added [this](http://pastebin.com/z4t8HiqV) at the end of my *app module* `build.gradle`. Won't compile, did not find library resources. Where did you come up with the 'pubRelease' and 'devRelease' task names? There are no such tasks in the project. (Thank you so much for your patience.) – Eugen Pechanec Mar 05 '15 at 18:17
  • Also please note that the *build types* are `release` and `debug` and the *flavors* are `pub` and `dev`. – Eugen Pechanec Mar 05 '15 at 18:19
  • Error:(364, 0) Cannot change dependencies of configuration ':app:compile' after it has been included in dependency resolution. – StarWind0 Sep 25 '17 at 22:14
3

Follow up @dooplaye's example, assume you only want to compile leanback in one flavor, you could refer to below snippet:

applicationVariants.all { variant ->
    def flavorString = ""
    def flavors = variant.productFlavors
    for (int i = 0; i < flavors.size(); i++) {
        flavorString += flavors[i].name;
    }

    if (flavorString.equalsIgnoreCase("pubdeb")) {
        dependencies {
            compile('com.android.support:leanback-v17:22.2.1')
        }
    }
}
Shebuka
  • 3,148
  • 1
  • 26
  • 43
Hsiao-Ting
  • 3,456
  • 2
  • 15
  • 20
  • I get this error: Cannot change dependencies of configuration ':app:compile' after it has been included in dependency resolution. – Dmytro Karataiev Jul 08 '17 at 20:52
  • 1
    There already is (and was 4 years ago) a standard way of doing this: `dependencies { pubdebCompile('com.android.support:leanback-v17:22.2.1') }` The question requires that you already know how to declare dependencies based on flavor. I'm voting this down. – Eugen Pechanec Feb 13 '19 at 16:37
2

Take a look at Multi-flavor variants You shouldn't use buildTypes for this. But you can define multi-flavors:

flavorDimensions "first", "second"

productFlavors {
    pub {
        flavorDimension "first"
    }
    dev {
        flavorDimension "first"
    }
    deb {
        flavorDimension "second"
    }
    rel {
        flavorDimension "second"
    }
}

And then you can add dependencies to your libs like this

pubRelCompile project(path: ':common', configuration: "pubRel")
devRelCompile project(path: ':common', configuration: "devRel")
pubDebCompile project(path: ':common', configuration: "pubDeb")
devDebCompile project(path: ':common', configuration: "devDeb")
dooplaye
  • 999
  • 13
  • 28
  • That would include `pubRelease` library in both `pubDebug` and `pubRelease` variant of app. This is what I'm using already. What I'm looking for is including `pubRelease` library in `pubRelease` app and `pubDebug` library in `pubDebug` app. – Eugen Pechanec Mar 11 '15 at 11:19
  • Re Edit: Can't do that. Would have to use buildTypes only and after that I'd have to maintain duplicate values for what-used-to-be-flavors. This is not an option. – Eugen Pechanec Mar 11 '15 at 23:01
  • This would generate twice as many APKs with next to no gain. Check out my solution and the associated sources. – Eugen Pechanec Apr 16 '15 at 04:30