【问题标题】:Please explain the Android build.gradle groovy syntax请解释Android build.gradle groovy 语法
【发布时间】:2015-06-10 09:41:48
【问题描述】:

以下 groovy 语法的真正含义是什么?

Gradle 文档吹捧 build.gradle 是如何只是 groovy。 Android 团队已将默认的 build.gradle 简化到它看起来不像代码的程度(至少对我而言)。请用 groovy 语法解释这是做什么的。例如,这些是 Android 插件使用的全局变量声明吗?

如果您在解释中包含对 http://groovy-lang.org/syntax.html 的引用,则可获得奖励积分。

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.crittercism"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 5
        versionName "5.0"
    }

}

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

【问题讨论】:

标签: groovy android-studio gradle android-gradle-plugin


【解决方案1】:

您可以将 gradle 构建脚本视为一些代码,委派给可以响应其中编写的方法调用的对象

该脚本使用了大量 Groovy 语法糖,因此删除它们,它应该如下所示:

apply( [plugin: 'com.android.application'] );

android({
    compileSdkVersion( 21 );
    buildToolsVersion( "21.1.2" );

    defaultConfig({
        applicationId( "com.crittercism" );
        minSdkVersion( 15 );
        targetSdkVersion( 21 );
        versionCode( 5 );
        versionName( "5.0" );
    });
});

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

所以脚本真的是一堆方法调用:

  • def apply(Map)
  • def android(Closure)
  • def dependencies(Closure)

这个android(Closure) 将接收一个闭包,并将其中调用的方法委托给一个可以响应这些方法的对象:

  • def compileSdkVersion(Integer)
  • def buildToolsVersion(String)
  • ...

鉴于此,我们可以解析脚本,将其委托给某个对象,然后执行它。

使用DelegatingBaseScript 委托是一种方法(不确定Gradle 是否这样做)。这是一个简化的工作版本:

import org.codehaus.groovy.control.CompilerConfiguration

gradleScript = '''
apply plugin: 'com.android.application'
    
android({
    compileSdkVersion( 21 )
    buildToolsVersion( "21.1.2" )
})'''


class PocketGradle {
  def config = [apply:[]].withDefault { [:] }
  
  def apply(map) {
    config.apply << map.plugin
  }
  
  def android(Closure closure) {
    closure.delegate = new Expando(
        compileSdkVersion: { Integer version -> 
          config.android.compileSdkVersion = version 
        },
        buildToolsVersion : { String version ->
          config.android.buildToolsVersion = version
        },
    )
    closure()
  }
}
    
def compiler = new CompilerConfiguration(scriptBaseClass: DelegatingScript.class.name)

shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)

script = shell.parse gradleScript
script.setDelegate( gradle = new PocketGradle() )
script.run()

assert gradle.config == [
  apply: ['com.android.application'],
  android: [
    compileSdkVersion: 21,
    buildToolsVersion: '21.1.2'
  ]
]

您可以在Groovy Web Console 中执行脚本(点击“在控制台中编辑”,然后点击“执行脚本”)。

大部分语法解释都在DSL section:

  1. 命令链

Groovy 允许您在顶级语句的方法调用的参数周围省略括号。 “命令链”特性扩展了这一点,允许我们链接此类无括号的方法调用,既不需要括号括住参数,也不需要链接调用之间的点。

还有 Groovy ConfigSlurper,但我不确定它是否能达到 Gradle 想要的程度。

【讨论】:

    【解决方案2】:

    感谢 AndroidGuy 提供了精彩的视频,让我了解了以下信息。视频时长 35 分钟,所以这里是 TL;DR。

    这种语法大部分是method 调用和closures 的混合。闭包由花括号表示。另请注意,方法调用不需要括号。

    apply plugin: 'com.android.application'
    

    这是在 project 对象上使用单个命名参数“plugin”调用 apply 方法。项目对象是 Gradle 提供的顶级对象。

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

    这是设置项目对象的dependencies 属性。 Groovy properties 基本上是 getter 和 setter 的简写。 dependencies 属性是一个委托给DependencyHandler 的闭包对象。 Groovy delegation 本质上是一种增加闭包范围分辨率的方法。依赖闭包包含一个用于编译的方法调用,它采用FileTree 位置参数。 FileTree 由项目对象中定义的fileTree 方法生成。编译方法对我来说仍然有点模糊。它似乎来自Java plugin,但没有明确记录在那里。 “编译”部分对我来说还是有点神奇。

    android {
        ...
    }
    

    我将把“android”部分留给读者作为练习。 Android Gradle 领域特定语言 (DSL) 在网络上不可用。你必须download it

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-19
      • 2010-11-27
      • 1970-01-01
      • 2013-11-15
      • 2016-09-29
      • 1970-01-01
      • 2013-11-19
      • 2022-10-21
      相关资源
      最近更新 更多