Gradle for Android-基础build自定义

我们从gradle的使用,Android项目的创建和转换开始。现在是时候更好的理解build文件,了解一些有用的task和探索gradle和Android插件了。

在这章,我们会学习以下主题:

-理解gradle文件
-从build task开始
-自定义build

理解gradle文件

当使用AS创建一个新的项目,默认会生成三个gradle文件。其中的两个是settings.gradle和build.gradle,位于项目的顶层目录中。另外一个是在Android app模块中创建的build.gradle文件。这就是gradle文件在项目中的位置:

MyApp
├── build.gradle
├── settings.gradle
└── app
       └── build.gradle

这三个文件每一个都服务于自己的目的,我们将会在接下来的段落中更近一步的了解。

settings文件

对于一个新创建的项目来说,仅包含一个Android app,settings.gradle文件看起来像这样:

include ':app'

settings文件在初始化阶段被执行,而且定义了哪些模块应该被包含到build中。在这个例子中,app module被包括进来。单module项目不是必须要求要有settings文件,但是多module项目必须要;否则,gradle不知道哪些模块需要被包括。

在背后,gradle为每一个setting文件创建一个Settings对象,并从该对象中调用必须的方法。你不需要知道Settings类的细节,但是最好能有所认识。

顶层build文件

顶层build.gradle文件中,可以配置在项目中适用所有module的选项。默认包含两块:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'
    }
}
allprojects {
    repositories {
        jcenter()
    }
}

buildscript块是build实际配置的地方。repositories块配置JCenter作为一个repository。在这里,一个repository意味着一个依赖源,换句话说,一列我们会在app和library中使用的可下载的库。JCenter是一个非常出名的Maven库。

buildscript块被用作为build进程自身配置依赖。这意味着不能在顶层build文件中添加app或library需要的依赖。唯一默认地依赖是Android plugin。这也是每一个Android module都要求的,因为正是这个plugin使得它能够执行Android相关的task。

allprojects块会被用作定义需要应用到所有module上的属性。你甚至可以更近一步在allprojects中创建task。这些task可以被所有的module获取。

一旦你使用allprojects,module就会和project连接起来。这意味着没有主project的build文件可能无法独立构建module。初看起来好像不是问题,但是之后你可能会决定把内部library与它的project独立开来,然后就需要编辑build文件。

模块build文件

module层的build.gradle文件包含仅应用到Android app模块的选项。也可以重写顶层build.gradle文件中的选项。模块build文件看起来如下:

apply plugin: 'com.android.application'
android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId "com.gradleforandroid.gettingstarted"
        minSdkVersion 14
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile
            ('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
}

我们将会详细了解这三个主要模块。

插件

第一行应用了Android应用插件,我们之前讨论过,该插件在顶层build文件中被配置为一个dependency。Android插件是被Google的Android Tools小组编写和维护,并提供所有需要build、test、打包Android app和library的task。

Android

build文件最大的部分就是android块。这个块包含了Android特定配置的入口,可通过我们之前应用过的Android plugin获取。

唯一要求的属性就是compleSdkVersion和buildToolsVersion:

-compileSdkVersion:你想用来编译app的Android API版本;
-buildToolsVersion:编译者要使用的build工具的版本;

build tool包含了命令行共用程序,例如aapt(Android Application Package Tool),zipalign,dx以及renderscript;这些都是用来生成组成应用的各种中间件。可以通过SDK Manager下载build tools。

defaultConfig块配置了app的核心属性。这个块中的属性重写了AndroidManifest.xml文件中相应的入口:

defaultConfig {
    applicationId "com.gradleforandroid.gettingstarted"
    minSdkVersion 14
    targetSdkVersion 22
    versionCode 1
    versionName "1.0"
}

块中的第一个属性就是applicationId。重写了manifest文件中的包名,但是applicationId和包名又有所差异。在gradle被用作默认的Android构建系统前,AndroidManifest.xml文件中的包名有两个目的:

