Gradle|Gradle For Android(2)--基础的定制构建
理解Gradle文件
当创建一个新的Project的时候,会默认生成3个Gradle文件。在项目的根目录(在Project的Top-Level)下会生成settings.gradle
和build.gradle
。而在Android app模块中会创建一个build.gradle
文件。目录结构如下:
MyApp
├── build.gradle
├── settings.gradle
└── app
└── build.gradle
Settings文件 对于一个新的Project,
settings.gradle
文件只会有一行include ':app'
这个
setting.gradle
在初始化阶段被执行,并且定义了哪些Module应该在构建中被包含。在该例中,只有:app
模块被包含。只有一个模块的Project可以不需要该文件,而多个模块的Project的必须要该文件,否则Gradle不知道哪些模块需要被包含(include)。在这种场景下,Gradle创建了为每个Settings文件都创建了一个
Serttings
对象,并且可以从该对象中调用所需要的Methods。我们不需要知道Settings类的细节,但是最好关注一下。顶层的build.gradle 顶层的
build.gradle
文件中,我们可以配置一些options,这些options可以应用于所有在这个Project中的Module。它默认包含以下两个代码块:buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
}
}
allprojects {
repositories {
jcenter() }
}
}
buildscript
代码块中是真正构建的配置的地方。respositories
代码块配置了JCenter作为仓库。在这种情况下,仓库代表了这个Project所依赖的资源或者说我们所需要的一些可下载的Libraries都是保存在这个仓库中。JCenter是一个知名的Maven仓库。dependencies
代码块用来配置构建过程的依赖。也就是说,我们不应该在Top-Level的build.gradle
中包含Application或者Libraries的依赖。它唯一的依赖关系应该为是默认定义的Android Plugin。它会去遍历每一个Android Module,因为它是会执行Android-Related Tasks的插件。allprojects
代码块用来定义需要被应用到每一个Module中的属性。我们甚至可以在这个代码块中创建Task,而这些Task可以在各个Module中被应用。Module中的build.gradle Module层的
build.gradle
文件包含了一些options,这些options只能应用在Android app module中。它也能够覆盖Project层的build.gradle
文件中的属性。该模块的file如下: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'
}
其中三个主要的代码块:
- plugin:第一行应用了Android的application plugin,配置在顶层的
build.gradle
中。这个插件主要由Android工具团队写并且维护的,提供了所有需要构建application以及libraries的build,test,package任务 - android:这个代码块主要包括了Android特殊的配置。只有两个属性需要配置
compileSdkVersion
以及buildToolsVersion
。负责编译的sdk api版本以及build tools的版本。其中build tools包括了很多命令行的工具,比如说aapt,zipalign,dx,renderscript等等,使用这些工具我们可以生产出各种各样的中间件。我们可以通过SDK Manager下载build tools。
defaultConfig
代码块配置了App核心的属性。在这个代码块中的属性会重写AndroidManifest.xml中相对应的属性。applicationId
属性会重写Manifest.xml中的packageName。在Gradle之前的构建系统中,PackageName有两个作用,唯一表示一个App以及用于为R.java赋予包名。而通过Gradle使用build variants使得构建不同版本的App变得更加简单了。比如,很容易构建一个付费/免费的版本。而这两个版本需要两个单独的PackageName,这样才能够被一起装到一个手机上。但是源代码以及R文件包名都还保持着相同的PackageName,以至于在构建多个版本的时候,需要把所有的源文件都进行修改。因此,这也就是为什么Android Tool团队减弱了packageName的这两个用途。定义在Manifest中的PackageName仍然会用于SourceCode以及R文件。而Google Play则会使用application id作为唯一标识符来区分App。
包括minSdkVersion,targetSdkVersion,versionCode,versionName等等在内的所有值都会覆盖掉Manifest.xml中的值,如果在
build.gradle
中定义了这些值,Manifest.xml中就可以不定义了,但是以防万一最好还是在Manifest.xml中定义好,避免遗漏出错。buildType
代码块定义了构建不同类型的App的地方。后续会再详细说明。dependencies
代码块是标准Gradle配置的一部分,这也就是它为什么会在android
代码块之外的原因。并且它定义了app或者library中所有的依赖关系。默认一个新的Android App会对libs
目录下的所有jar包有依赖。取决于新Project的启动项配置。了解Tasks 为了了解整个Project中哪些Task是可用的,我们可以通过
gradlew tasks
来列出所有可用的Tasks。如下图所示:文章图片
可用的Tasks
在一个新创建的Android Project中,它包括了:
- Android tasks
- build tasks
- build setup tasks
- help tasks
- install Tasks
- verification Tasks
- ...
gradlew tasks --all
。当你希望打印出执行一个特殊的Task的所有步骤时,可以加上参数-m
或者--dry-run
。Android Tasks Android Plugin继承自基础的Task,并且实现了自己一些功能。这些Tasks在Android中会有如下表现:
- assemble:为每个Build Type构建APK
- clean:移除所有Build中间件以及Apk文件等等
- check:执行Lint的检查,并且如果Lint出现问题的时候,会打断Build过程
- build:执行assemble以及check任务
Assemble
任务默认由assembleDebug
以及assembleRelease
构成,如果有更多的Build Type的话,则会有更多的任务。也就是说,执行Aseemble将会为每个Build Type触发一个构建。除了继承了这些Tasks之外,Android Plugin也添加了一些新的Task。以下为最重要的新的Tasks:
- connectedCheck:在已经连接的设备或者模拟器上执行tests任务
- deviceCheck:为其他插件在远程设备上调试提供的占位任务
- installDebug/installRelease:在已经连接的设备或者模拟器上安装一个特定的版本
- 所有的
install
任务都会有相对应的uninstall
任务
build
任务依赖于check
任务,而不是connectedCheck
或者deviceCheck
。这保证了常规的检查不需要连接设备 。执行完check
任务后,会生成一个Lint Report文件,其中保存着warnings以及errors,可以在app/build/outputs/lint-results.html
中找到。文章图片
Lint Report
当Assemble一个Release版本时,Lint将检查可能会导致App Crash的问题。如果找到的话,就会中断Build,并且在Command-Line中打印出错误。并且也会在
app/build/outputs
中生成lint-results-release-fatal.html
文件。如果有多个错误,则通过HTML的Report报告然后滑动到报错的位置就可以看到了。在Android Studio中,右侧的
Gradle
窗口双击对应的Task即可开始执行。也就不用在命令行工具中输入命令了。文章图片
Gradle窗口
BuildConfig以及Resources
从SDK Tool版本17之后,Build Tool会生成一个名为
BuildConfig
的类,其中包含了根据build type生成的DEBUG
常量。这对控制日志打印是非常有利的。而且,这也为Debug或者Release的常量区分带来了很多的方案,比如我们需要根据Build Type来开启/关闭一些Features,或者设置Server的URLs等等,例如: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
这一行,我们可以使用BuildConfig.API_URL
和BuildConfig.LOG_HTTP
来引用不同的值。而最近,Android Tool团队也会通过以下方式来配置资源:
android {
buildTypes {
debug {
resValue "string", "app_name", "Example DEBUG"
}
release {
resValue "string", "app_name", "Example"
}
}
}
Project级别的Settings 如果拥有多个Android Modules的话,它可以非常简便的修改每个Module中的
build.gradle
中的值,而不用手动的去修改了。我们已经看到了allprojects
代码块在顶层的build.gradle
中定义了reositories
,并且你可以使用相同的方式来应用Android指定的Settings:allprojects {
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
}
}
这段代码块只会应用于所有的Android App Project,因为需要应用Android Plugin去使用Android特殊的Settings。一种更好的方案是在顶层的
build.gradle
中定义这些值,然后在各个Module中应用。也就意味着,我们可以在build.gradle
文件中绑定ext
代码块,其中定义一些自定义的属性:ext {
compileSdkVersion = 22
buildToolsVersion = "22.0.1"
}
通过这种方式来在Module级别的
build.gradle
中使用rootProject
来获取使用的值。android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
Project properties 定义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
如果通过命令行参数执行
printProperties
任务的话,输出如下:$ gradlew printProperties -P cmd='Hello from the command line'
:printProperties
Hello from build.gradle
Hello from gradle.properties
Hello from the command line
默认的任务
如果使用
gradle
没有指定具体的任务的话,则会执行help
任务。如果需要指定默认的任务的话,则需要在顶层的build.gradle
中加入默认任务:defaultTasks 'clean', 'assembleDebug'
这样的话,执行
gradlew
就会默认执行这两个任务。而通过gradlew tasks | grep "Default tasks"
也可以查看默认的任务。推荐阅读
- android第三方框架(五)ButterKnife
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- android|android studio中ndk的使用
- Android事件传递源码分析
- RxJava|RxJava 在Android项目中的使用(一)
- Android7.0|Android7.0 第三方应用无法访问私有库
- 深入理解|深入理解 Android 9.0 Crash 机制(二)
- android防止连续点击的简单实现(kotlin)
- Android|Android install 多个设备时指定设备