I am trying to configure with Gradle a project which contains some external libraries. With Gradle I can setup different Environmental Configuration (with a class inside a c
Not sure what's wrong with your configuration but about your need, I would do it differently.
In the gradle build file you can use the buildConfig
keyword to add a specific line to the BuildConfig.java
generated class.
So you could add do something like that in your build.gradle
:
release {
buildConfig "public static final String USE_REPORTING = true;"
}
debug {
buildConfig "public static final String USE_REPORTING = false;"
}
And so have only one PlayerEnvConfig
with
public static final boolean USE_REPORTING = BuildConfig.USE_REPORTING;
Or even no more PlayerEnvConfig
and use directly the BuildConfig
class.
EDIT Since an update, the syntax has changed :
buildConfigField "<type>", "<name>", "<value>"
This is documented in https://code.google.com/p/android/issues/detail?id=52962 . As you've found out, the build type isn't propagated to library projects, and there isn't a good workaround. If you have control over the code of the library project, you could make the debug status a mutable global variable, and set it from your main application on startup. It's a bit of a hack, and it has the disadvantage that the compiler can't optimize the unused code paths away from release builds, but unless something unusual is going on it should work.
This is not possible with library projects as you yourself mentioned.
You could just change the library project to an application project. That seems to work fine (at least in theory, I haven't tested it myself).
The other way would be to override that class in your application project. Your application project class will be chosen when merging takes place and you'll have those values available.
UPDATE - since the time of this posting, there have been much progress in the gradle build process, thus this answer might not be the recommended best practice and new changes might even brake it. Use your own discretion.
I believe that there is a bit of confusion over the whole project structure and configuration. Let's say that you have the following build.gradle configuration
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java']
//resources.srcDirs = ['src/main']
//aidl.srcDirs = ['src/main']
//renderscript.srcDirs = ['src/main']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
Your project folder structure should be as follow
project_root
-src
-main
-java
-com
-example
-build-types
-debug
-java
-com
-example
-FooBar.java
-release
-java
-com
-example
-FooBar.java
FooBar.java
must not be in the prooject_root/src/main/java/com/example
. It must be in debug
and release
folder which is to reside outside src
folder but inside build-types
folder. That is configured by setRoot('build-types/*****')
method. A lot of people get confused from seeing 'debug/java' and 'main/java', where the later is referenced in a manner 'src/main/java' from presentation and end up putting 'debug/java' in src, the wrong folder. I hope this help.
For more complex environment involving other libraries, you can check out my answer here https://stackoverflow.com/a/19918834/319058
It's a @bifmadei answer from google code issue and it helps for me:
Try setting this in the dependency project
android {
publishNonDefault true
...
}
and this in the project that uses it
dependencies {
releaseCompile project(path: ':theotherproject', configuration: 'release')
debugCompile project(path: ':theotherproject', configuration: 'debug')
}
Taken from here: https://code.google.com/p/android/issues/detail?id=66805
As Scott points out, this is a known shortcoming of Gradle. As a workaround, you can use this method, which uses reflection to get the field value from the app (not the library):
/**
* Gets a field from the project's BuildConfig. This is useful when, for example, flavors
* are used at the project level to set custom fields.
* @param context Used to find the correct file
* @param fieldName The name of the field-to-access
* @return The value of the field, or {@code null} if the field is not found.
*/
public static Object getBuildConfigValue(Context context, String fieldName) {
try {
Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");
Field field = clazz.getField(fieldName);
return field.get(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
To get the DEBUG
field, for example, just call this from your Activity
:
boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");
I have also shared this solution on the AOSP Issue Tracker.