Why does Android Studio not run my generateConfig but command line does - android-studio

I'm trying to generate identical assets for each of the subprojects in a project. Since exactly the same thing has to happen for each subproject, I'm trying to avoid having to add the generation code to each subproject.
What I've got so far is:
// in my outer build.gradle
allprojects { proj ->
gradle.projectsEvaluated {
def configTemplate = project.file('src/main/templates/configuration.json')
def android = proj.getProperties()['android']
if (configTemplate.exists() && android != null) {
task generateConfigFiles(type: ConfigureTask) {
template configTemplate
environments proj.rootProject.file('scripts/environments.json')
environmentName host
destination new File(project.buildDir, 'templates/configuration.json')
}
android.applicationVariants.all { variant ->
variant.mergeAssets.dependsOn generateConfigFiles
}
}
}
}
// each application build.gradle
android {
sourceSets {
main {
assets.srcDir 'build/templates'
}
}
}
This seems to work exactly as expected when I run gradle from the command line ./gradlew mergeQaDebugAssets runs the generateConfigFiles task before running mergeQaDebugAssets
If I attempt to run this from Android Studio using the gradle window, it never runs generateConfigFiles
I've also gotten it to work by just including the projectsEvaluated step in each of the project build.gradle files, but, as noted, I'm trying to avoid the code duplication and maintenance headaches that brings.

Related

How do I get file outputs of gradle task

I want to create a gradle task in Android Studio that will do something with the output of the build task of another project
task foo {
dependsOn ':someApp:build'
...
copy results of :someApp:build to another location
...
}
I can't just hardcode a path as I won't know if someApp was built as debug or release and the output paths will vary based on the type of build.
dynamic copy task without using hardcoded path.
applicationVariants.all {
variant->
variant.outputs.each { output ->
println("..a")
task "copy${variant.buildType.name}"(type:Copy){
println("${variant.buildType.name}")
dependsOn app:assembleDebug
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
// you can add multiple copy if required, i am doing it here release build was named app-release-unsigned.apk
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}-unsigned.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
}
}
}
I added a task in android block of build.gradle of app module.
applicationVariants.all {
variant->
variant.outputs.each { output ->
println("..a")
task "copy${variant.buildType.name}"(type:Copy){
println("${variant.buildType.name}")
dependsOn app:assembleDebug
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
// you can add multiple copy if required, i am doing it here release build was named app-release-unsigned.apk
copy {
from "$buildDir\\outputs\\apk\\${variant.buildType.name}\\app-${variant.buildType.name}-unsigned.apk"
into "C:\\Users\\rkumar8\\AndroidStudioProjects\\MyApplication\\app\\build\\outputs\\apk\\"
}
}
}
}
There is another post for adding our task in android build path.
https://discuss.gradle.org/t/how-to-insert-my-task-into-a-pre-defined-build-android-build/29685/3

Android Studio Gradle: how to get variant/flavour in custom assets processor task

I have simple assets processing gradle task prepare_assets in Android Studio 3.1.3. It is linked to preBuild task:
preBuild.dependsOn(prepare_assets)
Now I have several flavors for different resolution versions and I want to let prepare_assets know what assets to process. Maybe I don't get the idea of Gradle, but I can't understand how to achieve this: I tried to set variable in config phase
applicationVariants.all { variant ->
buildType = variant.buildType.name // sets the current build type
}
but when I read variable in my task it always the same.
In flavours section declaration:
all { flavor ->
task("${flavor.name.capitalize()}_prepare_assets") {
println "*** conf TEST for ${flavor.name.capitalize()}***"
doLast {
println "*** action TEST ${flavor.name.capitalize()}***"
if (flavor.name.equals("fullhd"))
{
//WARNING: to call copy, javaexec closures here use project.copy and project.javaexec!
}
else
{
...
}
}
}
}
In the bottom of file adding dependenses for runtime created android tasks for all flavors:
tasks.whenTaskAdded { theTask ->
if (theTask.class.name.contains("AppPreBuildTask_Decorated"))
{
for (Iterator iterator = android.productFlavors.iterator(); iterator.hasNext();) {
String flv_name = iterator.next().name.capitalize();
if (theTask.name.contains(flv_name+"Debug") || theTask.name.contains(flv_name+"Release"))
theTask.dependsOn "${flv_name}_prepare_assets";
}
}
}

How to properly add `mock` package to Android Studio project?

I want Android Studio to recognize my mock folder by putting mock at the end of the package name while in the Android pane.
How can I achieve this?
I've tried different combinations of:
right-clicking -> new package
right-clicking -> new Java Folder
declaring sourceSets in Gradle like so:
sourceSets {
mock {
java.srcDir 'src/mock'
}
}
add Mock as a flavor
productFlavors {
mock {
applicationIdSuffix = ".mock"
dimension "default"
}
prod {
dimension "default"
}
}
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
if (variant.buildType.name == 'release'
&& variant.flavors[0].name == 'mock') {
variant.ignore = true
}
}

