Home » Android » android – Multi-flavor compile dependencies in gradle

android – Multi-flavor compile dependencies in gradle

Posted by: admin May 14, 2020 Leave a comment

Questions:

Is there a way to have compile dependencies by multiple flavors in Android Studio (build.gradle)?

I have 2 flavorGroups, and in each 2 variants. Out of the 4 possible combinations I would like to be able to depend on a lib only if I’m both in latest and in free flavor. latestCompile or freeCompile works, but latestFreeCompile doesn’t. this is the relevant part of my build.gradle:

android {
    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 19
        versionCode 15
        versionName "1.9." + versionCode
    }

    flavorGroups 'sdk', 'cost'

    productFlavors {
        latest {
            flavorGroup 'sdk'
            minSdkVersion 8
        }
        sdk7 {
            flavorGroup 'sdk'
            minSdkVersion 7
            versionName android.defaultConfig.versionName + ".sdk7"
        }
        free {
            flavorGroup 'cost'
        }
        pro {
            flavorGroup 'cost'
        }
    }
}
dependencies {
    // this works:
    freeCompile files('libs/StartAppInApp-2.2.1.jar')

    // and I would like something like this:
    latestFreeCompile 'com.google.android.gms:play-services:4.1.32' // minSdkVersion:8
}

If I would use:

latestCompile 'com.google.android.gms:play-services:4.1.32'

then it would be included in latestPro as well (not needed)
and if I’d use:

freeCompile 'com.google.android.gms:play-services:4.1.32'

then it would be included in sdk7Free as well (although it needs SDK 8)

How to&Answers:

I had the same problem. I resolved that with some gradle code in my build.gradle:

// global variables
ext {
    buildType = ""
    groupCost = ""
    groupSdk = ""
}

def splitCamelCase(String word) {
    def result = []
    int nextStart = 0;
    for (int i = 1; i < word.length(); i++) {
        if(word.charAt(i).isUpperCase()) {
            result.add(word.substring(nextStart, i));
            nextStart = i;
        }
    }

    result.add(word.substring(nextStart));
    return result;
}

// start parameters
println "Start parametes: tasks = " + gradle.startParameter.getTaskNames()

gradle.startParameter.getTaskNames().each { task ->

    // This line is needed to skip other projects' tasks
    // You can safely remove it if you have only one project
    if(!task.startsWith(':<your_application_name>:')) return;

    def taskParts = splitCamelCase(task.split(":").last());
    def groupCostPrefix = taskParts[taskParts.size() - 3];
    def groupSdkPrefix = taskParts[taskParts.size() - 2];
    def buildTypePrefix = taskParts[taskParts.size() - 1];

    if("Debug".startsWith(buildTypePrefix)) {
        buildType = 'debug';
    }
    else if("Release".startsWith(buildTypePrefix)) {
        buildType = 'release';
    }
    else {
        return; // do not process tasks that are not ending with proper build type.
    }

    if("Free".startsWith(groupCostPrefix)) {
        groupCost = 'free';
    }
    else if("Pro".startsWith(groupCostPrefix)) {
        groupCost = 'pro';
    }

    if("Sdk7".startsWith(groupSdkPrefix)) {
        groupSdk = 'froyo';
    }
    else if("Latest".startsWith(groupSdkPrefix)) {
        groupSdk = 'latest';
    }
}

Then all you need is to add following code inside your ‘dependencies’ section:

if(groupSdk == 'latest' && groupCost == 'free') {
    compile 'com.google.android.gms:play-services:4.1.32'
}

Answer:

Same issue here, but Pawel’s solution didn’t work because gradle dependencies have other issues in which it starts building not only the selected flavors/build type, but all of them and it requires a more dynamic solution.

Still I found this issue tracker:
https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=52962

There is also a reference to fixing the rebuild-all bug I mentioned above, but I didn’t try it yet.

And implemented this solution (as per issue tracker reply #60):

    Map<String, Dependency> customDeps = new HashMap<String, Dependency>()

    customDeps.put('flavor1GrpXflabor1GrpYDebugCompile', dependencies.project(path: ':lib', configuration: 'debug'))
    customDeps.put('flavor1GrpXflavor1GrpYReleaseCompile', dependencies.project(path: ':lib', configuration: 'release'))

    customDeps.put('flavor2GrpXflavor1GrpYDebugCompile', dependencies.project(path: ':other_lib', configuration: 'debug'))
    customDeps.put('flavor2GrpXflavor1GrpYReleaseCompile', dependencies.project(path: ':other_lib', configuration: 'release'))

    ....

    configurations.all() { config ->
        Dependency d = customDeps.get(config.name)
        if (d != null) {
            config.dependencies.add(d)
        }
    }

Answer:

As now described on the official Android Developers website, if you want to declare a dependency for a specific combination of product flavor AND build type you need to declare that configuration first.

For example for the free flavor and the debug type:

configurations {
    freeDebugImplementation {}
}

dependencies {
    freeDebugImplementation 'com.google.firebase:firebase-ads:9.8.0'
}

Advanced: multiple flavor dimensions

Note that if your app has multiple flavor dimensions, you must create the configuration corresponding to the full build variant (ALL flavors, then build type), like so:

flavorDimensions "money", "image" 
productFlavors {
    free { dimension "money" }
    paid { dimension "money" }

    picasso { dimension "image" }
    glide { dimension "image" }
}

configurations {
    freePicassoDebugImplementation {}
    freeGlideDebugImplementation {}
}

dependencies {
    freePicassoDebugImplementation 'com.google.firebase:firebase-ads:9.8.0'
    freeGlideDebugImplementation 'com.google.firebase:firebase-ads:9.8.0'
}