Android Studio Gradle: Execute static Java Method

2019-02-18 15:45发布

I am trying to run the static main method of a java class from my build.gradle script asp art of the build process. I am using Android Studio 1.0.2 with the Android/Gradle Plugin 'com.android.tools.build:gradle:1.0.0'

The java class whose main method I want to run during the build resides in ...\trunk-gradle\myproject\src\main\java\de\myapp\gradle

package de.myapp.gradle;

public class ConfigureCustomer {

    public static void main(String[] args){
        String server = args[0];
        String customer = args[1];
        System.out.println(String.format("Configuring customer %s with server %s", customer, server));
    }
}

Before I used ANT to call that java method as follows:

<java failonerror="yes" classname="de.myapp.gradle.ConfigureCustomer ">
    <classpath>
        <path location="${base.dir}/bin/classes/"/>
    </classpath>
    <arg line="${customer}"/>
    <arg line="${server }"/>
</java>

But now I am migrating to Groovy, so here is the relevant part of my project's build.gradle file that tries to execute the main method of above class (actual task definition is at the end just before the dependencies):

apply plugin: 'com.android.application'
android {

    project.ext.set("customer", "")
    project.ext.set("server", "")

    dexOptions {
        preDexLibraries = false
    }

    compileSdkVersion 19
    buildToolsVersion "21.1.2"

    defaultConfig {
//Default configuration
    }


    signingConfigs {
        release {
//Configuration for release builds
        }
    }


    buildTypes {

        debug{
            server = "test"
        }

        release {
            server = "release"
        }
    }

    productFlavors {
        customerA{
            customer = "a"
        }
        customerB{
            customer = "b"
        }
        customerC{
            customer = "c"
        }
    }
}

task (configureCustomer,  type: JavaExec) {
    println 'Running customer configuration...'
    main = 'de.myapp.gradle.ConfigureCustomer'
    args customer, server
}

dependencies {
    //Dependency settings
}

So now when I run the following via the command line (windows):

graldew configureCustomer

I get the following error message:

Error: Could not find or load main class de.myapp.gradle.ConfigureCustomer

My questions hence are as follows:

  1. How do I manage to fix the error message above? Do I have to move my java class to another folder? Maybe configure sth in the build scipt?
  2. How can I make sure the java task is executed after the classes have actually been compiled?
  3. If i wanted to execute the task configureCustomer as part of another task, would I simply write the following line in my gradle's task definition?

configureCustomer

I also tried to add the classpath:

task (configureCustomer,  type: JavaExec) {
    println 'Running customer configuration...'
    main = 'de.myapp.gradle.ConfigureCustomer'
    classpath = sourceSets.main.runtimeClasspath
    args customer, server
}

But all that got me was a gradle build error message saying:

Could not find property "main" on SourceSet container

So apparently "sourceSets.main.runtimeClasspath" does not exist in Android Studio's Gradle. Maybe it's named differently. Though I also tried setting the classpath like this:

classpath = '${projectDir.getAbsolutePath()}\\build\\intermediates\\classes\\' + customer + '\\release'

and I also tried this:

classpath = '${projectDir.getAbsolutePath()}\\build\\intermediates\\classes\\' + customer + '\\release\\de\\myapp\\gradle'

None of which worked, the error from above persists:

Error: Could not find or load main class de.myapp.gradle.ConfigureCustomer

2条回答
一纸荒年 Trace。
2楼-- · 2019-02-18 16:17

I finally found something that works for Android/Gradle but getting there seemed a lot more complicated, than it should have been.

So for recap - here is the Java class whose main method I'd like to execute:

package de.myapp.gradle;

public class ConfigureCustomer {

    public static void main(String[] args){
        String customer = args[0];
        String versionName = args[1];
        System.out.println(String.format("Configuring customer %s with versionName %s", customer, versionName ));
    }
}

I want to execute the above for each flavor and only for release builds (not debug builds) so here is my task definition (you'd still have to make your task depend on one of the gradle build tasks so it's executed - I am depending on the preBuild task for this purpose):

android {
//Build type setup, signing configuration and other stuff
}

//After the android block my task definition follows:

task buildPrintout(type: JavaExec) {
    android.applicationVariants.all { variant ->
    //Runt he java task for every flavor
        variant.productFlavors.each { flavor ->
            println "Triggering customer configuration for flavor " + flavor.name
            if (variant.buildType.name.equals('release')) {
                //Run the java task only for release builds
                //Cant find the runtime classpath in android/gradle so I'll directly link to my jar file here. The jarfile contains the class I want to run (with the main method)
                classpath += files("libs/my-jarfile.jar")
                //This is the fully qualified name of my class, including package name (de.myapp.gradle) and the classname (ConfigureCustomer)
                main = "de.myapp.gradle.ConfigureCustomer"
                //Pass in arguments - in this case the customer's name and the version name for the app (from AndroidManifest.xml)
                args flavor.name, variant.versionName
            }
        }
    }
}

You'll notice that I dumped the idea of having my Class integrated in the android project I am about to build. Instead I made that one class a separate project, built a jar file and dropped it in the libs folder of the android project i am building.

UPDATE 04.02.2015

I have slightly modified the above to use the javaexec method instead of the JavaExec Task type:

preBuild.doFirst {
    android.applicationVariants.all { variant ->
        variant.productFlavors.each { flavor ->
            if (variant.buildType.name.equals('release')) {
                javaexec {
                    println "Triggering customer build for flavor " + flavor.name
                    classpath += files("libs/my-jarfile.jar")
                    main = "de.myapp.gradle.ConfigureCustomer"
                    args flavor.name, variant.versionName
                }
                println "Done building customer for flavor " + flavor.name
            }
        }
    }
}

And here is yet another variation, where we define the javaexec within a reusable (which is preferred) task, that we then add as a dependency to the preBuild task:

//Define our custom task and add the closures as an action
    task buildCustomer << {
        android.applicationVariants.all { variant ->
            variant.productFlavors.each { flavor ->
                if (variant.buildType.name.equals('release')) {
                        javaexec {
                            println "Triggering customer build for flavor " + flavor.name
                            classpath += files("libs/my-jarfile.jar")
                            main = "de.myapp.gradle.ConfigureCustomer"
                            args flavor.name, variant.versionName
                        }
                        println "Done building customer for flavor " + flavor.name
                }
            }
        }        
    }
    //Make preBuild depend on our task
    preBuild.dependsOn buildCustomer

If you have any questions let me know and I'll try to answer them.

查看更多
对你真心纯属浪费
3楼-- · 2019-02-18 16:29

Change the way of configing classpath

classpath(files('build/intermediates/classes/release',"${android.getSdkDirectory().getAbsolutePath() + '/platforms/' + android.compileSdkVersion + '/android.jar'}"))

It works on android gradle 1.5

查看更多
登录 后发表回答