-app的唯一标识符;
-R资源类中的包的名称;

gradle使用build变体使得创建不同的app版本更加容易。例如,制作一个免费版本和一个收费版本是非常容易的。这两个应用需要有独立的标识符,所以他们在Google Play Store是以不同的app存在的,并且二者可以同时被安装。然而,源码和生成的R类必须总是保持相同的包名。否则,你所有的资源文件都需要被改变,取决于你当前build的版本。这也是为什么Anroid Tools小组解耦包名的两种用法。包,在manifest文件中被定义,继续用作资源代码和R类,然而被设备和Google Play使用作为唯一标识符的包名现在被我们称作application id。application ID将会更有意思当我们开始build type之旅的时候!

defaultConfig中接下来两个属性是minSdkVersion和targetSdkVersion。二者应被视作相似的,因为在manifest文件中都被定义为的一部分。minSdkVersion设置是配置运行app所需的最低的API版本。targetSdkVersion设置告诉系统app是在一个特定的Android版本测试,而且操作系统不需要启动任何向前兼容的行为。我们之前看到的compileSdkVersion没有做任何事情。

versionCode和versionName在manifest文件中也有相同的功能,被定义为app的版本号和人性化的版本名称。

build文件中的所有值都会重写manifest文件中的值。因此如果再build.gradle中定义了它们就不要求在manifest文件中再次定义。万一build文件并不包含一个值,manifest文件就会替补上。

依赖

dependencies块是标准的gradle配置的一部分(这也是为什么它会被放到android块之外)并切换定义了一个app或library的所有依赖。默认情况下,一个新的Android app都会对lib目录下的JAR文件有个依赖。依赖于你在新项目的导向程序中选择的选项,也依赖于AppCompat包。我们会在第三章讨论dependencies。

从task开始

为了了解哪些task在一个project中是可得的,可以运行gradlew tasks,它会打印一列可得的task。在一个新创建的Android项目中,包括Android tasks,build tasks,buidl setup tasks,help tasks,install tasks,verification tasks和其他的tasks。如果你不仅想看这些tasks,还想看他们的依赖,可以运行gradlew tasks –all.如果忘记了task的运行步骤,当运行一个指定的task时,会打印所有的执行步骤。这并不会真正的执行这些步骤,所以当运行一个确定的task时,查看你预期发生事是很安全的。你可以通过增加参数-m或–dry-run做“迷糊”运行。

基本task

Gradle的Android plugin利用Java基础plugin,Java基础plugin反过来利用基础plugin。这增加了标准的生命周期task和一些通用的约定的属性。基础plugin定义了assemble和clean task,Java基础plugin定义了check和build task。这些task没有在基础插件中被实现也没有实现任何action;它们都被用作为plugin定义增加实际做工作的task的约定。这些约定如下:

-assemble:聚集项目的输出
-clean:清除项目的输出
-check:运行所有的检查,通常用作单元测试和仪器测试;
-build:运行assemble和check

Java基础plugin也增加了资源集(sources set)的概念。Android plugin基于这些约定,并且因此暴露有经验的gradle用户通常想看到的task。在这些基础task的顶层,Android plugin也增加很多Android特有的task。

Android task

Android plugin继承基础task并实现他们的行为。这是在Android环境中task所做的事情:

-assemble:为每一个build类型创建APK;
-clean:移除所有build产品,例如APK文件;
-check:实现lint检测,如果lint检测到问题放弃build;
-build:运行assemble和check;

assemble task默认依赖于assembleDebug和assembleRelease,也会依赖更多task如果你增加更多的build类型。这意味着运行assemble将会触发构建你所拥有的所有build类型。

除了继承这些task之外,Android插 plugin也增加一些新的。这里是最有效的新的task:

-connectedCheck:在已连接的设备或模拟器上运行测试;
-deviceCheck:为其他plugin在远程设备上运行测试的一个占位符task;
-installDebug and installRelease:安装指定的版本到已连接的设备或模拟器上;
-所有install task都有与之对应的uninstall

