Flavors in Library Projects?

220 views
Skip to first unread message

Benjamin Cooley

unread,
Jun 5, 2013, 12:37:33 AM6/5/13
to adt...@googlegroups.com
It seems that library projects do not have flavors. Reading the docs it seems this is intentional but I am curious why? It seems to me the utility of flavors can easily be applied to library projects as well as apk projects?  I get wanting to only manage a single .aar file for a library dependency, but there seems to be no good way to handle the case of the same code built slightly differently to different downstream apks.

For reference, what I was trying to do was build against a different target/dependency to produce multiple apk's, something it would seem would fit flavors nicely.  I want to produce one APK linking against an add-on (so compileSdkVersion is set), while another sets compileSdkVersion to the generic android and providing dependencies (for a much fatter APK, but one that can be installed without certain libraries having to be on the system).

Of course, if I am going about this the wrong way pointers in the right direction would be appreciated :).

- Ben

Manfred Moser

unread,
Jun 5, 2013, 12:01:56 PM6/5/13
to adt...@googlegroups.com
Just build different aar projects that depend on an aar that has the common stuff in it. 

manfred



--
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.
 
 

Benjamin Cooley

unread,
Jun 5, 2013, 12:39:24 PM6/5/13
to adt...@googlegroups.com
That doesn't actually work for wanting to swap out dependencies, unless there is a way I don't know to set transitive dependencies.

Even ignoring the case of wanting to use different dependencies to build common code (which is what I was trying to do), you have the same case you have in apk's, if you want to make small changes, creating another project (or two) seems overkill. To use the example in the documentation, if you want a 'free' vs 'paid' application, i can easily see a library that stays mostly the same but has a few small differences (in dependencies and code), and having something like flavors would save you from having to create two other library projects (a common and the two derivatives).

But as I said, it won't work for the case where you want to have one piece of code call the same interface in two different dependency modules: For example, calling 'deviceSpecificLibrary' from one apk, and 'dropInReplacementLib' on another.

- Ben

Xavier Ducrohet

unread,
Jun 5, 2013, 2:19:15 PM6/5/13
to adt...@googlegroups.com
We didn't add flavors in libraries mostly to keep things simple, but I can understand people wanting to have it.

In a multi-module project where the app module has flavors, it makes sense to have flavors in the libraries. When building an aar for other people to use, less so.

We would also have to figure out how this works. While your library could use the "classifier" property to expose different artifact, I'm not sure if Gradle can support this for inter-module dependencies. I'll have to look that up.
--
Xavier Ducrohet
Android SDK Tech Lead
Google Inc.
http://developer.android.com | http://tools.android.com

Please do not send me questions directly. Thanks!

Benjamin Cooley

unread,
Jun 20, 2013, 8:34:45 PM6/20/13
to adt...@googlegroups.com
I managed to work around the problem as follows: 

I split my library projects into two projects, a java project and an android project. The android project depends on the java project. The java project has the ability to have transient dependencies, so I could make all the code dependencies in my libraries transient and include the correct dependencies in the correct flavors at the android apk project level.

While I obviously think flavors in library projects would be awesome (given that I just needed it), I can see why its not a high priority feature / would be low-use.  Gradle does support pulling in a single configuration from a dependency, so as long as you export the flavors to different configurations, you can do this.

However, I do think adding limited support for transient dependencies would be cheap and worthwhile. I get not having full built-in transient dependency support (since it doesn't make sense, particularly in the android environment), but a few of the work-around's I've done to address other issues would of been easier with the ability to have them. Something like what gradle has with the ability to add arbitrary entires to the classpath (sourceset.compileClasspath).  Manually tweaking the classpath is a powerful tool for handling wierd build edge-case logic, but by doing so you remove yourself from the standard gradle compile-dependency eco-system, and have to deal with that.  Thus you want to avoid using it, but it is really nice to have when say, you run into a to-be-implemented feature you need to use, and would be nice if we could do the same with the android classpath.

- Ben

Xavier Ducrohet

unread,
Jun 20, 2013, 9:06:39 PM6/20/13
to adt...@googlegroups.com
I definitively want to support flavors and build types in libraries the same way we do in application project.

There are some issues with it though. while you can write

   compile project(path: ':foo', configuration: 'flavor1')

This doesnt really scale. You would actually need to set this up like:

   flavor1Compile project(path: ':foo', configuration: 'flavor1')
   flavor2Compile project(path: ':foo', configuration: 'flavor2')

You'd have to do this for all you variant. And actually, that's not quite right either, you actually need:

   flavor1DebugCompile project(path: ':foo', configuration: 'flavor1Debug')
   flavor2ReleaseCompile project(path: ':foo', configuration: 'flavor2Release')

Where those configurations are composite configuration that are made up of all the configuration that make up your variant (the default compile, the build type and flavors if applicable).

I'm actually working on creating those composite configuration objects because we need to resolve the dependencies of a variant as a whole, instead of resolving each (default config, build type, flavors) separately and then combining the result like we were doing before.

However we don't want developers to setup dependencies on those composite configurations, they are purely internal implementation details.
(Those we want developers to create custom resolutionStrategy on the composite, not on the single configuration!).

So to get back to the library project. What you really want is just say:

   compile project(':foo')

and have gradle do the right thing, which is let the plugin query what artifacts of 'foo' are available and choose the right one base on what variant is currently being compiled (since 'compile' is used by all the variant).

If both app and library use the same buildtypes/flavors then we just use the right one automatically. If they are different, we could let the user provide some mapping to help. But in some case we can figure it out automatically.

For instance if the app has (debug, release)x(flavor1, flavor2) and the library has (debug, release) only we can do the matching directly based on the build type.
If the library has (debug,release)x(flavor3, flavor4) then we'll need to know the mapping.

In all case it's better than having the app explicitly define dependencies on the variant directly.

Gradle right now is missing some hooks to do that. I actually just spent all of yesterday talking with the Gradle lead developer and we spent a *lot* of time talking about dependency management (there are other features that are tied to dependency management that we need to improve on both sides).

Improving the dependency management in Gradle to support Android's use case is going to be high on our priority list, so we'll get there.

Xav
Reply all
Reply to author
Forward
0 new messages