前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Gradle系列-进阶篇

Android Gradle系列-进阶篇

作者头像
Rouse
发布2019-07-17 17:42:28
1.5K0
发布2019-07-17 17:42:28
举报
文章被收录于专栏:Android补给站

Rouse

读完需要

13

分钟

速读仅需5分钟

上篇文章我们已经将Gradle基础运用介绍了一遍,可以这么说,只要你一直看了我这个Gradle系列,那么你的Gradle也将过关了,应对正常的工作开发已经不成问题了。

这篇文章我要向你介绍的是关于如何使用Gradle来更加优雅的管理多个module之间的依赖关系。

相信你一定有这样的经历:主项目依赖于多个子项目,或者项目间互相依赖。不同子项目间的依赖的第三方库版本又没有进行统一,升级一个版本所有依赖的项目都要进行修改;甚至minSdkVersion与targetSdkVersion也不相同。

今天我们就来解决这个问题,让Gradle版本管理更加优雅。

1

Google推荐

之前的文章Gradle系列-运用篇中的dependencies使用的是最基本的引用方式。如果你有新建一个kotlin项目的经历,那么你将看到Google推荐的方案

代码语言:javascript
复制
 1buildscript {
 2    ext.kotlin_version = '1.1.51'
 3    repositories {
 4        google()
 5        jcenter()
 6    }
 7    dependencies {
 8        classpath 'com.android.tools.build:gradle:3.0.0'
 9        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
10    }
11}

在rootProject的build.gradle中使用ext来定义版本号全局变量。这样我们就可以在module的build.gradle中直接引用这些定义的变量。引用方式如下:

代码语言:javascript
复制
1dependencies {
2    implementation fileTree(dir: 'libs', include: ['*.jar'])
3    implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
4}

你可以将这些变量理解为java的静态变量。通过这种方式能够达到不同module中的配置统一,但局限性是,一但配置项过多,所有的配置都将写到rootProject项目的build.gradle中,导致build.gradle臃肿。这不符合我们的所提倡的模块开发,所以应该想办法将ext的配置单独分离出来。

这个时候我就要用到之前的文章Android Gradle系列-原理篇中所介绍的apply函数。之前的文章我们只使用了apply三种情况之一的plugin(应用一个插件,通过id或者class名),只使用在子项目的build.gradle中。

代码语言:javascript
复制
1apply plugin: 'com.android.application'

这次我们需要使用它的from,它主要是的作用是应用一个脚本文件。作用接下来我们需要做的是将ext配置单独放到一个gradle脚本文件中。

首先我们在rootProject目录下创建一个gradle脚本文件,我这里取名为version.gradle。

然后我们在version.gralde文件中使用ext来定义变量。例如之前的kotlin版本号就可以使用如下方式实现

代码语言:javascript
复制
 1ext.deps = [:]
 2
 3def versions = [:]
 4versions.support = "26.1.0"
 5versions.kotlin = "1.2.51"
 6versions.gradle = '3.2.1'
 7
 8def support = [:]
 9support.app_compat = "com.android.support:appcompat-v7:$versions.support"
10support.recyclerview = "com.android.support:recyclerview-v7:$versions.support"
11deps.support = support
12
13def kotlin = [:]
14kotlin.kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jre7:$versions.kotlin"
15kotlin.plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
16deps.kotlin = kotlin
17
18deps.gradle_plugin = "com.android.tools.build:gradle:$versions.gradle"
19
20ext.deps = deps
21
22def build_versions = [:]
23build_versions.target_sdk = 26
24build_versions.min_sdk = 16
25build_versions.build_tools = "28.0.3"
26ext.build_versions = build_versions
27
28def addRepos(RepositoryHandler handler) {
29    handler.google()
30    handler.jcenter()
31    handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
32}
33ext.addRepos = this.&addRepos

因为gradle使用的是groovy语言,所以以上都是groovy语法

例如kotlin版本控制,上面代码的意思就是将有个kotlin相关的版本依赖放到deps的kotlin变量中,同时deps放到了ext中。其它的亦是如此。

既然定义好了,现在我们开始引入到项目中,为了让所有的子项目都能够访问到,我们使用apply from将其引入到rootProject的build.gradle中

代码语言:javascript
复制
1buildscript {
2    apply from: 'versions.gradle'
3    addRepos(repositories)
4    dependencies {
5        classpath deps.gradle_plugin
6        classpath deps.kotlin.plugin
7    }
8}

这时build.gradle中就默认有了ext所声明的变量,使用方式就如dependencies中的引用一样。

我们再看上面的addRepos方法,在关于Gradle原理的文章中已经分析了repositories会通过RepositoryHandler来执行,所以这里我们直接定义一个方法来统一调用RepositoryHandler。这样我们在build.gradle中就无需使用如下方式,直接调用addRepos方法即可