build task依赖于check,但是不是connectedCheck或deviceCheck。这是为了确保定期检测不要求一个已连接的设备或正在运行的模拟器。运行check task生成一个带有一系列警告和错误的lint报告,以及一个详细的解释和一个相关文档的链接。报告在app/build/outputs目录在并叫做lint-result.html。看起来如下:
这里写图片描述

当你组装发布时,lint会检测可能会导致程序崩溃的严重问题。如果发现任何问题,将会放弃build并在命令行接口打印错误日志。并在app/build/outputs目录下生成叫做lint-results-release-fatal.html的文件。如果有多个问题的话,检查html报告要比在命令行接口来回回滚更方便。(lint)提供的链接也是非常有用的,因为它们会直接带给你关于这个问题的详细解释。

Android Studio中

你无须总是从命令行接口运行gradle task。AS有个包含了一系列可得的task的工具窗口。这个工具窗口叫做Gradle,看起来如下:
这里写图片描述

从这个工具窗口,你可以简单地通过双击名称运行task。你可以跟踪任何正在运行的task的进程在Gradle Console工具窗口。如果没有发现这些工具窗口,你可以在View菜单下的Tool Window打开它。Gradle Console看起来如下:
这里写图片描述

你也可以在AS中的命令行接口运行task,所以如果你愿意的话可以在IDE中做所有与app相关的工作。为了运行命令,需要打开Terminal工具窗口。这是一个很成熟的终端,所以可能可以运行任何指令。你或许需要导向到这个项目的顶层目录,以便使用gradlew wrapper更好的工作。

自定义build

自定义build进程有很多方式,而且当你在AS中编辑build文件时,不管你自定义了什么,也总会建议您使用gradle文件同步项目。当你开始添加依赖或buildConfig fields时,这回尤其重要,我们会在接下来讨论。

AS会立刻在编辑器中显示消息当你编辑settings.gradle或build.gradle文件时,并且可能总是会触发同步通过导向到Tools|Android|Sync Project with Gradle或在工具栏中相应的按钮。
这里写图片描述
AS同步实际上运行generateDebugSources task,基于build文件中的配置,生成所有必须的类。

操作manifest入口

我们已经看到直接用build文件代替manifest文件配置applicationid、minSdkVersion、targetSdkVersion,versionCode是可能的。这里有许多你可以操作的属性:

-testApplicationId:工具测试APK的应用id;
-testInstrumentaionRunner:用来运行你的测试程序的单元测试运行者名称;
-signingConfig(see Chapter4)
-proguardFile and proguardFiles(see Chapter9)

Android Studio中

代替手动修改build文件,也可以在Project Structure对话框中修改基本设置。从File菜单打开对话框,它使得你能够编辑项目级的设置和设置每一个模块。对于每一个Android模块,你可以改变标准的Android plugin属性和所有的manifest属性。在下面的截图中,你会在Project Structure中看到已发布的app模块版本属性信息:

这里写图片描述

要认识到如果你在Project Structure对话框做任何改变,AS都会把改变写到build文件中。

BuildConfig和resources

到目前为止,SDK tools版本已经到了17,build tool生成一个叫做BuildConfig的类,包含了一个根据build类型设置的DEBUG常量。这是非常有用的如果你有想仅在测试的时候运行的代码,例如log,可能通过gradle继承文件以便可以使用变量保存表示debug和release的不同的值。

这些常量都是非常有用的对于切换功能或设置服务器URL,例如

android {
    buildTypes {
        debug {
            buildConfigField "String", "API_URL",
            "\"http://test.example.com/api\""
            buildConfigField "boolean", "LOG_HTTP_CALLS", "true"
        }
        release {
            buildConfigField "String", "API_URL",
            "\"http://example.com/api\""
            buildConfigField "boolean", "LOG_HTTP_CALLS", "false"
    }
    }
}

