I currently have a series of components with java, aidl, assets, resources, jni, and manifests and proguard files to support the components.
I would like to deliver AAR files with a number of different combinations of these components.
I would like to be able to debug the code in each component when assembled (which I think means making a project that includes all the components source files, as AAR explosion doesn't do release/debug variants.)
I want to use the experimental gradle plug in for the NDK part.
My first hack looks like:
model {
android {
// ... stuff
sources {
main {
def mySourceSet = ["../../sourceTree/client",
"../../sourceTree/instrumentation",
"../../sourceTree/engine"]
java {
source {
srcDirs = mySourceSet } } }
aidl {
source {
srcDirs = mySourceSet } } }
resources {
source {
srcDirs = mySourceSet } } }
assets {
source {
srcDirs = mySourceSet } } }
manifest {
source {
srcDirs = mySourceSet } } }
jniLibs {
source {
srcDirs = mySourceSet } } }
jni {
source {
srcDirs = mySourceSet } } }
}
}
}
}
The java classes get combined as I would like.
The aidl files get combined as I would like.
Everything else is not quite there (manifests aren't merged, resources/assets pick up java classes, and still using old .so from previous build system.)
Going into the different rules, it looks like mySourceSet is going to need repetition to do the right thing for the non java/aidl files to get the format right to pick things up (or exclude them.) I've been trying (with little success) to see what I can do with += notation and if I can move those to a gradle settings/config fragment in the sourceTree, include it, and have it modify the srcDirs.
I'd like something like one of these to work:
model { android { sources { main { aidl { source { srcDirs += "../../sourceTree/instrumentation" } } } } } }
model.android.sources.main.aidl.source << { srcDirs += "../../sourceTree/instrumentation" }
model.android << { sources { main { aidl { source { srcDirs += "../../sourceTree/instrumentation" } } } } }
but they fail with various "you can't do that" errors.
Is there a way to set the srcDirs outside the android { model {}} block?
Any hints on how to make the assets/resources/manifest merge correctly given a list of top level directories it should look through?
Related
Gradle 2.13
Revision: 3b427b1481e46232107303c90be7b05079b05b1c
OS: Linux 3.10.0-327.36.3.el7.x86_64 amd64
In linux on calling the clean task the contents of buildDir path are not deleted whereas the same in windows deletes the contents of buildDir(expected behaviour). Whats the reason ?
Code sample
apply plugin : 'java'
ant.importBuild 'build.xml'
sourceCompatibility = 1.8
def projVersion = ant.properties['version']
def projName = "xyz"
def buildPath = "/home/test/build"
def dependencyPath = "/home/test/dependency"
buildDir = new File("$buildPath","$projName")
def serviceDirBin = new File(buildDir , 'bin')
def serviceDirConf = new File(buildDir , 'conf')
def serviceDirThirdparty = new File(buildDir , 'thirdparty')
repositories {
flatDir {
dirs file("$dependencyPath"),
}
}
sourceSets{
main{
java{
srcDir 'src'
}
output.classesDir 'classes'
}
test{
java {
srcDir 'src/test'
}
}
}
dependencies {
/*Some compile dependencies*/
}
jar{
destinationDir = new File(serviceDirThirdparty, 'lib')
baseName='xyz'
manifest {
'Build-Timestamp': new Date().format('yyyy-dd-MM HH:mm:ss'),
'Specification-Version': '1.0',
'Implementation-Version': "$projVersion"
}
}
task xyzpackager << {
copy{
from ("$buildPath/sf/distribution/bin")
into file(serviceDirBin)
}
copy{
from ('conf')
into file(serviceDirConf)
}
copy{
from configurations.compile
from configurations.runtime
into new File(serviceDirThirdparty,'lib')
}
}
test {
reports {
html.enabled = false
junitXml.enabled = true
junitXml.destination = file("TestReport/xml")
}
}
jar.doLast {
delete "$buildDir/tmp","$buildDir/dependency-cache","$buildDir/classes","$buildDir/libs"
}
compileTestJava.doLast{
delete "TestReport"
}
the jar is copied to thirdparty folder and the bin/conf folders have some other files. SO basically i want to delete the buildDir before every new build
I am upgrading my project from experimentalNdk to ndkBuild
I have copied one of the previously generated Android.mk from build/intermediates/ndk/green/debug/Android.mk to my main jni folder.
I kept most of it but the following three includes, as they are flavor/buildType specific: (assuming productFlavor is "green")
LOCAL_C_INCLUDES += C:\path\to\project\modulename\src\green\jni
LOCAL_C_INCLUDES += C:\path\to\project\modulename\src\debug\jni
LOCAL_C_INCLUDES += C:\path\to\project\modulename\src\greenDebug\jni
I managed to add two of those lines via gradle:
externalNativeBuild {
ndkBuild {
path "$projectDir/src/main/jni/Android.mk"
}
}
productFlavors {
green {
externalNativeBuild {
ndkBuild {
arguments "LOCAL_C_INCLUDES+=$projectDir\src\green\jni"
}
}
}
... Other flavors ...
}
buildTypes {
debug {
externalNativeBuild {
ndkBuild {
arguments "LOCAL_C_INCLUDES+=$projectDir\src\debug\jni"
}
}
}
... Other build types ...
}
But where can I add the third line, that combines both?
LOCAL_C_INCLUDES+=$projectDir\src\greenDebug\jni
As part of an Android app that uses the NDK, I need to export some constants from the C/C++ world into Java. For obvious reasons, I'd rather have this automated. I'm using Android Studio with the NDK support.
How can I generate some .java file on the fly from a shell script that would be ran by Gradle whenever the app builds? Ideally this .java file would go in an build intermediaries directory somewhere and wouldn't have to be in the app source directory.
As an example, the shell script would generate this Java source:
public enum Type {
FOO,
BAR
}
from this C++ source:
enum class Type {
FOO,
BAR
}
For reference here's a simplified version of the Gradle file I'm starting from in Android Studio:
apply plugin: 'com.android.model.application'
model {
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "..."
minSdkVersion.apiLevel = 18
targetSdkVersion.apiLevel = 23
}
defaultConfig.multiDexEnabled = true
}
android.ndk {
platformVersion = "18"
moduleName = "jni"
...
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
ndk.with {
CFlags.add("-Werror")
cppFlags.add("-Werror")
}
}
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
}
}
repositories {
...
}
dependencies {
...
}
apply plugin: 'com.google.gms.google-services'
You could just write the generated file to the $buildDir/generatedJava then add that directory as a source folder. Then make the task javaCompile depend on your task that generates the source. Something like this could be used inside a build.gradle
def outputJavaFile = new File("$buildDir.absolutePath/generatedJava", 'MyEnum.java')
task generateSources(type: Exec) {
def source = $/
package com.example;
public enum Something {
One,
Two
}
/$
if (!outputJavaFile.parentFile.exists()) {
outputJavaFile.parentFile.mkdirs()
}
outputJavaFile.withWriter {
it << source
}
}
compileJava.dependsOn outputJavaFile
sourceSets {
main {
java {
srcDirs 'src/main/java', outputJavaFile.absolutePath
}
}
}
// if the goal is to generate the source from a script then just call the script
// inside the Exec closure
task shellScriptToGenerateSources(type: Exec) {
commandLine 'myShellScript.sh'
}
// then make compileJava depend on the task that runs the script
compileJava.dependsOn shellScriptToGenerateSources
Edit: To apply the same logic to your updated build.gradle file might look something like this
apply plugin: 'com.android.model.application'
// define an output folder for our generated .java files
def GENERATED_JAVA_OUTPUT = "$buildDir/generatedJava"
// if the goal is to generate the source from a script then just call the script
// inside the Exec closure
task shellScriptToGenerateSources(type: Exec) {
commandLine 'myShellScript.sh'
}
// then make compileJava depend on the task that runs the script
compileJava.dependsOn shellScriptToGenerateSources
model {
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "..."
minSdkVersion.apiLevel = 18
targetSdkVersion.apiLevel = 23
}
defaultConfig.multiDexEnabled = true
}
android.ndk {
platformVersion = "18"
moduleName = "jni"
...
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
ndk.with {
CFlags.add("-Werror")
cppFlags.add("-Werror")
}
}
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
}
// let android know that our java sources shoudl also consider the generated java for the compiler
android.sourceSet {
main {
java {
srcDir(GENERATED_JAVA_OUTPUT)
}
}
}
}
repositories {
...
}
dependencies {
...
}
apply plugin: 'com.google.gms.google-services'
I have a multiproject build where I need to publish some dependencies to a custom local Maven repository on disk and then add this folder to a distribution zip.
I define publishing tasks for each subproject using the maven-publish plugin.
subprojects {
apply plugin: 'maven-publish'
configurations {
offlineDependencies
}
publishing {
publications {
configurations.each { config ->
if (config.name == "offlineDependencies") {
def files = config.files
config.dependencies.each { dep ->
files.each { file ->
if (file.name == "${dep.name}-${dep.version}.jar") {
"${dep.name}"(MavenPublication) {
artifact (file) {
groupId = "${dep.group}"
artifactId = "${dep.name}"
version = "${dep.version}"
}
}
}
}
}
}
}
}
repositories {
maven {
name 'dependencies'
url '../build/repository'
}
}
}
}
Using the distribution plugin I create a zip file
distributions {
release {
baseName 'release'
contents {
from('src/main/resources/')
into("repository"){
from("$buildDir/repository")
}
}
}
}
How can I make sure that all the dynamically created publish tasks are run before creating the zip file?
I tried making a new task for all subprojects that depends on the dynamically created tasks, but it seems they're not created yet at that time.
subprojects {
task offlineDep << {
println 'Creating offline dependencies'
}
offlineDep.dependsOn {
tasks.findAll { task -> task.name.endsWith('PublicationToDependenciesRepository') }
}
}
I found a solution to this problem. By collecting the names of the artifacts and generating the tasknames I know will be created later and adding them as dependencies.
subprojects {
apply plugin: 'maven-publish'
def offlineDependencyNames = []
publishing {
publications {
configurations.each { config ->
if (config.name == "offlineDependencies") {
def files = config.files
config.dependencies.each { dep ->
files.each { file ->
if (file.name == "${dep.name}-${dep.version}.jar") {
offlineDependencyNames << dep.name
"${dep.name}"(MavenPublication) {
artifact (file) {
groupId = "${dep.group}"
artifactId = "${dep.name}"
version = "${dep.version}"
}
}
}
}
}
}
}
}
repositories {
maven {
name 'dependencies'
url "${rootProject.buildDir}/repository"
}
}
}
task publishOfflineDependencies
publishOfflineDependencies.dependsOn {
offlineDependencyNames.collect { name ->
"publish${name[0].toUpperCase()}${name.substring(1)}PublicationToDependenciesRepository"
}
}
}
releaseDistZip.dependsOn {
subprojects.collect {
p -> p.path + ':publishOfflineDependencies'
}
}
Suppose I have such build.gradle:
android {
productFlavors {
flavor1 {
}
flavor2 {
}
}
}
How do I specify different dependencies such as:
dependencies {
flavor1DebugCompile ...
flavor1ReleaseCompile ...
flavor2DebugCompile ...
flavor2ReleaseCompile ...
}
Gradle will generate errors such as: Could not find method flavor1DebugCompile() for arguments ...
it's a bug.
try this:
def customDeps = [
flavor1DebugCompile : dependencies.project(path: ':yourproject', configuration: 'flavor1Debug'),
flavor2DebugCompile : dependencies.project(path: ':yourproject', configuration: 'flavor2Debug'),
flavor1ReleaseCompile : dependencies.project(path: ':yourproject', configuration: 'flavor1Release'),
flavor2ReleaseCompile : dependencies.project(path: ':yourproject', configuration: 'flavor2Release'),
]
configurations.all() { config ->
Dependency d = customDeps.get(config.name)
if (d != null) {
config.dependencies.add(d)
}
}