Android Gradle main project and submodule flavors - android

I have a main Android project, which depends on a submodule.
The main project has flavors defined in Gradle.
Also the submodule has a few flavors defined. This should be logical - to be able to have flavors for both projects.
For example in the submodule:
productFlavors {
flavorName {
}
}
But this does not work - The build crashes with a message saying that submodule resources are not found in the main project.
But when I delete flavors from the submodule, everything works fine.
It seems to mix the build order when flavors are defined for the subproject, could this be true?
What am I missing? Is it even possible for both main and sub projects to have flavors?

When you reference your sub-modules as dependencies in your build.gradle file, be sure to specify which flavor of the sub-module you are referring to:
dependencies {
compile project(path: ':module', configuration:'yourflavorDebug')
}
then be sure in your build variants, you are building the flavor your main module depends on, and everything should work out.
Also be sure the libraries you are referencing have this in their build.gradle as well:
publishNonDefault true
Without it android studio doesn't seem to be able to depend on flavors of that module. More information here.

Related

missingDimensionStrategy everywhere - Is there no better way?

I have a library project - let's call it lib1 which has custom flavorDimensions specified. More precisely there is buld dimension with actual flavors full and production.
This library is used by another library project (lib2) with no custom flavorDimensions specified and app project with dependency to lib2 but not directly to lib1.
To tell lib2 which flavor of lib1 to use I can specify missingDimensionStrategy 'build', 'full'. Great. Mission accomplished, right?
Well not really... Project won't sync because app project doesn't know which flavor of lib1 should it use??? I need to put the missingDimensionStrategy 'build', 'full' to the app project as well. You can imagine that if you try to build a well modularized app. This line will be practically in every build.gradle which transitively depends on lib1.
Is this how it should be? Can't I tell gradle somewhere globally what flavor to use? I wanted to add the dependency with debugApi project (path:':xxx', configuration: 'fullDebug') etc. but that doesn't work... :(
Can anybody give an advice? Thanks.

Gradle: interchangeably use AAR or project dependency

I have an AAR library that I want to distribute to partners along with a sample project that uses it. I want to also use the same sample project for manual testing while developing the AAR library. Thus, I would like to be able to use the library project as a dependency when developing, and the AAR file as a dependency when distributing.
I tried to define two flavors in the sample application:
productFlavors {
aar {}
project {}
}
...and then define dependencies like this:
dependencies {
//other dependencies
projectCompile project(':myLibrary')
aarCompile 'com.example.mylibrary:myLibrary-release#aar'
}
The aar flavor builds if I comment out the dependency for the project flavor, but if I leave both uncommented, Gradle sync fails if the myLibrary directory is not present - despite the fact that the project build flavor is not part of the current build variant.
What is the correct way to do this? Or do I have to choose between creating a whole separate project for distribution or always referencing the AAR even when debugging/testing?

Gradle multi-project conditional dependencry

How would one create an Android Studio (Gradle) multi-project configuration such that projB depends on project(':projA') if projA is defined, but uses a file in libs/ otherwise?
Since it may be asked, in this case projA is an SDK; projB is a test application designed to demonstrate the SDK. If the SDK team gets a bug report, it often includes reproduction steps using projB.
When projB team does work, they do so on RC builds of projA, whereas the SDK team uses projB, with a dependency on project(':projA') so that a debug session can be run.
projB has no specific definition of its dependency on projA; that team takes the projA output from the build server and drops it in the libs/ folder, and has a wildcard dependency.
EDIT
I finally went with this code in the dependencies closure, and it works like a charm:
def sdkRef
project.getRootProject().allprojects.each { proj ->
if (proj.name.equals("Sdk")) {
sdkRef = proj;
return true;
}
}
if (sdkRef) {
println "SDK present in project; using project reference as dependency"
compile sdkRef
} else {
println "SDK is not present in project; using libs/"
}
I wonder if that's something you can do with flavors and build variants.
Through code you might try in your build file :
dependencies {
if (project.getRootProject().findProject(":projectA")) {
compile project(":projectA")
} else {
compile files("libs/projectA.jar")
}
}
One thing you have to consider is that your settings.gradle defines what modules are included in your project. So your two teams might end up with different files anyway for the project.
You can achieve that with productFlavors.
You just have to define:
2 product flavors in projB/build.gradle
a specific dependency for each flavor
android {
productFlavors {
demo{}
sdkdev{}
}
...
}
dependencies{
demoCompile files("libs/projectA.jar")
sdkdevCompile project(":projectA")
...
}
The build will produce 2 apks.
In Android studio, someone from the demo team can run the demo flavor by selecting the "demoDebug" (or "demoRelease") variant (in Build Variant tab) and someone from sdk team will select the "sdkdevDebug" variant.
The gradle.settings must contains references for projA and projB, but a user from demo team will never have to compile projA because the demo flavor have no dependencies on it.

Conditional dependencies with Gradle, is it possible?

I have an Android project (already ported to Android Studio and using Gradle) that is made up of different modules.
The project is actually used to create two different apps, where the code is pretty much the same, except for some resources.
Thus the resources have been split into two different modules.
The original author of this project used to work in Eclipse and switch the resource modules included in the dependencies based on which app he wanted to build. And he also used to change by hand the package name in AndroidManifest.xml
I would like to automate all of this and still have a single code base, but have two build targets with specific modules for each target. Is that doable with Gradle?
Update:
To make things even harder, my project has a hierarchy that is pretty much the following:
--+--MainProject
+--LibData
+--LibBase
+--LibResA
+--LibResB
Where:
MainProject depends on LibBase and LibData.
LibData depends on LibBase
LibBase either depends on LibResA or LibResB based on the final APK that I need to build.
As suggested, I've tried implementing this with flavors by adding in the MainProject build.gradle the following:
productFlavors {
producta {
}
productb {
}
}
And then in LibBase I've added the following to its build.gradle:
dependencies {
productaCompile project(':LibResA')
productbCompile project(':LibResB')
}
But then, when I build the project, LibData can't find the classes and resources inherited from LibBase. So now I'm stuck with this error. To me it looks like LibBase isn't being copied to the intermediates of LibData. That way LibData can't resolve the classes in LibBase, but it's just my assumption.
Update 2:
I kept investigating this issue and now I've changed my build.gradle files to look like this:
Main Project build.gradle:
defaultPublishConfig "productaRelease"
publishNonDefault true
productFlavors {
producta {
applicationId "com.producta"
}
productb {
applicationId "com.productb"
}
}
dependencies {
compile project(':LibData')
}
LibData build.gradle (has no product flavors, just the dependencies):
dependencies {
compile project(':LibBase')
}
LibBase build.gradle:
defaultPublishConfig "productaRelease"
publishNonDefault true
productFlavors {
producta {
}
productb {
}
}
dependencies {
productaCompile project(path: ':LibResA')
productbCompile project(path: ':LibResB')
}
This way I get no errors when doing the usual gradle clean build but I can see that the resources included are always those of LibResA just like the defaultPublishConfig is the only one used at all times.
If I open this project in Android Studio (0.8.1 atm) the result is that if I try to switch the build variant of the LibBase module and set it to productbRelease, the following error is being shown: Error:Module 'LibBase' has variant 'productbRelease' selected, but the module ''LibData'' depends on variant 'productaRelease'.
I'm running out of ideas.
Since you already have the product flavors:
productFlavors {
producta {
}
productb {
}
}
Define your dependencies prefixed with flavor name.
Example:
dependencies {
productaImplementation 'com.google.android.gms:play-services:11.0.2'
productbImplementation 'com.google.android.gms:play-services:12.0.1'
}
Common dependencies will be defined normally.
Now build apk for individual flavors.
Not the best way to do it, but if productFlavors is not enough to specify conditional dependencies you can rely on an inline if and evaluate it based on some value that can be injected via external properties.
For example here is how I toggle LeakCanary (no-op is just the empty implementation of the other one):
build.gradle
dependencies {
compile "com.squareup.leakcanary:leakcanary-android"+(project.ext.has("leakCanary")?"":"-no-op")+":1.3.1"
}
To build with com.squareup.leakcanary:leakcanary-android:1.3.1:
$ ./gradlew :app:assembleDebug -PleakCanary
By default it builds with the empty implementation com.squareup.leakcanary:leakcanary-android-no-op:1.3.1:
$ ./gradlew :app:assembleDebug
This provides a quick and more flexible way to toggle things using build command, but too much of it and things will get messy real quick.
Yes, it is. New Android build system based on Gradle supports your use case with its concept of product flavors. http://tools.android.com/tech-docs/new-build-system/user-guide
Note that you will likely want to switch from Eclipse to Android Studio when you do migration to Gradle build.

Gradle Android project dependency not working

I'm trying to migrate from maven to Gradle for an Android project and I am facing the following issue:
I have three projects i.e
root
- projlib
build.gradle
- projA
build.gradle
- projB
build.gradle
build.gradle
settings.gradle
Basically what I want to achieve is that projB depends on projA and projlib. projlib is a lib folder that compiles and generates a lib(jar) file. projA is an Android Application and projB is another Android Application that needs to reference code in projA. Right now what I have added in the projB build.gradle file is
dependencies {
compile project(':projlib')
compile project(':projA')
}
So say if there's a class
FooProjLib in projlib and
FooProjA in projA
Then In projB I can do
FooProjLib foo = new FooProjLib
which works fine
but when I do
FooProjA foo = new FooProjA
Gradle gives me package projA does not exist, what I have observed is that both dependency is resolved but only the lib can be reference and not the apk.
Does anyone have an idea how to solve this?
You can't do exactly what you want. projA can't build an application (i.e. an APK) and also have other things depend on it. projB can only depend on projA if projA is an Android library, meaning in its build file you have this declaration:
apply plugin: 'android-library'
instead of
apply plugin: 'android'
Of course, this means that projA won't build an APK, but will build an AAR instead.
If projA needs to also be an APK, you'll have to restructure things such that the common code that's in projA that projB also needs is moved out to a shared library. If both projects are similar, perhaps you could have just one module for them and use project flavors to differentiate them; it's hard to say whether this is a good approach without a lot more information.

Categories

Resources