代码语言:javascript
复制
1    //之前调用
2    repositories {
3        google()
4        jcenter()
5    }
6    //现在调用
7    addRepos(repositories)

另一方面,如果有多个module,例如有module1,现在就可以直接在module1中的build.gradle中使用定义好的配置

代码语言:javascript
复制
1dependencies {
2    implementation fileTree(dir: 'libs', include: ['*.jar'])
3    // support
4    implementation deps.support.app_compat
5    //kotlin
6    implementation deps.kotlin.kotlin_stdlib
7}

上面我们还定义了sdk与tools版本,所以也可以一起统一使用,效果如下

代码语言:javascript
复制
 1android {
 2    compileSdkVersion build_versions.target_sdk
 3    buildToolsVersion build_versions.build_tools
 4    defaultConfig {
 5        applicationId "com.idisfkj.androidapianalysis"
 6        minSdkVersion build_versions.min_sdk
 7        targetSdkVersion build_versions.target_sdk
 8        versionCode 1
 9        versionName "1.0"
10        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
11    }
12    ...
13}

一旦实现了统一配置,那么之后我们要修改相关的版本就只需在我们定义的version.gradle中修改即可。无需再对所用的module进行逐一修改与统一配置。

2

BuildSrc&Kotlin

如果你的项目使用了kotlin,那么buildSrc&Kotlin的统一管理方案将更适合你。

Gradle项目会默认识别buildSrc目录,并且会将该目录中的配置注入到build.gradle中,以至于让build.gradle能够直接引用buildSrc中的配置项。

有了这一特性,我们就可以直接将之前version.gradle中的配置放入到buildSrc中,下面我们开始实现。

首先在根目录新建一个buildSrc目录(与app同级),然后在该目录新建src/main/java目录,该目录是你之后配置项所在的目录;同时再新建build.gradle.kts文件,并在该文件中添加kotlin-dsl

代码语言:javascript
复制
1plugins {
2    `kotlin-dsl`
3}
4
5repositories {
6    jcenter()
7}

之后再sync project,最终的目录结构如下

搭建好了目录,现在我们在src/main/java下使用kotlin新建Dependencies文件(文件名任意),在该文件中将之前的配置项放进来,只是使用kotlin语法进行实现而已,转化的代码如下

代码语言:javascript
复制
 1object Versions {
 2    const val support = "26.1.0"
 3    const val kotlin = "1.3.31"
 4    const val gradle = "3.4.1"
 5    const val target_sdk = 26
 6    const val min_sdk = 16
 7    const val build_tools = "28.0.3"
 8}
 9
10object Dependencies {
11    val app_compat = "com.android.support:appcompat-v7:${Versions.support}"
12    val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
13    val kotlin_plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
14    val gradle_plugin = "com.android.tools.build:gradle:${Versions.gradle}"
15    val addRepos: (handler: RepositoryHandler) -> Unit = {
16        it.google()
17        it.jcenter()
18        it.maven { url = URI("https://oss.sonatype.org/content/repositories/snapshots") }
19    }
20}

这时你就可以直接使用Dependencies与Versions在各个build.gradle中引用,例如app下的build.gradle

代码语言:javascript
复制
 1android {
 2    compileSdkVersion Versions.target_sdk
 3    buildToolsVersion Versions.build_tools
 4    defaultConfig {
 5        applicationId "com.idisfkj.androidapianalysis"
 6        minSdkVersion Versions.min_sdk
 7        targetSdkVersion Versions.target_sdk
 8        versionCode 1
 9        versionName "1.0"
10        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
11    }
12    ...
13}
14dependencies {
15    implementation fileTree(dir: 'libs', include: ['*.jar'])
16    // support
17    implementation Dependencies.app_compat
18    //kotlin
19    implementation Dependencies.kotlin_stdlib
20}

根目录的build.gralde亦是如此

代码语言:javascript
复制
 1buildscript {
 2    Dependencies.addRepos.invoke(repositories)
 3    dependencies {
 4        classpath Dependencies.gradle_plugin
 5        classpath Dependencies.kotlin_plugin
 6    }
 7}
 8
 9allprojects {
10    Dependencies.addRepos.invoke(repositories)
11}
12
13task clean(type: Delete) {
14    delete rootProject.buildDir
15}

其实我们真正需要get到的是一种思想,将配置统一管理。至于到底使用哪一种,这就看个人喜好了,但如果你的项目使用了kotlin,我还是建议你使用buildSrc模式,因为对于Groovy语法而言,我相信你还是对Kotlin更加熟悉。

源码地址: https://github.com/idisfkj/android-api-analysis

Android补给站

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android补给站 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档