通上前两篇博文由浅入深的学习Gradle的基础和Gradle的Java插件相关知识后,现在终于到了高潮部分了,让我们来进一步正式学习Android Gradle插件。前面提到,Android Gradle插件是一个基于内置的Java插件来实现的第三方插件,它是由google的Android团队开发的。
1 分类
Android Gradle插件根据我们Android工程的属性分为三类:
插件名称 | id | 描述 |
App | com.android.application | App应用工程,它可生成一个运行的apk应用 |
Library | com.android.library | Library库工程,它可生成AAR包 |
Test | com.android.test | Test测试工程,用于对App工程或者Library库工程进行单元测试 |
应该很好理解,像我们之前提到的工程中,有app和mylibrary两个子工程的情况下,除了Root Project的build.gradle外,其它两个Child Project的build.gradle的第一行便能看到应用android插件的代码:
\app\build.gradle
apply plugin: 'com.android.application'
mylibrary\build.gradle
apply plugin: 'com.android.library'
2 配置依赖
前面提到,要应用第三方插件前,必须先对其进行配置,因为Android Gradle插件是托管在jcenter库上,所以在Root Project的build.gradle里有这样的代码:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
3 build.gradle的结构
经过前面的知识学习,现在我们应该可以很容易地看懂在Android Studio新建工程后的Root Project的build.gradle和Child Project的build.gradle的大概意思,我们先列出它们的大至结构:
Root Projec的build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
说明:
- buildscript的配置就是上面所说的配置依赖关系
- allprojects的配置我们在《Android Gradle使用详解(二) 之 项目结构和初识Java Gradle插件》中有提过,一般地在Root Project的build.gradle中使用allprojects或subprojects是对Child Project进行统一的抽离公共配置,这样所有的Child Project的build.gradle就不用重复配置。这里是配置仓库。告诉Gradle是要去google库和jcenter库搜寻第三方库。
- task clean是Java插件内置的Task,同样也在《Android Gradle使用详解(二) 之 项目结构和初识Java Gradle插件》介绍过,它用于清理构建生成的目录文件。
App的build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
……
}
buildTypes {
……
}
}
dependencies {
……
}
说明:
- 第一行我们在上面介绍过了,apply plugine就是应用Android Gradle中的App类型插件
- android{}是Android Gradle工程唯一的一个入口,通过它可以进行自定配置工程参数,我们在下面再对其详细介绍
- dependencies就是配置依赖关系了,同样也在《Android Gradle使用详解(二) 之 项目结构和初识Java Gradle插件》介绍过,可以配置依赖第三方库或者依赖另一个Gradle项目(例如mylibrary)
mylibrary的build.gradle
apply plugin: 'com.android.library'
android {
……
}
dependencies {
……
}
说明:
总体上跟App的build.gradle文件大同小异,区别在于第一行中应用的是Android Gradle中的Library类型插件。
4 android{}
Android Gradle工程的配置,都是在android{}中,这是唯一的一个入口。通过它可以对Android Gradle工程进行自定义的配置。示例如下:
android {
compileSdkVersion 26
buildToolVersion "26.0.1"
defaultConfig {
applicationId "com.zyx.myapplication"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
4.1 compileSdkVersion
compileSdkVersio是配置Android工程的SDK,或者说是告诉 Gradle 用哪个 Android SDK 版本编译你的应用。还可以这样写成:
android {
compileSdkVersion "android-26"
}
或者
android. compileSdkVersion "android-26"
4.2 buildToolVersion
buildToolsVerion表示使用的Android构建工具的版本。
4.3 defaultConfig{}(默认配置)
defaultConfig是Android对象中的一个配置块,负责定义所有的默认配置。其里面可以配置很多字段,一般基本的defaultConfig配置字段有:
4.3.1 applicationId
用于指写生成的APP的包名,默认情况下是null,若为null,则会在构建的时候从AndroidManifest.xml文件中配置的manifest标签的package属性读取。
4.3.2 minSdkVerion
用于指写APP最低支持的Android 系统版本,其对应的值是Android SKD 的API Level。
4.3.3 targetSdkVersion
是 Android 提供向前兼容的主要依据,表明是基于哪个Android 版本开发的。也就是说,只要targetSdkVersion 不变,即使APK 安装在新 Android 系统上,其行为还是保持老的系统上的行为,这样就保证了系统对老应用的前向兼容性。
4.3.4 versionCode
表明APP应用内部版本号,它是一个整数,一般用于APP升级。更多介绍,请参考后面文章《Android Gradle使用详解(五) 之 动态生成App版本号》。
4.3.5 verionName
表明APP应用内部版本名称。更多介绍,请参考后面文章《Android Gradle使用详解(五) 之 动态生成App版本号》。
4.3.6 testInstrumentationRunner
用于配置单元测试时使用的Runner,一般情况下使用默认的是android.test.InstrumentationTestRunner即可。
4.3.7 testApplicationId
用于配置测试APP的包名,默认情况下是applicationId + “.test”。一般情况下默认即可。
4.3.8 testFunctionalTest
用于配置单元测试时是否为功能测试。
4.3.9 testHandleProfiling
用于配置单元测试时是否启用分析功能。
4.3.10 等
4.4 buildTypes{}(构建类型)
buildTypes是一个域对象。它是对构建类型:release、debug等的配置。还可以在buildTypes{}里新增任意多个需要构建的类型。每一个BuildType还会生成一个SourceSet。上面示例中,release就是一个BuildType。一般地像defaultConfig{}中的配置如果需要区分不同的构建版本配置不同的参数的话,就得在这里进行配置。常用的配置字段下面介绍的。
4.4.1 minifyEnabled(使用混淆)
用于配置是否启用Proguard混淆,接收一个boolean类型的值。代码混淆是一个非常有用的功能,它不仅能使APK包size变小,还可以让反编译的人不容易看明白我们的源代码逻辑从而增加分析难度。一般情况下,release模式编译的版本会启动混淆功能。因为混淆后无法断点调试,所以debug模式下一般是不启动的。
4.4.2 proguardFiles/ proguardFile
proguardFiles是当我们启用混淆时,ProGuard的配置文件,它可以同时接受多个配置文件,因为它的参数是一个可变类型的参数。
proguardFile也是用于配置App proGuard混淆所使用的ProGuard配置文件,它接收一个文件作为参数。
当我们将minifyEnabled设为true,启动混淆后,还要通过proguardFiles或proguardFile指写混淆的配置表即可,如上面示例中代码:
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
说明:
- getDefaultProguardFile用于指定使用的混淆配置文件,该文件路径于Android SDK安装目录下的tools/proguard文件夹下。在该目录下有两个Android的Proguard配置文件:proguard-android.txt和proguard-android-optimize.txt,从名字可以看出,它们一个是无优化,另一个是有做优化的。
- 配置代码中,在逗号后是一个文件,一般地,该文件位于build.gradle同级目录中。它就是我们进行不混淆哪些类的配置文件,注意这里头配置的是不混淆白名单,当minifyEnabled设为true后默认是全部混淆的。一般情况下,如果你的代码使用到反射的话,都不能进行混淆,就要在此文件中配置你的不混淆的相关代码。一般规则用连起来单词表示,主要有:
keep 保留,例如keepattributes:表示保留属性
dont 不要,例如dontwarn:表示不要提示警告
ignore 忽略,例如ignorewarning:表示忽略警告
更多详细的规则大家可自行上网查找相关资料,这里不就作详情列举了。
4.4.3 consumerProguardFiles
跟proguardFiles的用法一样,在启动混淆时用于配置使用的ProGuard配置文件。只不过consumerProguardFiles是专门用于aar包使用,这样在应用引用aar包并启动混淆时,会自动使用这个属性配置对aar包里的代码进行混淆。
4.4.4 applicationldSuffix
用于配置基于默认applicationId的后缀,比如默认defaultConfig中配置的applicationId为com.zyx.myapplication,若在debug的BuildType中指写applicationIdSuffix为.debug,那么构建生成的debug.apk的包名就是com.zyx.myapplication.debug。
4.4.5 debuggable
用于配置是否生成一个可供调试的apk。一般release中都是为false,而debug中都是为true。
4.4.6 jinDebuggable
跟debuggable类似,用于配置是否生成一个可供调试Jni(C/C++)代码的apk。
4.4.7 multiDexEnabled
用于配置是否启用自动拆分多个Dex的功能。一般用程序中代码太多,超过了65535个方法的时候,拆分多个Dex,接收一个boolean类型的值。关于突破65535方法限制具体使用,请参考后面文章《Android Gradle使用详解(六) 之 如何解决65535方法限制》。
4.4.8 zipAlignEnabled
用于配置是否启用Android 的 zipalign整理优化APK文件的工具。zipalign能提高系统和应用运行效率,更快地读写APK中的资源,降低内存的使用。一般情况下,release模式编译的版本下都会启动此优化。
4.4.9 shrinkResources(自动清理资源)
用于配置在构建时是否自动清理未使用的资源,默认为false。此配置要配合minifyEnable(混淆)一起使用,因为先清理掉无用的代码后,这样一些无用的代码引用的资源才能被清理掉。
自动清理未使用的资源跟使用代码混淆都存在一个同样的问题,那就是当代中使用了反射去时,Android Gradle就区分不出来了,从而误清理了被引用的资源,针对这种情况,Android Gradle提供了keep方法来让我们配置哪些资源不被清理。操作如下:
- 新建一个xml文件:res/raw/keep.xml
- 通过tools:keep属性来配置,它接受一个以逗号分割的配置资源列表,并支持星号通配符
- 通过tools:shrinkMode属性配置自动清理资源的模式,默认是safe(安全的),也可以将它改为strict(严格的)
- 正常情况下,keep.xml会在构建时不会被打到包里去,不会影响apk的大小,除非你在代码中通过R.raw.keep来引用它
示例如:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="
@layout/abc_*,
@drawable/a_b_c_d"
tools:shrinkMode="strict"/>
4.4.10 signingConfig
用于配置APK包的签名信息,如:signingConfig signingConfigs.releaseConfig。具体使用,请参考后面文章《Android Gradle使用详解(四) 之 如何安全配置APK包的签名》。
4.4.11 等
4.5 signingConfigs{}(APK签名)
一个APP只有在签名这后才能被发布、安装和使用,签名是保护APP的方式,它能标记APP的唯一性,防止恶意篡改。它配置中使用的字段如下所示,具体使用,请参考后面文章《Android Gradle使用详解(四) 之 如何安全配置APK包的签名》。下面简单介绍签名中使用到的一些属性字段。
4.5.1 storeFile
指定签名证书文件,接收一个文件类型。
4.5.2 storePassword
配置签名证书文件的密码。
4.5.3 keyAlias
配置签名证书中密钥别名。
4.5.4 keyPassword
配置签名证书中该密钥的密码。
4.6 ProductFlavors{}(渠道配置)
多渠道、多语言的构建都是利用对ProductFlavor{}的配置。针对不同的渠道区分个别特殊功能、跟踪活跃留存这些数据来源是很有必要的,特别在国内应用市场如此多的情况下。每个ProductFlavor可以有自己的SourceSet,还可以有自己的Dependencies依赖,这意味着我们可以为每个渠道定义它们自己的资源、代码以及依赖的第三方库。几乎所有在defaultCofnig{}和buildTypes{}中可配置使用的方法或属性,都能在productFlavors{}中使用。关于多渠道具体使用,请参考后面文章《Android Gradle使用详解(七) 之 多渠道构建你的App》。下面就简单介绍下除了在defaultCofnig{}和buildTypes{}介绍过的属性方法外,还比较常用到到的一些属性和方法。
4.6.1 BuildConfigField
可用于在构建后在BuildConfig类中自定义新增一些常用的常量,例如渠道号。
4.6.2 resValue
resValue是一个方法,它在defaultCofnig{}、buildTypes{}和ProductFlavor中都可以使用。可用于自定义资源的方式来区分渠道。
4.6.3 manifestPlaceholdes
manifestPlaceholdes是一个Map类型,通过对它的配置就可以方便地动态来设置AndroidManifest中的预设的占位符变量。例如像友盟这类第三方分析统计,就会要求我们在AndroidManifest文件中指定渠道号名称。
4.6.4 dimension
dimension是维度的意思,它就好像一个分组一样。用于多维度地对ProductFlavor{}配置,从而解决多渠道的脚本冗余和更好的维护。
4.6.5 resConfigs
resConfigs属于PraductFlavor{}的一个方法,它可以让我们配置哪些类型的资源才被打到包中去。使用如:
android {
defaultConfig {
resConfigs “en", “zh"
// 或者 resConfigs “hdpi", “xhdpi", “xxhdpi"
}
}
4.7 compileOptions{}(编译选项)
我们有时候会对Java源文件的编码、源文件使用的JDK版本等进行调优修改。比如需要配置源文件的编码为UTF-8。还比如想配置编译Java源代码的级别为二级1.10,为此Android Gradle提供了compileOptions的配置入口让我们来做些配置,例如:
android {
……
compileOptions{
ending = 'uft-8'
sourceCompatibility = JavaVersion.VERSION_1_10
targetCompatibility = JavaVersion.VERSION_1_10
}
……
}
4.7.1 ending
配置源文件的编码格式。
4.7.2 sourceCompatibility
配置Java源代码的编译级别,比如1.9、1.10,取值如示例所示。
4.7.3 targetCompatibility
配置生成的Java字节码的版本,其可以选值和sourceCompatibility一样。
4.8 adbOptions{} (adb操作选项配置)
在Android Gradle中可通过adbOptions{}闭包来对adb的一些选项进行控制配置。使用例如:
android {
……
adbOptions {
timeOutInMs = 5 * 1000
installOptions '-r', '-s'
}
……
}
4.8.1 timeOutInMs
配置adb命令的超时时间,单位是毫秒。若adb操作超时会返回CommandRejectException异常。
4.8.2 installOptions
配置adb install安装操作的选项,后面跟选项的参数。一般地有下面6种选项:
-l 锁定该应用程序
-r 替换已存在的应用程序,即强制安装
-t 允许测试包
-s 把应用程序安装在sd卡上
-d 允许进行降级安装,也就是安装的程序比手机上带的版本低
-g 为应用授予所有运行时的权限
4.9 dexOptions{}(dex选项配置)
Android中的Java源代码被编译成class字节码后,在打包成apk时Android Gradle插件会调用SDK中的dx脚本命令来生成Android虚拟机可执行的dex文件。dx命令是一个脚本,它调用了Java编写的dx.jar库,是Java程序处理的,所以当内存不足的时候,可能会出现异常情况。默认情况下给dx分配的内存是1G。所以此时就要在Android Gradle中可通过dexoptions{}闭包来设置从java代码向.dex文件转化的过程中的配置选项。使用示例如:
android {
……
dexOptions {
javaMaxHeapSize = "4g"
jumboMode true
preDexLibraries true
threadCount 2
}
……
}
4.9.1 javaMaxHeapSize
配置执行dx命令时为其分配的最大堆内存。默认是1g大小,如果不够用的话,可以配置此值更大,只要你的计算机有足够的内存
4.9.2 jumboMode
配置是否开启jumbo模式。也就是忽略65535方法数限制的检查。如若你的apk明确不会运行在5.0以下的手机上,是可以直接设置此项为true。否则如果你的代码数超过65535的话,又在5.0以下手机上安装就会出现INSTALL_FAILED_DEXOPT错误。关于突破65535方法限制具体使用,请参考后面文章《Android Gradle使用详解(六) 之 如何解决65535方法限制》。
4.9.3 preDexLibraries
配置是否执行dex Libraries库工程,开启后会提高增量构建的速度,不过也会影响clean构建的速度。默认为true。当程序中代码太多,超过了65535个方法的时候,就得拆分多个Dex,此时可能存在库工程冲突情况,此时就应该将其设为false。关于突破65535方法限制具体使用,请参考后面文章《Android Gradle使用详解(六) 之 如何解决65535方法限制》。
4.9.4 threadCount
配置Android Gradle运行dx命令时使用的线程数量,适当的线程数量可以提高dx的效率。
4.10 useLibrary(使用共享库)
4.10.1 标准SDK库
Android的包(比如android.app、android.content、android.view、android.widget等)是默认包含在AndroidSDK库里的,所有的应用都可以直接使用它们,系统会帮我们自动链接它们。还有一些库,比如com.google.android.maps、android.test.runner等,这些库是独立的,并不会被系统自动链接,所以要使用它们的话,就需要单独进行生成使用,这类库称为共享库。
在AndroidManifest文件中,指定使用的库:
<uses-library
android:name=”com.goole.android.maps”
android:required=”true” />
声明之后,在安装apk包时,系统会根据我们的定义检测手机系统是否有我们需要的共享库,因为android:required=”true”,如果手机不满足将不能安装该应用。
4.10.2 add-ons附件库和optional可选库
add-ons库位于Android SDK安装目录下的add-ons目录下,这些库大部分是第三方厂商或公司开发的。
optional可选库位于Android SDK安装目录下的platforms/android-xx/optional目录下,一般是为了兼容旧版本的API,比如org.apache.http.legacy,这是一个HttpClient的库,但在Android 6.0 SDK版本开始已经将该库移除了。
and-ons附件库Android Gradle会自动解析,帮我们添加到classpath里。但optional可选库不会,要使用可选库,可以使用useLibrary方法:
android {
……
useLibrary 'org.apache.http.legacy'
}