I have a custom task in my build.gradle file that does bytecode transformations on class files before getting dex'd that looks like this:
task droidcook(type: JavaExec) {
main 'org.tsg.android.asm.Main'
}
afterEvaluate { project ->
android.applicationVariants.each { variant ->
variant.javaCompile.doLast {
project.tasks.droidcook.configure {
classpath variant.javaCompile.classpath
classpath "build/classes/" + variant.dirName
classpath sdk.dir + "/platforms/android-19/android.jar"
classpath "compile-libs/droidcook.jar"
args "build/classes/" + variant.dirName
args "com.example"
// args "-debug"
// args "-asmifier"
}
project.tasks.droidcook.execute()
}
}
}
The issue with the above is the classpath sdk.dir + ... line where sdk.dir isn't evaluated appropriately. To get this working, I currently have to hard code the path to the android.jar.
Bonus points if you can answer with an appropriate value to replace android-19 with for accessing a platform specific android.jar based on project configuration. :D
I don't see a published API to expose sdk.dir to your build file, so I just cribbed the code from https://android.googlesource.com/platform/tools/build/+/d69964104aed4cfae5052028b5c5e57580441ae8/gradle/src/main/groovy/com/android/build/gradle/internal/Sdk.groovy to read it manually. As for replacing android-19, if I read android.compileSdkVersion I get that exact string. I'm not sure that this is a published API either, so it may be subject to change and breakage in future versions of the Android Gradle plugin.
With that said, this works for me:
afterEvaluate {
def rootDir = project.rootDir
def localProperties = new File(rootDir, "local.properties")
if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDir = properties.getProperty('sdk.dir')
def androidJarPath = sdkDir + "/platforms/" + android.compileSdkVersion + "/android.jar"
print androidJarPath + "\n"
}
}
If there's no local.properties, this code is going to fail. If you care about that case, you can copy more code from Sdk.groovy to mimic its behavior in trying to find a reasonable default.
There's a much simpler way, although it isn't documented, so it probably isn't officially supported.
println "${android.getSdkDirectory().getAbsolutePath()}"
Oddly this method only seems to be available for certain versions of the gradle plugin. It isn't available in the commit linked above by Scott. If the above code doesn't work, then try this:
println "${android.plugin.getSdkFolder().getAbsolutePath()}"
For completeness, here's how to get the ndk.dir variable, too:
println "${android.plugin.getNdkFolder().getAbsolutePath()}"
As of android gradle plugin v2.1.2, this is what I use in my gradle script:
android.ndkDirectory.path
android.sdkDirectory.path
For example to explicitly launch ndk-build:
task ndkBuild(type: Exec) {
commandLine android.ndkDirectory.path+'/ndk-build', '-C', file('src/main').absolutePath
}
Use:
String androidJar = android.getBootClasspath()[0]
Assuming you're using SDK 21, this would set '<path-to-SDK>/platforms/android-21/android.jar' into variable androidJar (the SDK version selection performed automatically).
The next step would obviously be replacing 'classpath sdk.dir ...' etc. with:
classpath androidJar
Related
I have an android gradle project structure that looks like this
module1-aar
module2-aar
testapp-apk
Key facts
module2-aar depends on module1-aar
testapp-apk depends on module2-aar
JDK11
Gradle 7.4.2
Android gradle plugin 7.1.3
Without javadocs, gpg, signing, or publishing, everything builds just fine. App runs, everything is great.
When i started adding in tasks to generate javadocs, that's when everything went haywire. module1-aar will build and generate javadocs with no problem. module2-aar however always fails during the javadoc task.
Task is below. Most of it was borrowed from here How to generate javadoc for android library when it has dependencies which are also aar libraries?
project.task("javadoc", type: Javadoc) {
afterEvaluate {
configurations.all
.each {item ->
item.setCanBeResolved(true)
}
classpath += configurations.api
classpath += configurations.implementation
// Wait after evaluation to add the android classpath
// to avoid "buildToolsVersion is not specified" error
classpath += files(android.getBootClasspath())
// Process AAR dependencies
def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
classpath -= aarDependencies
//fails here when an AAR depends on an AAR
aarDependencies.each { aar ->
// Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
def outputPath = "$buildDir/tmp/aarJar/${aar.name.replace('.aar', '.jar')}"
classpath += files(outputPath)
// Use a task so the actual extraction only happens before the javadoc task is run
dependsOn task(name: "extract ${aar.name}").doLast {
extractEntry(aar, 'classes.jar', outputPath)
}
}
}
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += project.files(android.getBootClasspath())
classpath += configurations.implementation
classpath += fileTree(dir: project.buildDir.absolutePath + "/tmp/aarsToJars/")
classpath += files(project.buildDir.absolutePath + "/intermediates/compile_r_class_jar/release/R.jar")
classpath += files(project.buildDir.absolutePath + "/generated/source/buildConfig/release/release")
classpath += files(project.buildDir.absolutePath + "/generated/source/r/buildConfig/release/release")
destinationDir = file( project.buildDir.absolutePath + "/outputs/javadoc/")
failOnError true
options.charSet 'UTF-8'
options.docEncoding 'UTF-8'
options.encoding 'UTF-8'
options.addBooleanOption 'Xdoclint:none', true
exclude '**/BuildConfig.java'
exclude '**/R.java'
exclude '**/doc-files/*'
}
// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
if (!archive.exists()) {
throw new GradleException("archive $archive not found")
}
def zip = new java.util.zip.ZipFile(archive)
zip.entries().each {
if (it.name == entryPath) {
def path = new File(outputPath)
if (!path.exists()) {
path.getParentFile().mkdirs()
// Surely there's a simpler is->os utility except
// the one in java.nio.Files? Ah well...
def buf = new byte[1024]
def is = zip.getInputStream(it)
def os = new FileOutputStream(path)
def len
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len)
}
os.close()
}
}
}
zip.close()
}
//wires in the javadoc task to the normal build
tasks.named("build") { finalizedBy("generateJavadocJar") }
The error message i'm getting is the following
* What went wrong:
A problem occurred configuring project ':module2-aar'.
> Could not resolve all files for configuration ':module2-aar:implementation'.
> Could not resolve project :module1-aar.
Required by:
project :module2-aar
> Cannot choose between the following variants of project :module1-aar:
- debugRuntimeElements
- releaseRuntimeElements
All of them match the consumer attributes:
- Variant 'debugRuntimeElements' capability com.github.test:module1-aar:6.1.11-SNAPSHOT:
- Unmatched attributes:
- Provides com.android.build.api.attributes.AgpVersionAttr '7.1.3' but the consumer didn't ask for it
- Provides com.android.build.api.attributes.BuildTypeAttr 'debug' but the consumer didn't ask for it
- Provides com.android.build.gradle.internal.attributes.VariantAttr 'debug' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
- Variant 'releaseRuntimeElements' capability com.github.test:module1-aar:6.1.11-SNAPSHOT:
- Unmatched attributes:
- Provides com.android.build.api.attributes.AgpVersionAttr '7.1.3' but the consumer didn't ask for it
- Provides com.android.build.api.attributes.BuildTypeAttr 'release' but the consumer didn't ask for it
- Provides com.android.build.gradle.internal.attributes.VariantAttr 'release' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
I've been playing around with the gradle task a bit and it seems that the error message is generated anytime i attempt to iterate over the classpath of the module2-aar.
I have tried a number of other suggestions, like changing module2-aar's dependency declaration from
api project(':module2-aar')
to
api project(path:':module2-aar')
However that doesn't do anything
I also tried this:
api project(path: ':module1-aar', configuration: 'default')
While the above resolves the reported issue, it causes a compile issue whereby module2-aar doesn't appear to have module1-aar in the classpath during compile...and it seems to compile before module1-aar.
Unfortunately, the documentation for what configuration means when referencing an android project is a bit thin, or perhaps I'm looking in the wrong place. I'm not sure what other valid values are available.
Anyhow, I'm not sure what's wrong here other than I've spent way too much time on this.
I going to publish my solution to the problem of using "aar" files in javadoc. In the course of trying to solve the problem, I too, had been getting the same error that spy was referring to. That actually error means it can differentiate whether it should be using release or debug libraries. It seemed to me to be too futile to try and correct that issue, so instead, I took a different approach to solving what I think is essentially the same problem.
In my case, I have a project that contains multiple subprojects, and when I produce my javadoc documentation I wanted to produce a merged javadoc document, that consisted of just some of the subprojects (not all of the subprojects). As far as I know, this is not a capability, built into Android Studio. The current version of Android Studio(2021.2.1) seems to have problems producing javadoc documentation for android library modules. There are two issues:
1.) the javadoc classpath doesn't have the android bootclasses added. You get errors for referencing any android SDK method such as "Context", "Typeface", etc.
2.) the javadoc classpath doesn't get any AndroidX libraries added to it. Many of the AndroidX libraries are "aar" files. Android Studio(2021.2.1) does not handle aar files correctly when using javadoc.
My environment is similar to spy, except that I'm using android gradle plugin 7.2.0. I've created a custom javadoc task in the "app" module's build.gradle.kts script. My "app" module is an android application module. The code needs to be place in any module that contains either the plugin "com.android.application" or "com.android.library". Some of the modules that I produce the merged javadoc for are java libraries, and that's okay.
// create a custom configuration
val javadocDeps = configurations.create("javadocDeps")
// add javadoc dependencies that you need.
dependencies {
javadocDeps(project(":OsgiFramework"))
// note: I'm using a libs version catalog for the dependencies
// you can add hardwired dependencies if you prefer
javadocDeps (libs.androidx.appcompat)
javadocDeps (libs.androidx.fragment)
javadocDeps (libs.androidx.navigation.fragment)
javadocDeps (libs.androidx.navigation.ui)
javadocDeps (libs.androidx.constraint.layout)
}
// register the createCoreJavadoc task
// in my case, "gradlew app:createCoreJavadoc" creates the merged javadoc
tasks {
register<Javadoc>("createCoreJavadoc") {
setFailOnError(true)
val docDir: File = File(project.projectDir.parentFile.parentFile, "Doc/Core")
println("javadoc destination dir: " + docDir.absolutePath)
// set the location where the documentation is produced in
setDestinationDir(docDir)
// select the projects to produce merged javadoc for
var sourcepaths: FileCollection = project(":CoreInterfaces").files("src/main/java")
sourcepaths =
sourcepaths.plus(project(":CoreInternalInterfaces").files("src/main/java"))
sourcepaths = sourcepaths.plus(project(":CoreAndroidInterfaces").files("src/main/java"))
sourcepaths =
sourcepaths.plus(project(":CoreAndroidInternalInterfaces").files("src/main/java"))
sourcepaths = sourcepaths.plus(project(":OsgiInterface").files("src/main/java"))
sourcepaths =
sourcepaths.plus(project(":InstallPlanInterfaces_1_0_0").files("src/main/java"))
setSource(sourcepaths.asFileTree)
// fix the problem with the missing android bootclasses
android.bootClasspath.forEach{
classpath += fileTree(it)
}
// create a temporary directory for storing the "classes.jar" file contained in the *.aar files
val tmpDir:File = File(project.buildDir, "\\tmpAar\\")
if (tmpDir.exists()) tmpDir.delete()
tmpDir.mkdirs()
// add the javadoc dependencies
javadocDeps.forEach {
// I've got a custom class that allows me to treat jar or zip files and a file system
// you could replace this using spy's zip file extraction method
val zipFileSystem: com.phinneyridge.ZipFileSystem = ZipFileSystem(it.absolutePath,null)
if (it.name.endsWith(".aar")) {
// extract the classes.jar file from the aar file to the tmpDir
// renaming it to name of the aar file, but change the extension to jar
val tmpFile:File = File(tmpDir, it.name.replace(".aar", ".jar"))
zipFileSystem.extractEntry("classes.jar", tmpFile)
} else {
// for jar files, we just add it to the path
classpath += fileTree(it)
}
}
// now add the tmpDir files to the javadoc classpath
classpath += fileTree(tmpDir)
// for diagnosis purposes, we'll print the classpath.
// Notice that you have a lot more path entries then you have javadocDeps
println("classpath: " + classpath.asPath)
}
}
I understand that you have a project structure like this: app -> module2 -> module1.
Where -> means the dependency stream. So I deployed a project with that same dependency flow, but using gradle 7.0.2 (because that's what I'm currently using), and had no problem generating javadoc for module2 and module1
Basically it boils down to implementing this in every gradle of every module: https://stackoverflow.com/a/73096187/9902249
I hope it works for you.
I am developing Android library with CI(Continuous Integration) support in git server. The configuration use a .yaml or .yml file. The build system that I use is the default one from Android Studio, which is gradle, so I also use .gradle configuration files here. My question is, how can I share variables between those files? Because I need to upgrade some variables that actually the same from each file, like ANDROID_API_LEVEL, ANDROID_BUILD_TOOLS_VERSION, etc. It will be inconvenience if I should edit every file to upgrade version. Is there any best practice that I can use?
For example, here is my yaml file looks like
language: android
sudo: false
dist: precise
env:
global:
- ANDROID_API_LEVEL=27
- ANDROID_EMULATOR_API_LEVEL=21
- ANDROID_BUILD_TOOLS_VERSION=27.0.3
- ANDROID_ABI=armeabi-v7a
...
And here is my project-level gradle file looks like
buildscript {
ext {
kotlinVersion = '1.2.31'
ankoVersion = "0.10.2"
compileSdkVersion = 27
buildToolsVersion = "27.0.3"
minSdkVersion = 14
targetSdkVersion = 27
androidSupportVersion = "27.1.1"
}
...
Let's say I want to share the value of a variable ANDROID_BUILD_TOOLS_VERSION in yaml file with buildToolsVersion in gradle file.
You can use SnakeYAML for reading and writing properties from YAML files.
Take a look at this answer, they talk about the same problem.
Update answer with example
The implementation is exactly the same since both, Android Studio and Spring (in this case), use Gradle as the main executive buildtool. The link i shared showed the basic principle on how to access YAML properties in your build.gradle and was intended as a how-to-start.
This will synchronise selected env.global properties of your build.gradle file with your YAML file. Trivial properties like language, sudo and dist stay untouched by this action. The main file to maintain in this case would be the build.gradle file since the YAML file will be maintained by Gradle.
I wrote a short snippet on how to attain this:
File: cfg.yaml
language: android
sudo: false
dist: precise
env:
global:
- ANDROID_API_LEVEL=27
- ANDROID_EMULATOR_API_LEVEL=21
- ANDROID_BUILD_TOOLS_VERSION=27.0.3
- ANDROID_ABI=armeabi-v7a
File: build.gradle
import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.Yaml
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'org.yaml', name: 'snakeyaml', version: '1.21'
}
}
ext {
buildToolsVersion = '27.202'
}
task updateYAMLFile() {
def configurationYAML = "cfg.yaml"
inputs.files buildscript.sourceFile
outputs.files configurationYAML
DumperOptions options = new DumperOptions()
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK)
options.setPrettyFlow(true)
Yaml yaml = new Yaml(options)
ext {
updateGlobalProperties = { cfg, name, version ->
def index = (int) cfg.env.global.findIndexValues { it ==~ /$name.*/ }[0]
cfg.env.global.set(index, name + '=' + version)
}
}
doLast {
def cfg = yaml.load(new File(configurationYAML).newInputStream())
updateGlobalProperties(cfg, 'ANDROID_BUILD_TOOLS_VERSION', buildToolsVersion)
FileWriter writer = new FileWriter(configurationYAML)
yaml.dump(cfg, writer)
}
}
I've gone through almost entire Internet in search of a way how to aggregate Javadocs in the project consisting of separate library modules into single Javadoc.
There is a plugin that apparently allows to do that:
https://github.com/nebula-plugins/gradle-aggregate-javadocs-plugin
However, if I run the command specified by the plugin Gradle finds the task and executes it but no output directory is generated.
Any help how to build single Javadoc from multiple modules much appreciated.
I managed to get it working some time ago, apologies for a late response. The solution for aggregatable Javadoc creation is the following:
In each of the subprojects maintained within the project create a task generating the Javadoc:
android.libraryVariants.all { variant ->
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
destinationDir = project.file("$project.projectDir/javadoc/$project.PROJECT_NAME") //Project name in the Project's gradle.properties
title = "A title of my project - $project.PROJECT_VERSION_NAME" //Project version name in the Project's gradle.properties
description "Generates Javadoc for $variant.name."
source = variant.javaCompile.source
ext.androidJar ="${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar) + project.files(android.getBootClasspath().join(File.pathSeparator))
options {
memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PUBLIC //change the modifier according to your needs
links "http://docs.oracle.com/javase/8/docs/api/"
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
}
exclude '**/BuildConfig.java'
exclude '**/R.java'
}
task("bundle${variant.name.capitalize()}Javadoc", type: Jar) {
baseName = "Compass API - ($version)"
description "Bundles Javadoc into zip for $variant.name."
classifier = "javadoc"
from tasks["generate${variant.name.capitalize()}Javadoc"]
}
}
The configuration above adds a Javadoc generation task for each buildVariant of your subproject. At this point you can you can generate Javadoc for each module separately by typing
gradle :myRootProject:mySubproject:generateDebugJavadoc
gradle :myRootProject:mySubproject:generateReleaseJavadoc
gradle :myRootProject:mySubproject:generateMyFancyFlavourDebugJavadoc
gradle :myRootProject:mySubproject:generateMyFancyFlavourReleaseJavadoc
If you use JRE 8 the following configuration disables errors raised by doclint during the Javadoc build (explanation in greater detail here)
if (JavaVersion.current().isJava8Compatible()) {
tasks.withType(Javadoc) {
// disable the crazy super-strict doclint tool in Java 8
//noinspection SpellCheckingInspection
options.addStringOption('Xdoclint:none', '-quiet')
}
}
To aggregate Javadocs of each submodules into a single one create a Plugin in to build.gradle which will add a task to the submodule a partial Javadoc generation of which you are interested in:
class JavadocAggregationPlugin implements Plugin<Project> {
static final String AGGREGATE_JAVADOCS_TASK_NAME = 'aggregateJavadocs'
#Override
void apply(Project project) {
Project rootProject = project.rootProject
rootProject.gradle.projectsEvaluated {
Set<Project> librarySubprojects = getLibraryProjects(rootProject)
if (!librarySubprojects.isEmpty()) {
rootProject.task(AGGREGATE_JAVADOCS_TASK_NAME, type: Javadoc) {
description = 'Aggregates Javadoc API documentation of all subprojects.'
group = JavaBasePlugin.DOCUMENTATION_GROUP
dependsOn librarySubprojects.generateReleaseJavadoc //please note that generateReleaseJavadoc is the name of the separate Javadoc generation task in each library module
source librarySubprojects.generateReleaseJavadoc.source
destinationDir rootProject.file("$rootProject.buildDir/docs/javadoc") //Javadoc destination directory
classpath = rootProject.files(librarySubprojects.generateReleaseJavadoc.classpath)
}
}
}
}
private Set<Project> getLibraryProjects(Project rootProject) {
rootProject.subprojects.findAll { subproject -> subproject.plugins.findPlugin("com.android.library") } //In this case every library module is selected
}
}
Finally, include your plugin to the gradle configuration in the Project's build.gradle below your plugin definition.
apply plugin: JavadocAggregationPlugin
By doing this and rebuilding gradle's configuration you should be able to create aggregated Javadoc in specified directory by typing the following command via cli:
gradle aggregateJavadocs
Hope that helps somehow.
Helpful link: Android Gradle DSL
I've been building some tasks for a gradle multi-project build and have a need to get the class path for a project. The build script has projects that use the Java plugin and projects that use the Android plugin.
For the Java projects I was able to use the top voted answer in this question to get the class path using configurations.runtime.asPath; however, this is not working for the Android projects because there is no configurations.runtime property.
How can generate a classpath for a gradle project using the Android plugin?
Android projects may build multiple versions of the app. These are called variants. The most basic variants are "debug" and "release" The following code should create the classpath assignment for all the variants in a project. Place this code in the "build.gradle" file for the module.
android.applicationVariants.each { variant ->
variant.javaCompile.classpath += configurations.provided
}
You should be able to refer to a specific variant using the variant name:
debug.javaCompile.classpath
Here is a gradle task that generates the module jar and includes also the test classpath for all variants.
It is including libraries and the android.jar from selected runtime.
I've added two commandline executions for updating some env var inside emacs and for killing any running beanshell (with previous classpath).
task classpath(type: Jar) {
from android.sourceSets.main.java.srcDirs,
android.sourceSets.test.java.srcDirs
outputs.upToDateWhen { false }
doLast {
println "Building classpath..."
def cp2 = [android.getBootClasspath()[0], it.archivePath]
android.applicationVariants.all { v ->
cp2 += v.getApkLibraries()
}
def classpath = cp2.unique().join(":")
println "Updating emacs..."
exec {
executable "sh"
args "-c", "emacsclient --eval '(setenv \"CLASSPATH\" \""+classpath+"\")'"
}
exec {
executable "sh"
args "-c", "emacsclient --eval '(jdee-bsh-exit)'"
}
}
}
Be aware that I'm using ":" for joining the classpath
project.android.applicationVariants.all { v ->
v.getCompileClasspath(null).getFiles().each{
File f->
f.getAbsolutePath()//this is the one of classpath
}
}
Here is another example a gradle task that generates javadocs with umlgraph + graphiz in an android project and includes classpath for all variants using the coding example given in the user1737310's previous answer. It is manually including android.jar from the selected runtime, I am still looking for a way to retrieve it dynamically.
task javadoc(dependsOn: build) {
setDescription('Generates Javadoc API documentation with UMLGraph diagrams')
setGroup(JavaBasePlugin.DOCUMENTATION_GROUP)
doLast {
def javaFilePath = file('src/main/java')
def cp = [System.getenv('ANDROID_HOME')+'/platforms/android-26/android.jar'];
project.android.applicationVariants.all { v ->
v.getCompileClasspath(null).getFiles().each{
File f->
cp.add(f.getAbsolutePath())//this is the one of classpath
}
}
def classpath = ":"+cp.join(':')
if (javaFilePath.exists()) {
ant.javadoc(classpath: (configurations.umljavadoc).asPath + classpath,
sourcepath: file('src/main/java'),
packagenames: '*',
destdir: "${docsDir}/javadoc",
private: 'false',
docletpath: configurations.umljavadoc.asPath) {
doclet(name: 'org.umlgraph.doclet.UmlGraphDoc') {
param(name: '-inferrel')
param(name: '-inferdep')
param(name: '-qualify')
param(name: '-postfixpackage')
param(name: '-hide', value: 'java.*')
param(name: '-collpackages', value: 'java.util.*')
param(name: '-nodefontsize', value: '9')
param(name: '-nodefontpackagesize', value: '7')
param(name: '-link', value: 'http://java.sun.com/j2se/1.5.0/docs/guide/javadoc/doclet/spec')
param(name: '-link', value: 'http://java.sun.com/j2se/1.5/docs/api')
}
}
}
}
}
`
I have searched a lot, but haven't seen an answer for this. I have source that's in different flavors. Something like:
App/src/flavorA/MyFlavor.java
App/src/flavorB/MyFlavor.java
App/src/flavorC/MyFlavor.java
And it works great, until I need to run my AOP step. I found it couldn't complete because it was unable to find this class, which is referenced from source in App/src/main/.
This doesn't find the MyFlavor class:
android.applicationVariants.all { variant ->
variant.javaCompile.doLast {
def androidSdk = android.adbExe.parent + "/../platforms/" + project.ext.android_version + "/android.jar"
def iajcClasspath = configurations.compile.asPath + ";" + androidSdk
// This add's project jars as well as support jars.
project.ext.tree = fileTree(dir: "${project.buildDir}/intermediates/exploded-aar", include: '**/*.jar')
project.ext.tree.each { jarFile ->
iajcClasspath += ":" + jarFile
}
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties",
classpath: configurations.ajc.asPath)
ant.iajc(
source: "1.6",
target: "1.6",
destDir: "${project.buildDir}/intermediates/classes/${variant.dirName}",
fork: "true",
maxmem: "512m",
aspectPath: configurations.aspects.asPath,
inpath: configurations.ajInpath.asPath,
sourceRootCopyFilter: "**/.svn/*,**/*.java",
classpath: iajcClasspath
) {
sourceroots {
android.sourceSets.main.java.srcDirs.each {
pathelement(location: it.absolutePath)
}
pathelement(location: "${project.buildDir}/generated/source/r/${variant.dirName}")
pathelement(location: "${project.buildDir}/generated/source/buildConfig/${variant.dirName}")
}
}
}
}
I can get it working if I add in something like:
pathelement(location: "$`enter code here`{project.buildDir}/../src/flavorA/java")
But that's if I only want to build flavorA. Is there a better way of setting things up so that when the IAJC task runs, it can find the source that it needs for the particular variant that it's building? If I assembleFlavorARelease, my variant name is going to be something like flavorARelease and I can get the build type of "release" by doing variant.buildType.name but that's not going to help me. I need to point it to the source for the flavor I'm building.
I took the variant.name and subtracted the build type name off of it to be left with the "flavorA" part:
pathelement(location: "${project.buildDir}/../src/${variant.name.substring(0, variant.name.length() - variant.buildType.name.length())}/java")
Still seems wonky. What if I want to assembleRelease and build all flavors? There's got to be a better way of approaching this which I'm not seeing.
You can iterate over the available flavors for your particular variant using:
def currentFlavor;
variant.productFlavors.each { flavor ->
flavorToChoose = flavor
}
From here you can grab onto the flavor you want from the list and then add a path element similar to the "main" source set like:
android.sourceSets."${flavorToChoose}".java.srcDirs.each {
pathelement(location: it.absolutePath)
}
Make sure to stick this block in your sourceroots section.