user3355139
user3355139

Reputation: 373

why does build.gradle doesn't look like Groovy?

I read the gradle was written in groovy.
However my build.gradle file doesn't look like groovy.
Infact it doesn't look like a language at all. Here's my build.gradle file:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.israelkariti.location2_1"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
    compile 'com.google.android.gms:play-services-maps:10.2.1'
    testCompile 'junit:junit:4.12'
}

Can someone please explain to me what's up with this syntax.
How does that syntax is a Groovy code?
And if i m missing something big than please elaborate on how this thing work.
thank you

Upvotes: 3

Views: 1054

Answers (1)

Lukas Körfer
Lukas Körfer

Reputation: 14493

Well, Gradle adds some magic for its DSL, but technically speaking is each Gradle script fully valid Groovy.

To understand all the things like dependencies, apply plugin: and so on, we need to learn about the different types of Gradle scripts:

  • Build scripts (build.gradle)
  • Settings scripts (settings.gradle)
  • Initialization scripts (e.g. init.gradle)

All these script are executed in different scopes, since they are "applied on" different objects. Gradle calls this behaviour "attaching a delegate object".

For build scripts (like the one, you asked about), this object is a Project. Now lets analyze your Gradle script:

apply plugin: 'com.android.application'

The Project interface extends the PluginAware interface, which defines an apply method taking a Map<String,?>. In Groovy, the map notation is [key:value, ...], brackets can be omitted and map keys of type String are not written in quotes. So, plugin: 'com.android.application' is nothing more but a Groovy map and its handed to the apply method.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    ...
}

I'll continue with this part and finish with the android part, because its easier to understand this way:

dependencies is not a Gradle keyword, its simply the name of a method of the already mentioned Project interface. This method takes a Closure, which is wrapped inside the braces. Normal method call brackets are omitted again. The closure is executed on a DependencyHandler object. Now we just add dependencies to our configurations. We could use the add method and pass a configuration name and a dependency notation (and optionally a new closure).

Here starts the Gradle magic. For each existing configuration in the project's ConfigurationContainer, a new method with the name of the respective configuration is added to the DependencyHandler, so we can simply use this method instead of using add all the time. When developing for Java, these configurations and therefor methods are compile, runtime, testCompile (among others). The fileTree is, once again, just a method of the Project interface.

android {
    compileSdkVersion 25
    ...
}

The methods defined by the Project interface are not the only available methods. Gradle plugins (like the Android plugin you are using) can add extensions or conventions. This way, properties and methods can be called like they would belong to the Project object. This is how the android part can be configured via a closure right in the build script.

Inside the android closure, some additional Gradle magic happens. You probably know that, in Groovy, one can omit the get or set part and access properties directly (while possible getters or setters are still called). Gradle also adds a method for each property with the name of the property, which can be used as setter. This way, we can call the compileSdkVersion method to set the compileSdkVersion property. Once again, brackets are omitted. This is just some syntactic sugar, which lets us omit the assignment operator.

Whenever you start a new braces level, you basically use a closure to configure an object. Sometimes a new object is created, sometimes an existing property is used. Sometimes, you need to read the documentation to understand what's happening exactly.

Upvotes: 3

Related Questions