string旁边的双引号对于它生成为一个实际的string是必须的。添加完buildConfigField后,在你的java代码中使用BuildConfig.API_URL和BuildConfig.LOG_HTTP就是可能的了。

最近,Android Tools小组增加了以类似的方式配置资源的可能行:

android {
    buildTypes {
        debug {
            resValue "string", "app_name", "Example DEBUG"
        }
        release {
            resValue "string", "app_name", "Example"
        }
    }
}

这里的双引号不是必须的,因为资源值默认总是包裹着value=””.

项目级设置

如果在一个项目中有多个模块,对每一个模块应用设置而非修改build文件就会非常有用。我们已经看到allprojects块是怎么在顶层build文件中被用于定义库的,并且可以也使用相同的策略应用Android特定的设置:

allprojects {
    apply plugin: 'com.android.application'
    android {
        compileSdkVersion 22
        buildToolsVersion "22.0.1"
    }
}

这仅会当你所有的模块都是Android app项目是才会有作用,因为你需要应用Android plugin设置Android特定的设置。一个更好的方式是在顶层build文件中定义值,然后在模块中应用。在Project对象的gradle中增加额外特别的属性是可能的。这意味着任何build.gradle文件都可以定义额外的属性,这发生在ext块中。

你可以用自定义的属性增加一个ext块到顶层build文件中:

ext {
    compileSdkVersion = 22
    buildToolsVersion = "22.0.1"
}

这使得它可能在module层build文件中通过rootProject使用属性:

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
}

项目属性

ext块在以上的例子中是一种定义额外属性的方式。可以使用属性快速地定义一个build进程,而且我们将会使用他们当我们开始写自定义的task时。有好几种方式定义属性,但是我们仅会了解最常用的三种:

-ext块;
-gradle.properties文件;
–P命令行参数;

这里有一个组成了这三种增加额外属性的build.gradle文件例子:

ext {
local = 'Hello from build.gradle'
}
task printProperties << {
    println local // Local extra property
    println propertiesFile // Property from file
    if (project.hasProperty('cmd')) {
        println cmd // Command line property
}
}

这是伴随的gradle.properties文件(在相同的文件中):

propertiesFile = Hello from gradle.properties

如果你用命令后参数运行printProperties task,输出将会如下:

$ gradlew printProperties -Pcmd='Hello from the command line'
:printProperties
Hello from build.gradle
Hello from gradle.properties
Hello from the command line

感谢自定义属性,改变build的额皮质就像改变一个单一属性一样容易,甚至仅仅增加一个命令行参数。

在顶层或module层build文件定义属性是可能的。如果module定义了一个已经存在于顶层文件的属性,将会简单的重写它。

默认task

如果没有指定task运行gradle,将会运行help task打印一些gradle如何工作的信息。因为help task被设置成为默认的task。重写默认的task和拥有一个非常普通的task,甚至多task都是可能的,每次运行gradle都不用明确指明task。

为了指明默认的task,在顶层build文件中增加这样代码:

defaultTasks 'clean', 'assembleDebug'

现在,当你不带参数运行gradle wrapper,它将会运行clean和assembleDebug。通过运行tasks task和过滤输出很容易看到哪些task是被设置成默认运行的task

$ gradlew tasks | grep "Default tasks"
Default tasks: clean, assembleDebug

总结

在这一章节,我们详细的看了被AS自动生成的不同的gradle文件。你可以自己创建build文件,并且增加所有要求的字段和配置关键的属性。

我们从基础build task开始,学习Android plugin如何基于基础plugin构建,以及使用新的Android特定的task扩展它。我们也看到如何从命令行接口和AS内部运行build task。

在章节最后部分,我们看了影响build输出和配置build进程自身的几种方式。

在最近几年,Android开发者生态系统极大的增长,大量有趣的包可供每个人使用。在下一章,我们将会学习增加依赖到项目中的集中方式,所以我们可以利用这些资源。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值