Gradle for Android 第二篇( Build.gradle入门 )

新年新气象,奋斗的一年,在这一章,我们将学习以下内容:

  • 理解Gradle文件

  • 编写简单的构建任务

  • 自制构建脚本


理解Gradle脚本

当然我们现在讨论的所有内容都是基于 Android studio 的,所以请先行下载相关工具。当我们创建一个新的工程,Android studio 会默认为我们创建三个 gradle 文件,两个 build.gradle,一个 settings.gradle,build.gradle 分别放在了根目录和 moudle 目录下,下面是 gradle 文件的构成图:

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

setting.gradle 解析

当你的 app 只有一个模块的时候,你的 setting.gradle 将会是这样子的:

include ':app'

setting.gradle 文件将会在初始化时期执行,关于初始化时期,可以查看上一篇博客,并且定义了哪一个模块将会被构建。举个例子,上述 setting.gradle 包含了 app 模块,setting.gradle 是针对多模块操作的,所以单独的模块工程完全可以删除掉该文件。在这之后,Gradle 会为我们创建一个 Setting 对象,并为其包含必要的方法,你不必知道 Settings 类的详细细节,但是你最好能够知道这个概念。


根目录的 build.gradle

该 gradle 文件是定义在这个工程下的所有模块的公共属性,它默认包含二个方法:

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

buildscript 方法是定义了全局的相关属性,repositories 定义了 jcenter 作为仓库。一个仓库代表着你的依赖包的来源,例如 maven 仓库。dependencies 用来定义构建过程。这意味着你不应该在该方法体内定义子模块的依赖包,你仅仅需要定义默认的 Android 插件就可以了,因为该插件可以让你执行相关 Android 的 tasks。

allprojects 方法可以用来定义各个模块的默认属性,你可以不仅仅局限于默认的配置,未来你可以自己创造 tasks 在 allprojects 方法体内,这些 tasks 将会在所有模块中可见。


模块内的 build.gradle

模块内的 gradle 文件只对该模块起作用,而且其可以重写任何的参数来自于根目录下的 gradle 文件。该模块文件应该是这样:

 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 应用插件,该插件我们在上一篇博客已经介绍过,其是 google 的 Android 开发团队编写的插件,能够提供所有关于 Android 应用和依赖库的构建,打包和测试。


Android

该方法包含了所有的 Android 属性,而唯一必须得属性为 compileSdkVersion 和 buildToolsVersion:

  • compileSdkVersion:编译该 app 时候,你想使用到的 api 版本。

  • buildToolsVersion:构建工具的版本号。

构建工具包含了很多实用的命令行命令,例如 aapt,zipalign,dx 等,这些命令能够被用来产生多种多样的应用程序。你可以通过 sdk manager 来下载这些构建工具。

defaultConfig 方法包含了该 app 的核心属性,该属性会重写在 AndroidManifest.xml 中的对应属性。

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

第一个属性是 applicationId,该属性复写了 AndroidManifest 文件中的包名 package name,但是关于 applicationId 和 package name 有一些不同。在 gradle 被用来作为 Android 构建工具之前,package name 在 AndroidManifest.xml 有两个作用:其作为一个 app 的唯一标示,并且其被用在了 R 资源文件的包名。

Gradle 能够很轻松的构建不同版本的 app,使用构建变种。举个例子,其能够很轻松的创建一个免费版本和付费版本的 app。这两个版本需要分隔的标示码,所以他们能够以不同的 app 出现在各大应用商店,当然他们也能够同时安装在一个手机中。资源代码和 R 文件必须拥有相同的包名,否则你的资源代码将需要改变,这就是为什么 Android 开发团队要将 package name 的两大功能拆分开。在 AndroidManifest 文件中定义的 package name 依然被用来作为包名和R文件的包名。而 applicationid 将被用在设备和各大应用商店中作为唯一的标示。

接下来将是 minSdkVersion 和 targetSdkVersion。这两个和 AndroidManifest 中的\<uses-sdk>很像。minSdkVersion 定义为最小支持 api。

versionCode 将会作为版本号标示,而 versionName 毫无作用。

所有的属性都是重写了 AndroidManifest 文件中的属性,所以你没必要在 AndroidManifest 中定义这些属性了。

buildTypes 方法定义了如何构建不同版本的 app,我们将在下一篇博客中有所介绍。


