How to avoid duplicate classes for build types ?

5,747 views
Skip to first unread message

Thomas Bruyelle

unread,
Aug 13, 2013, 8:20:10 AM8/13/13
to adt...@googlegroups.com
I want to build an "admin" version of my app, but not with the usage of product flavors, because I don't want variants like adminDebug or adminRelease.
So I created a new buildtype "admin" which extends the "debug" one, and created a new folder "admin" in my src folder.

My idea is to redefine some classes and layouts in the admin folder, in order to add special capabilities. But when I launch "gradle assembleAdmin", I get an error "duplicate classes".

It seems the build types merge works well for resources, but not for java source files, am I wrong ? 
If true, can someone give me a tip to override source files with build types ?

Thx in advance

Xavier Ducrohet

unread,
Aug 13, 2013, 12:12:41 PM8/13/13
to adt...@googlegroups.com
The source code for Build Types (and flavors) is not meant to replace classes from src/main. It's just an additional folder.

You could use a different architecture in your code to provide different capabilities depending on the build types you are building.

Or, if you really want to replace just a few classes, you could put the replaced class in their own source folder, and make the non admin types use this source folder.


--
You received this message because you are subscribed to the Google Groups "adt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Xavier Ducrohet
Android SDK Tech Lead
Google Inc.
http://developer.android.com | http://tools.android.com

Please do not send me questions directly. Thanks!

Thomas Bruyelle

unread,
Aug 13, 2013, 3:38:33 PM8/13/13
to adt...@googlegroups.com
Thanks for your answer Xavier.
About your first solution, it implies that I need set a variable which contains the buildType in the BuildConfig, in order to be aware of it at runtime. Is that what you thought ?
About the second solution, I don't really get it. I need to manipulate the sourceSets in the buildtypes ?

Xavier Ducrohet

unread,
Aug 13, 2013, 4:08:01 PM8/13/13
to adt...@googlegroups.com
Yes in the first solution you can use BuildConfig to enable something that will use a particular implementation of something.

You could do it this way:


productFlavors.whenObjectAdded { flavor ->
       flavor.buildConfig "public static final String PRODUCT_FLAVOR = \"${flavor.name}\";"
   }

In the second solution you could do:

src/main/java -> main code
src/basic/java -> default classes you want to override in admin
src/admin/java -> contains the replacement classes.

then you ensure that all your other build types also include src/basic/java

Something like roughly like this:

android {
   buildTypes.whenObjectAdded { buildType ->
       if (buildType.name != "admin") {
          sourceSets.get(buildType.name).srcDir 'src/basic/java
       }
   }
}


--
You received this message because you are subscribed to the Google Groups "adt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Thomas Bruyelle

unread,
Aug 14, 2013, 2:47:59 AM8/14/13
to adt...@googlegroups.com
Ok I get it, with the second solution we have a kind of product flavors without the mix with buildtypes.
Thanks again for your help I appreciate.

Thomas Bruyelle

unread,
Aug 14, 2013, 5:33:42 AM8/14/13
to adt...@googlegroups.com
For the follow-up, I picked up the second solution and ended with that configuration :

android {
   buildTypes.all { buildType ->
       if (buildType.name != "admin") {
          sourceSets[buildType.name].java.srcDir 'src/basic/java
       }
   }
}

I had to replace buildTypes.whenObjectAdded by buildTypes.all because whenObjectAdded isn't called for the standard build types release and debug.

The major issue I have now is the IDE configuration, AS seems completely lost with the duplicate classes and merged resources.

Xavier Ducrohet

unread,
Aug 14, 2013, 1:15:25 PM8/14/13
to adt...@googlegroups.com
ah yeah that's because by the time this is evaluated, debug and release have already been added.

.all is applied to existing and future items so that does what you want.

Studio should just work through. Maybe Alex can chime in?


--
You received this message because you are subscribed to the Google Groups "adt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Kevin Gorham

unread,
Aug 15, 2013, 2:17:28 AM8/15/13
to adt...@googlegroups.com
We encountered this exact use-case at work today. Our apps are sports-related and we are leveraging flavors and flavor groups to vastly cut down on unnecessary projects with lots of elements in common. Each school can be a different flavor, along with "paid" and "free" groups.

Personally, I think it's going to be a fairly common case with users who make meaningful use of buildVariants. Eventually, variations will arise that can't be fully covered by styles/themes/etc. Unfortunately, most solutions to this are either "hacky" or involve bloating all variants with code that only applies to a few (admittedly, the solution proposed here feels like a hack). Having a structured & consistent way of managing this would be ideal. 

That prompted me to join this group and start looking into how to contribute to ADT. I imagine the core team has more important things to work on so it would be nice to lend a hand with making this less clumsy. Having the gradle plugin allow for this in a "declarative" way (i.e. replaceSources=true), feels more like the "right" approach.

Anybody agree?

- Kevin

Jake Wharton

unread,
Aug 16, 2013, 1:35:57 PM8/16/13
to adt...@googlegroups.com
Replacing sources seems extremely prone to silent and difficult to track down problems. The contract of the replaced source is only implicitly based on the original (though enforced at compile-time at the very least).

Why wouldn't you just extract an interface with different implementations?

--

Daniel Smith

unread,
Jul 16, 2014, 5:17:12 PM7/16/14
to adt...@googlegroups.com
Why wouldn't you just extract an interface with different implementations?

Are you implying that the different implementations would live in the packages that correspond to differing product flavors? 
Reply all
Reply to author
Forward
0 new messages