46

I have a library project and a application. I'd like to have 2 product flavours (store, dev) for both library and application. When I build the store flavour for the application I want to use the store flavour from the library. Also when I build the dev flavour for the application I want to use the dev flavour from the library. I tried setting the same product flavours for both library and application but it does not work.

Here is my configuration:

Library

apply plugin: 'android-library'

android {
    compileSdkVersion 19
    buildToolsVersion "19.1.0"

    defaultConfig {
        applicationId "ro.amarkovits.graddletest.lib"
        minSdkVersion 14
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors{
        store{

        }
        dev{

        }
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

and I have this files: src/main/res/values/strings.xml and src/store/res/values/strings.xml

Application

apply plugin: 'android'

android {
    compileSdkVersion 19
    buildToolsVersion '19.1.0'
    defaultConfig {
        applicationId 'ro.amarkovits.mymodule.app'
        minSdkVersion 14
        targetSdkVersion 19
        versionCode 1
        versionName '1.0'
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors{
        store{

        }
        dev{

        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':lib')
}

In this situation I get this error: Error:(12, 23) No resource found that matches the given name (at 'text' with value '@string/app_name'). The app_name is defined in string.xml in the library (in both main and store directory)

If I remove the productFlavors from the library it builds but always use the values.xml from the main directory

Bryan Herbst
  • 66,602
  • 10
  • 133
  • 120
amarkovits
  • 776
  • 1
  • 10
  • 17

3 Answers3

60

In your library you need to tell gradle to build every time every variant:

android {
    publishNonDefault true
}

Then in your application, since recently I guess, you can do this:

dependencies {
    (...)
    devCompile project(path: ':lib', configuration: 'devDebug') // or 'devRelease'
    storeCompile project(path: ':lib', configuration: 'storeRelease') // or 'storeDebug'
}

Found in the official documentation under Library Publication.

Edit:

Since version 0.14.3 (2014/11/18), you can now have Flavor-buildType-Compile directive as well:

In your build.gradle before the android {} scope add the following:

configurations {
    devDebugCompile
    devReleaseCompile
    storeDebugCompile
    storeReleaseCompile
}

Then you can declare and use different versions of your library per Flavor-BuildType:

dependencies {
    (...)
    devDebugCompile project(path: ':lib', configuration: 'devDebug')
    devReleaseCompile project(path: ':lib', configuration: 'devRelease')
    storeDebugCompile project(path: ':lib', configuration: 'storeDebug')
    storeReleaseCompile project(path: ':lib', configuration: 'storeRelease') 
}

Edit:

Dependency management between modules has changed since Android Gradle Plugin 3.0.0. It automatically tries to matches flavours between your app and the libraries/modules it depends on.

See the documentation for the whole explanation!

galex
  • 3,279
  • 2
  • 34
  • 46
  • 3
    Any idea how to do this so devDebug uses devDebug, and devRelease uses devRelease (doesn't make sense in this case, but does for my use case)? – Kevin DiTraglia Mar 09 '15 at 13:36
  • There is no "per variant", only per-flavor or per-buildType compile keyword for now. – galex Mar 24 '15 at 09:45
  • @KevinDiTraglia I edit my answer as what you asked for actually now exists – galex Feb 01 '16 at 13:49
  • do we need to add module again in module settings ? or above code is good enough ? – Meher Feb 27 '17 at 14:17
  • @Meher what do you mean in module settings ? In settings.gradle ? Yes your library defined as module needs to be there, otherwise gradle does not know it is there to be built. – galex Feb 27 '17 at 14:19
  • Very helpful answer! This information, along with this post: https://www.thedroidsonroids.com/blog/android/android-gradle-configurations/ helped me figure out my gradle compile issues with missing packages and symbols. – HelloImKevo Jun 22 '17 at 17:38
  • it seems not working for latest AS. it cannot fetch the project if I specify the `configuration` – bj4947 Aug 14 '17 at 22:07
  • @IHC_Applroid didn't try it yet but replace the keyword "Compile" by "Implementation" ? – galex Aug 15 '17 at 02:31
  • @galex no, AS changed the way it works. https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html – bj4947 Aug 15 '17 at 04:02
  • @galex please check this https://stackoverflow.com/questions/47215663/android-studio-3-0-submodule-compile-failed – Aks4125 Nov 10 '17 at 07:08
  • _configurations {. . .}_ Thanks for hint. Though editor provide you auto selection while adding dependency for flavour but you have to defined same in _configurations_ block. – CoDe Dec 06 '17 at 03:50
  • I would say there is a good web-page with a detailed explanation how to do it, see https://developer.android.com/studio/build/dependencies#resolve_matching_errors – ultraon Aug 07 '19 at 16:13
5

To define specific dependency for each flavor you can use "nameOfTheFlavorCompile" instead of "compile"

dependencies {
    storeCompile project(':lib')
}
2

I had a similar issue a while ago, what happens is that the compiler ignores product flavors for the library project. Moreover, even when you add more build types, it keeps looking for and compiling release/debug sources.

The reason is simple:

  • Product flavors are not supported for the library plugin.
  • The only build types supported seem to be debug and release.

The compiler will never look for anything you put in the store directory of your library project. So, you need to find a way around it.

One way around it would be to include both implementations with a level of abstraction in your library (through interfaces, multiple constructors, etc), and then let your app project decide which part of the library to run. If you use proguard, it will automatically get rid of the unneeded code, if it is decoupled well enough (and possibly so even if it is not).