前言
根据我们上一篇的介绍,我们知道了项目的结构以及构建的流程,根据上面的知识,我们知道了构建的规则实际就是我们写在build.gradle的内容。gradle android插件读取这个文件的内容后,最后完成构建工作。在讲解实际内容前,我先提供一个网站给大家,因为gradle android 插件 是通过dsl语言编写的,所以我们需要知道在什么地方获取相应的api。
https://docs.gradle.org/3.5/dsl/
https://google.github.io/android-gradle-dsl/current/
第一个网站是gradle官方提供的dsl,第二个网站是google提供的dsl查询手册
我们来打开根目录下面的build.gradle文件,这个文件是整个项目的配置文件,我们一般是放置一些基础的配置。
上图是build.gradle文件的内容
buildscript{} 这个是基础配置,所有的子模块都会读取到这个配置里面的内容,当构建开始的时候,就开始读取这个 buildscript{} 里面的内容。
repositories{} 这个模块的内容告诉gradle 去什么地址下载第三方的库。
jcenter() 代表https://bintray.com/bintray/jcenter
mavenCentral() 代表使用maven的服务器https://search.maven.org/
但是有一个问题就是上面的两个网站在中国访问速度慢
1.buildscript{
2.repositories{
3.maven{url’http://maven.aliyun.com/nexus/content/groups/public/’}
4.}
5.}
可以使用阿里云的maven服务
allprojects 一般是配置所有模块的共同使用的内容。
1.allprojects{
2.repositories{
3.jcenter()
4.}
5.}
这个是默认的配置,代表所有的子modle都是从jcenter获取第三方包的。我建议大家可以改成下面的写法
1.allprojects{
2.repositories{
3.maven{url’http://maven.aliyun.com/nexus/content/groups/public/’}
4.}
5.}
在根目录上面的build.gradle的版本我们可以设置gradle 插件的版本号,初学者经常搞不懂插件与gradle的关系。特别是个版本之间的关系,下面我们来讲讲插件设置的方式。
最后的序号就是插件的版本号,注意插件不是gradle,插件是根据gradle特性编写为完成需求的jar包,插件依赖于gradle。
1.dependencies{
2.classpath’com.android.tools.build:gradle:2.3.0′
3.
4.// NOTE: Do not place your application dependencies here; they belong
5.// in the individual module build.gradle files
6.}
如果你使用的是2.3版本的插件,必须使用gradle3.3以上的版本。
如果你使用的是2.2版本的插件,必须使用gradle2.14.1以上的版本。
基本原则就是对照上面的表,看看你使用的是什么版本的插件。
那gradle的版本设置在哪里设置呢?我们打开gradle文件夹找到gradle-wrapper.properties文件,如下图所示
最后我再介绍一个方法,经常有同学说打开一个项目很久,其实就是去下载gradle.我们可以根据上面的这个表来手动下载gradle。然后放置到相应的文件夹内,下面的两张图片是插件的文件目录和gradle的文件目录
一般在稍微大一点的项目中,我们都按照业务逻辑分好不同的模块。根目录下的build.gradle是对所有模块起效果的基础配置,而每个模块下的build.gradle是这个模块的详细构建的配置,下面我们来学习一下有哪些内容。
上面的这张图片是默认的build的内容。我们看到内容可以分成三份。
1.apply plugin:’com.android.application’
这句话告诉gradle使用什么类型的插件进行构建。上面的是构建应用的,如果是构建库文件的是有下面的
1.apply plugin:’com.android.library’
这个模块是声明项目的依赖,为什么我们要配置依赖呢?我们的项目大部分需要使用第三方库,而第三库很有可能还有其他的依赖,比如说Okhttp。这个依赖的内容由gradle进管理,免除了开发者下载、导入、设置等繁琐的炒作。这个内容不是android gradle 插件提供了,是gradle提供的,也就是说不止android,java,c++,只要是使用gradle构建的项目都能够使用这个模块声明。
这个模块是声明项目的依赖,可以依赖本地的文件,远程的资源库,本地的library库。详细的参数我们可以查询gradle Dsl的工具页面。
https://docs.gradle.org/current/userguide/artifact_dependencies_tutorial.html
如果英语好的同学可以看到,gradle支持了4种依赖的模式。
·compile 意思是告诉gradle编译代码是需要使用的依赖。
·runtime 产品代码在运行时需要的依赖。
·testCompile 编译测试代码时所需要的依赖。
·testRuntime 运行测试时需要的依赖。
其中runtime会包括compile的依赖。 testRuntime会包括testCompile的依赖。但是很遗憾的是,android gradle plugings不支持runtime,所以android只包含上面的compile、testCompile两种模式。
那为什么会有两种不一样的模式了,其实是这样的,比如在java Web中,编译的时候需要的是servlet的依赖,但是运行的时候,就由服务器的容器提供,所以需要分开来,但是在android中,基本上使用的依赖就是一起把类文件编译打包到apk,所以没有runtime与compile的区别。
compile是gradle依赖使用最多的关键字,在build.gradle中使用了compile后,gradle就会去repositories中加载,我们看看如果在我们的项目中使用了OKHTTP的写法是怎么写的呢?
1.compile’com.squareup.okhttp3:okhttp:3.8.0′
这个是最简单的写法,我们刚开始从eclipse转到android studio开发的时候就知道整儿写了,但是世界实际这个一个简短的写法。规范的写法应用是这样。
1.compilegroup:’com.squareup.okhttp3′,name:’okhttp’,version:’3.8.0′
同步完成后,我们可以在External Libraries下面找到添加的依赖
)
gradle 提供了下载远程依赖包的能力,这个方式也是目前最流行的方式,但是考虑到国情等情况,我们也经常需要使用本地的jar包、AAR包、libery依赖。下面我们来学习这几种依赖的写法
1.compile fileTree(include:[‘*.jar’],dir:’libs’)
上面这句话就把libs下面的jar包,导入到项目中,也就是绑定到项目的classPath.也可以单独制定某一个jar包。
1.compile files(‘libs/xxxx.jar’)
上面的这两种方法都是导入jar包的方法,如果需要导入aar包,我们需要按照下面的来写。
1.repositories{
2.flatDir{
3.dirs’libs’
4.}
5.}
增加一个本地的源目录。将aar文件放入libs文件夹。
1.compile(name:’不带后缀的文件名’,ext:’aar’)
同步完成后就可以使用导入的类库了。
我们可以在项目中创建不同的module,创建的model的时候我们可以选择创建一个不同的类型。
)
上图是我们创建一个新的module的时候可以选择的选项,通常我们选择的是第一个,代表这个是一个可执行的项目。第二个代码是一个libery库,它与一般的项目不同,libery项目不能运行,libery项目最后会生成一个aar包,aar包与jar包类似。jar包是将编译的class打包的压缩包,aar包不止包括了class还有项目的资源生成的压缩包。
上面我们学习了怎么依赖一个aar包,下面我们来学习一下怎么依赖一个library项目,常见的有两种方法:
在需要依赖的模块上面的build.gradle文件内,查找到dependencies{}模块。添加以下代码:
1.compile project(‘:名称’)
在冒号后面输入模块的名称
我们在项目上面点击右键打开moduleseting
android 模块的是该模块的详细设置,android app 的大部分的构建的内容都是在这个模块内配置的。
1.android{
2.compileSdkVersion24
3.buildToolsVersion”24.0.2″
4.defaultConfig{
5.applicationId”com.it520.x5webview”
6.minSdkVersion15
7.targetSdkVersion24
8.versionCode1
9.versionName”1.0″
10.testInstrumentationRunner”android.support.test.runner.AndroidJUnitRunner”
11.}
12.buildTypes{
13.release{
14.minifyEnabledfalse
15.proguardFiles getDefaultProguardFile(‘proguard-android.txt’),’proguard-rules.pro’
16.}
17.}
18.}
上面是android studio为我们创建的内容。
1.compileSdkVersion24
告诉Gradle 用哪个 Android SDK 版本编译你的应用,建议使用最新的SDK 进行编译。在现有代码上使用新的编译检查可以获得很多好处,避免新弃用的 API ,并且为使用新的 API 做好准备。
1.buildToolsVersion”24.0.2″
构建工具的版本,其中包括了打包工具aapt、dx等等。这个工具的目录位于..your_sdk_path/build-tools/XX.XX.XX,注意这个工具和gradle版本有关系。
1.buildTypes{
2.release{
3.minifyEnabledfalse
4.proguardFiles getDefaultProguardFile(‘proguard-android.txt’),’proguard-rules.pro’
5.}
6.}
buildTypes 用来设置应用的构建版本。默认的情况会创建两个版本,1个版本是release(发布版),1个版本是debug(开发版)。默认的情况下,只显示了release的配置。我们一般都是在buildType中设置好相应的签名文件、打包加密方式、冗余资源等。
上面的文档是buildType支持的所有的属性
·applicationIdSuffix 包名的后缀
·versionNameSuffix 版本的后缀
上面两个是我们在区分不同版本的时候增加的后缀名称
·signingConfig
上面这个配置是设置打包的签名
·shrinkResources
上面的配置是去除冗余资源
·minifyEnabled
这个配置是控制是否进行混淆。minifyEnabled true 就是开启混淆,minifyEnabled false就是关闭混淆。
1.defaultConfig{…}
默认配置,这里的代码块配置的在后面的各个构建变体(这里理解成不同的版本)都能够使用,这里面设置的值,在不同的构建变体内还可以再修改成具体的值。
上面的配置是IDE默认生成的。了解默认的脚本后,我们来看看详细的配置。
我们生成一个apk需要经过一个过程就是给这个app进行签名的过程,这个过程我们要设置应用的签名,有同学不明白,为啥咱们调试的时候不需要?实际上默认提供了一个调试的签名文件.在mac系统的位置在~/.android
在windows系统的位置在(C:\Documents and Settings[User Name].android)(C:\Users.android)这两个位置中。我们可以看到一个文件叫做debug.keystore。这个文件就是我们的调试的签名文件。
但是在正式包的时候,我们是不能使用调试的签名文件的,我们需要使用对应的签名文件。
首先我们要生成一个签名文件,
生成完成后,我们要配置这个应用的签名,配置签名一般有以下几个参数,详细的参数请查看
上图的4个值分别是 签名的别名,签名的密码,签名的位置,签名的密码
1.signingConfigs{
2.debug{
3.}
4.realse{
5.keyAlias’xmg’
6.keyPassword’123456′
7.storeFile file(‘/Users/kay/Desktop/release_key.jks’)
8.storePassword’123456′
9.}
10.}
定义了两种类型的签名配置。
设置好签名配置,我们要给不同类型的构建设置签名。
1.buildTypes{
2.release{
3.minifyEnabledfalse
4.proguardFiles getDefaultProguardFile(‘proguard-android.txt’),’proguard-rules.pro’
5.signingConfig signingConfigs.realse
6.}
7.debug{
8.applicationIdSuffix”.debug”
9.versionNameSuffix”huangkai”
10.}
11.}
在上面的代码,我们给发布版设置了签名配置。
为了验证签名配置的情况,我们切换到Terminal对话框,在对话框下输入以下命令
1../gradlew assembleRelease
除了可以使用配置的情况,我们也可以使用ide来配置达到一样的效果。
我们现在在中国开发要面对大量的渠道商(360市场、小米商店、应用宝),为了统计不同的渠道商,我们需要提供不同的版本。这样就会给开发者增加大量的开发任务,而且也出现代码管理的问题。原来在eclipse的环境下,我们需要将代码复制多份,再运行打包脚本,打包成不同的渠道包。但是现在使用gradle进行代码管理,我们就不需要在做这个了,我们可以使用gradle来定制不同的版本,最后gradle会根据一定的规则把代码或者资源进行融合,最后生成我们需要的apk。
在android{}模块内部增加以下的代码
1.productFlavors{
2.
3.free{
4.
5.}
6.pay{
7.
8.}
9.}
我们定义了当前的应用有两个版本,一个是free(免费),pay(收费)。我们预计要打两个版本的包。这里组合起来有四个版本。
·freeDebug
·freeRelease
·payDebug
·payRelease
gradle把不同版本的文件夹下的资源进行合并与替换,假设free与pay版本的区别在与某个资源文件。
我们在src文件中创建相关的资源文件夹。
接着我们在各个资源夹中创建一个string.xml资源文件,接着编写以下内容
!!!!注意,在各个资源文件夹下的内容要不一样才看得到区别。
接着我们编写一个activity放置在main文件夹内,在activity的布局显示这个字符串title。
在左下方选择相应的构建类型,比如说我们选择的是payDebug
编写代码完成后,我们可以使用命令行来构建相应的版本。
1../gradlew assembleFreeRelease
总结一下,同名的资源文件可以存在不同的版本文件内。
上面的例子我们是通过一个资源来区分应用的版本,在实际的开发中,也存在这样的情况,不同的版本可能有不一样的业务逻辑,所以我们可能需要在不同的版本里面处理java代码。
首先我们还是在之前的项目结构上面进行开发,这里有两个版本,一个free,一个pay。
首先我们先选择一个build variants,在这里我们选择payDebug。
选择完成后,我们打开pay文件夹,我们需要创建一个Activity。我们知道java代码再android studio下面默认是存放在java文件夹下的。所以我们需要创建一个Java文件夹。
同样的步骤我们在free文件夹也操作一遍
我们发现了free 和 pay 的Java文件夹颜色不一样,pay的变成了蓝色,free还是普通的黄色。
我们尝试新建一个class。
很明显在free文件上面没法新建类。为什么呢?
因为我们之前选择的payDebug,ide就只编译了pay文件夹下面的Java类。如果我们选择了freeDebug,情况就刚好相反。
我们在free 和 pay 下面创建了两个同名的activity,并指派了不同的界面。分别运行后,发现每次运行只能选其中一种显示。
接着我们在main文件夹下面创建一个类,Util。接着我们无论在free或者pay下面都无法创建同名的类了,均会提示我们重复创建类错误。
总结一下:
·1 main 文件夹下有A类,那个其他版本的文件夹内不能有同名的类A
·2 不同版本的相同的文件A类,运行的时候请选择相应的build variants
上面的例子是我们使用productFlavors合并了java代码。
7.2.3.3 定制版本组合 flavorDimensions
在项目中,我们可能会碰到这样的需求,我们可能需要对某个版本提供特殊的功能,但是这个功能与当前的定制版本代码差别不大,如果根据每个定制版本都再新建一个定制版本出来就优点复杂了。比如说我们根据上面的例子来说,当前的应用提供了两个定制版本,一个是pay,一个是free。但是项目在测试的时候,测试组希望根据版本提供有log消息和没有log消息的版本。根据之前的我们需要新建payLog,payNoLog,freeLog,freeNoLog等版本。看起来还行吧,但是如果不止两个而是5个版本,pay,free,….free5,而且log和noLog的区别可能就是几句代码。那个这个项目的结构就太过复杂了。这个时候,我们就可以使用定制版本组合。
定制版本组合怎么操作呢,我们根据需求将代码分成不同的组,不同的组代表不同的功能,组和组可以互相组合,最终形成需要的版本。相对于productFlavors,flavorDimensions是productFlavors的补充选择,可以让我们版本定制更灵活。
以上面的例子来说:
我们可以将版本的需求分成两个维度,一个是支付状态,一个是输出消息状态。
1.flavorDimensions”log”,”pay_status”
首先定义两个维度。下面我们要指定版本属于哪个维度。
1.productFlavors{
2.
3.withLog{
4.dimension”log”
5.}
6.noLog{
7.dimension”log”
8.}
9.
10.free{
11.dimension”pay_status”
12.}
13.pay{
14.dimension”pay_status”
15.}
16.
17.}
最后gradle会自动组合版本
我们在上面的内容学习了依赖的写法,但是之前我们学习依赖的时候,这个依赖的是对这个项目整体生效的。意思就是项目所有的版本都生效,但是在实际开发中,我们可能会碰到这样的情况,比如说我们开发一个应用,这个应用分成收费版本和免费版本。收费版本不需要显示广告。免费版本因为没有付费,需要显示广告。在这里我们需要对我们的定制版本的依赖做细化的区分。原来在eclipse的时候,我们只能通过复制多一份代码来进行实现。现在我们可以同过gradle实现。
1.free{
2.dimension”pay_status”
3.
4.dependencies{
5.freeCompile’com.bm.photoview:library:1.4.1′
6.}
7.}
在上面的代码我们在版本定制内部添加了一个xxxxCompile的标签,这个意思就是告诉gradle是什么版本的依赖。xxxx是这个版本的名称。
我们可以使用这个参数来告诉Gradle什么文件打包到apk内,什么文件不打包,重复文件如何处理等。
·pickFirst 路径,如果文件匹配这个路径,只有第一个文件打包进apk
·Merge 合并两个文件进入apk,第二个文件会在第一个文件后
·
Exclude 不打包的文件的路径
·
·
i.packagingOptions{
ii.//以下文件不加入apk里
iii.exclude’LICENSE.txt’
iv.}