依赖包

依赖模块作为 gradle 默认的属性之一(这也是为什么其放在了 Android 的外面),为你的 app 定义了所有的依赖包。默认情况下,我们依赖了所有在 libs 文件下的 jar 文件,同时包含了 AppCompat 这个 aar 文件。我们将会在下一篇博客中讨论依赖的问题。


让我们开始 tasks 吧

如果你想知道你多少 tasks 可以用,直接运行 gradlew tasks,其会为你展示所有可用的 tasks。当你创建了一个 Android 工程,那么将包含 Android tasks,build tasks,build setup tasks,help tasks,install tasks,verification tasks 等。


基本的 tasks

android 插件依赖于 Java 插件,而 Java 插件依赖于 base 插件。

base 插件有基本的 tasks 生命周期和一些通用的属性。

base 插件定义了例如 assemble 和 clean 任务,Java 插件定义了 check 和 build 任务,这两个任务不在 base 插件中定义。

这些 tasks 的约定含义:

  • assemble: 集合所有的 output

  • clean:清除所有的 output

  • check:执行所有的 checks 检查,通常是 unit 测试和 instrumentation 测试

  • build:执行所有的 assemble 和 check

Java 插件同时也添加了 source sets 的概念。


Android tasks

android 插件继承了这些基本 tasks,并且实现了他们自己的行为:

  • assemble:针对每个版本创建一个 apk

    • clean:删除所有的构建任务,包含 apk 文件

    • check:执行 Lint 检查并且能够在 Lint 检测到错误后停止执行脚本

    • build:执行 assemble 和 check

默认情况下 assemble tasks 定义了 assembleDebug 和 assembleRelease,当然你还可以定义更多构建版本。除了这些tasks,android 插件也提供了一些新的 tasks:

  • connectedCheck 在测试机上执行所有测试任务

    • deviceCheck 执行所有的测试在远程设备上

    • installDebug 和 installRelease 在设备上安装一个特殊的版本

    • 所有的 install task 对应有 uninstall 任务

build task 依赖于 check 任务,但是不依赖于 connectedCheck 或者 deviceCheck,执行 check 任务的使用 Lint 会产生一些相关文件,这些报告可以在 app/build/outputs 中查看:


android studio 的 tasks

你根本不必要去执行 gradle 脚本在命令行中,Android studio 有其对应的工具:

在这个界面,你要做的就是双击了。当然你也可以在 Android studio 中打开命令行,执行相关命令,具体操作就不介绍了。


自定义构建

当你在 Android studio 中自定义了 gradle 文件,需要更新 project:


其实该按钮,执行了 generateDebugSources tasks,该任务会生成所有必要的 classes 文件。


BuildConfig 和 resources

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"
     } 
 }

类似这些定义的常量,当定义了这些属性后,你完全可以在代码中使用:BuildConfig.API_URL 和 BuildConfig.LOG_HTTP

最近,Android tools team 也让其里面定义 string 变为可能:

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

你可以在代码中使用这些 string。其中 “” 不是必须得。


全局设置

如果你有很多模块在一个工程下,你可以这么定义你的 project 文件。

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

这只会在你的所有模块都是 Android app 应用的时候有效。你需要添加 Android 插件才能访问 Android 的 tasks。更好的做法是你在全局的 gradle 文件中定义一些属性,然后再模块中运用它们。比如你可以在根目录下这么定义:

 ext {
       compileSdkVersion = 22
       buildToolsVersion = "22.0.1"
}  

那么你在子模块中就可以使用这些属性了:

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

Project properties 文件

上述方法是一种办法,当然还有很多办法:

  • ext方法

  • gradle.properties文件

  • -p参数

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

你也可以输入命令行:

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

总结

在这篇博客中,我们细致的查看了 Android studio 生成的三个 gradle 文件,现在你应该能够自己去创建自己的 gradle 文件,我们还学习了最基本的构建任务,学习了 Android 插件以及其 tasks。

在接下来的几年里,Android 开发生态将会爆炸性增长,很多有趣的依赖库将会让每个人去使用,在下一篇博客里面,我们将看看我们能有几种方式添加我们的依赖库,这样我们才能够避免造轮子。

转载自:Android开发中文站 > Gradle for Android 第二篇( Build.gradle入门 )

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1