Android Studio - Gradle assemble task

I'm currently struggling with a build process in gradle. My goal is to not have a specific java class in the final .apk for a specific flavor.
The logic goes like this:
1.) before compiling my project delete MyClass.java and copy it to a temp folder
2.) after assembling the apk copy back MyClass.java to my original folder
3.) delete the temp folder
This happens only if I build a specific flavor, so it doesn't happen for all build variants. My code works perfectly when I build only one flavor and one build variant e.g. assembleFlavorRelease, but if I wan't to make my code work for multiple build types; if I run assembleFlavor it should build flavorDebug the same way it does flavorRelease.
However my logic goes trough only the first time and after that it stops, so flavorDebug is build with MyClass and it shouldn't be, while flavorRelease doesn't include MyClass in the .apk because my code runs the first time.
Here is what the code looks like:
task copyResource << {
copy {
from 'src/main/java/MyClass.java'
into 'src/temp'
}
}
task deleteResource << {
delete {
'src/main/java/MyClass.java'
}
}
task deleteTemp << {
delete {
'src/temp'
}
}
task copyBackToSource << {
copy {
from 'src/temp/MyClass.java'
into 'src/main/java'
}
deleteTemp.execute()
}
android.applicationVariants.all { variant ->
if (variant.name.contains('flavor')) {
deleteResource.dependsOn copyResource
variant.javaCompile.dependsOn deleteResource
variant.assemble.doLast {
copyBackToSource.execute()
}
}
}
I think that the directories which I use in my code are somehow locked when trying to execute the whole process the second time?
I feel that you are approaching the problem in the wrong way. Instead of thinking
Put the java file in src/main/java and remove it from flavorX
You should instead be approaching it as
Add an extra source directory to the source sets for flavorY and flavorZ
Once you approach the problem like this it becomes much easier
If you only want the file in one flavor, you can put the file in the flavor specific source folder using the built in conventions (ie src/flavorX/java)
If you want the file in more than one flavor you could put MyClass.java in src/common/java and do something like
android {
productFlavors {
flavor1 {
}
flavor2 {
}
flavor3 {
}
}
}
sourceSets {
flavor1.java = ['src/flavor1/java','src/common/java']
flavor2.java = ['src/flavor2/java','src/common/java']
}
Ok so I got the right solution from here: https://discuss.gradle.org/t/android-gradle-assemble-tasks/10711
If you want to avoid compiling a specific class then use this:
variant.javaCompile.exclude '**/SourceFileToExclude.java'

Apply configuration to specific projects in gradle build script

I have a gradle project that has java applications as well as android applications.
root/
build.gradle
settings.gradle
java1/
java2/
android1/
android2/
java3/
etc.
What is the best practice for structuring my build script? I am a total gradle novice and am migrating the project from maven to gradle.
I wanted to do something instead of
configure(subprojects) {}
to apply plugins and other specific things.
such as
configure(java1, java2, java3) { // java specifics }
configure(android1, android2) { // android specifics }
I am probably approaching this from the wrong way.
More explicitly I need to apply the plugin java only for the java projects and the android plugin for the android projects.
configure(subprojects.findAll {it.name == "java1" || it.name == "java2"}) {
Under the filtering section in the guide
Hope this helps someone else out.
There are multiple ways, depending on what you want... Some examples:
// Configures just project java1
project(":java1") { ... }
// Configures projects java1 and java2
["java1","java2"].each { name ->
project(":$name") { ... }
}
You can use normal groovy to find/iterate over all the projects.
Another option:
configure([ project(':sub1'), project(':sub2'), ... ]) {
...
}
The shortest and easiest option:
configure(subprojects.findAll()) {
if (it.name.equals('MY_PROJECT')) {
...
} else {
...
}
}
Another approach...
In the settings.gradle you do define your projects like this:
gradle.ext.javaProjects=[]
gradle.ext.androidProjects=[]
javaProject('java1')
javaProject('java2')
javaProject('java3')
androidProject('android1')
androidProject('android2')
def javaProject(String name) {
gradle.ext.javaProjects.add(name)
include ":$name"
}
def androidProject(String name) {
gradle.ext.androidProjects.add(name)
include ":$name"
}
Now you can reference those in your root build.gradle:
def javaProjects = subprojects.findAll {gradle.ext.javaProjects.contains(it.name)};
def androidProjects = subprojects.findAll {gradle.ext.javaProjects.contains(it.name)};
configure(javaProjects) {
...
}
configure(androidProjects) {
...
}
Maybe thats overkill... but i usually have the project definition method in my settings.gradle anyway. E.g. if you want to put all java projects under a java folder you could define things like this:
def javaProject(String name) {
gradle.ext.javaProjects.add(name)
include ":$name"
project(":$name").projectDir = file('java/'+ name)
}

Resources