8

Our application has a free and a paid version. We also make branded-versions, which means that the application vary in two dimensions.

Four versions could be:

  • The App, Nike ed. free
  • The APP, Nike ed. paid
  • The App, Adidas ed. paid
  • The App, Adidas ed. free

My solution now is to have two build-types, paid and free:

  buildTypes {
        paid {
            packageNameSuffix ".paid"
        }

        free {
            packageNameSuffix ".free"
        }
    }

And two build flavors:

productFlavors{
    nike{
        packageName "com.example.theapp.nike"
    }

    adidas{
        packageName "com.example.theapp.adidas"
    }

}

Every free-version of the app make us of a content-provider, a content provider which is specific per flavor-build type combination. The problem is that I don't understand where to put a source file based on build variant. Source files put into /src/nike or /src/free will be picked up depending on build type or flavor. But how about source files that are depending on the build variant (the combination of type and flavor)?

Top-Master
  • 7,611
  • 5
  • 39
  • 71
lorgartzor
  • 359
  • 5
  • 10

4 Answers4

10

You can create a new folder under src for every build or flavor that you have. i.e: 'free', 'paid', 'nike', 'adidas'.

The files that you put in any of these folders gets picked up when building depending on the type and build both.

According to Gradle Plugin User Guide on Android Tools Project Site:

Similar to Build Types, Product Flavors also contribute code and resources through their own sourceSets.

and

The following rules are used when dealing with all the sourcesets used to build a single APK:

  • All source code (src/*/java) are used together as multiple folders generating a single output.
  • Manifests are all merged together into a single manifest. This allows Product Flavors to have different components and/or permissions, similarly to Build Types.
  • All resources (Android res and assets) are used using overlay priority where the Build Type overrides the Product Flavor, which overrides the main sourceSet.
  • Each Build Variant generates its own R class (or other generated source code) from the resources. Nothing is shared between variants.

meaning that your java files for the buildType "free" will overwrite the ones for your flavors "nike" if they have the same name.

But if you're adding something to a manifest, according to the second point in the list above the final manifest will be a merge of all of the manifests.

If you need more customization you can put your files in your build variant's folder "src/freeNike/".

maclir
  • 3,218
  • 26
  • 39
  • 9
    Java files are not overwritten per flavor. If you'll have same java file in main source set and in flavor's source set, you'll get an error "Duplicate class found". The reason for that, as you've written yourself, is that "All source code (src/*/java) are used **together** as multiple folders generating a single output." You have to either specify java file in main source set only, or in **all** other flavors' source sets. – Haspemulator Jan 29 '15 at 12:22
  • Resource files overlay just fine (also as stated). I use a combination of splitting java files (where you need a copy of the file in every flavor/variant but not in main) or a resource file (e.g. with a default value in main of a lib, then values to overwrite in flavor/variant directories of the main project. – ProjectJourneyman Feb 08 '16 at 22:28
3

I had similar problem with build types overriding flavors due to the overlay rules.

I ended up redirecting the build type source sets into different folders depending on which flavor was built.

android.applicationVariants.all { variant ->
    switch (variant.name) {
        case "FreeNike":
            variant.mergeResources.doFirst {
                android.sourceSets.free.setRoot("src/freeNike")
            }
            break;
        case "FreeAdidas":
            variant.mergeResources.doFirst {
                android.sourceSets.free.setRoot("src/freeAdidas")
            }
            break;
        case "PaidNike":
            variant.mergeResources.doFirst {
                android.sourceSets.paid.setRoot("src/paidNike")
            }
            break;
        case "PaidAdidas":
            variant.mergeResources.doFirst {
                android.sourceSets.paid.setRoot("src/paidAdidas")
            }
            break;
    }
}

You are of course free to use a different folder structure. See example here: Folder naming convention for gradle build variants

Community
  • 1
  • 1
ddante
  • 166
  • 4
1

Have a look at newest Gradle plugin it now allows to have variant specific resources http://tools.android.com/tech-docs/new-build-system

And here You have example of usage https://android.googlesource.com/platform/tools/build/+/master/tests/overlay3/

mar3kk
  • 1,886
  • 2
  • 17
  • 21
  • This is the best answer. I needed to have the same resource directory for several different variants, so I ended up doing this: `sourceSets { var1.res.srcDirs = ['same\res\path'] var2.res.srcDirs = ['same\res\path'] var3.res.srcDirs = ['same\res\path'] }` – Jansky Nov 14 '17 at 14:21
0

Have you tried to put the srcDir in the sourceSets ? Like so:

    sourceSets {
            main {
                java {
                    srcDirs 'src/java'
                }
            }
     }

That should output a javaResources with two source codes, nike and adidas.