Android Gradle 三方依赖管理详解

目录
  • 发展历史
  • 最原始的依赖
  • 使用 .gradle 配置
  • 使用 gradle.properties 配置
  • 使用 buildSrc 配置
  • 使用 Composing Builds 配置
  • Version Catalogs 配置
    • 开始使用
    • 使用 settings.gradle.kts 配置
  • 使用 libs.versions.toml 配置
    • 使用插件配置
      • 插件配置
    • 插件使用
      • 重写版本
    • 使用方式
  • 总结

发展历史

Gradle 的依赖管理是一个从开始接触 Android 开发就一直伴随着我们的问题(作者是Android开发,仅以此为例),从最初的 没有统一管理 到 通过.gradle或gradle.properties管理,再到 Kotlin 出现之后使用 buildSrc 管理 以及在这基础上优化的 Composing BuildsGradle 依赖管理一直在不断的发展、更新,而到了 Gradle 7.0Gradle 本身又专门提供了全新的 Version Catalogs 用于依赖管理,今天我们就来说说这些方式的优劣及使用方式吧。

最原始的依赖

当我们通过 Android Studio 创建一个新项目,这个项目里面默认的依赖就是最原始的,没有经过统一管理的;如果你的项目中只有一个 module,那么这种默认的管理方式也是可以接受的,是否对它进行优化,这取决于你是否愿意投入成本去修改,谈不上什么优劣。

使用 .gradle 配置

当你的项目中 module 的数量超过一个甚至越来越多的时候,对 Gradle 依赖进行统一管理就变得重要起来,因为你不会想在升级一个三方依赖的版本后发现冲突,然后一个个打开各个 module 的 build.gradle 文件,找到你升级的那个依赖引用,重复的进行版本修改;

因此我们有了初步的优化方案:

  • 在项目根目录下创建 config.gradle 文件,在其中按照以下格式添加相关配置;
ext {
    android = [
            compileSdkVersion: 30
    ]
    dependencies = [
        "androidx-core-ktx"	:	"androidx.core:core-ktx:1.3.2",
        "androidx-appcompat":	"androidx.appcompat:appcompat:1.2.0",
        "google-material"	:	"com.google.android.material:material:1.3.0"
    ]
}
  • 在项目根目录下的 build.gradle 文件顶部添加 apply from: "config.gradle"
  • 在各个 module 的 build.gradle 中就可以通过 rootProject 来引用对应的依赖及参数了;
...
    android {
        compileSdkVersion rootProject.ext.android.compileSdkVersion
    }
...
    dependencies {
        implementation rootProject.ext.dependencies["androidx-core-ktx"]
        implementation rootProject.ext.dependencies["androidx-appcompat"]
        implementation rootProject.ext.dependencies["google-material"]
    }
...

使用这种方式,我们就能够将项目中的版本配置、三方依赖统一管理起来了,但是这种方式还是有缺陷的,我们无法像正常代码中一样便捷的跳转到依赖定义的地方,也不能简单的找到定义的依赖在哪些地方被使用。

使用 gradle.properties 配置

这个方式和上面的方式类似,把依赖相关数据定义到 gradle.properties 文件中:

...
androidx-core-ktx = androidx.core:core-ktx:1.3.2
androidx-appcompat = androidx.appcompat:appcompat:1.2.0
androidx-material = com.google.android.material:material:1.3.0

在各个 module 的 build.gradle 中使用;

...
    dependencies {
        implementation "${androidx-core-ktx}"
        implementation "${androidx-appcompat}"
        implementation "${google-material}"
    }

这种方式相对于 .gradle 方式不需要单独创建 config.gradle 文件,但是同样的也无法快速定位到定义的地方及快速跳转到依赖使用。

使用 buildSrc 配置

在 Kotlin 的支持下,我们又有了新的方案,这个方案依赖于 IDEA 会将 buildSrc 路径作为插件编译到项目以及 Kotlin dsl 的支持,并且解决上面两个方案依赖无法快速跳转问题;

使用方式如下:

  • 在项目根目录新建文件夹 buildSrc,并在该路径下新建 build.gradle.kts 文件,该文件使用 Kotlin 语言配置
repositories {
   google()
   mavenCentral()
}

plugins {
    // 使用 kotlin-dsl 插件
   `kotlin-dsl`
}
  • 在 buildSrc 中添加源码路径 src/main/kotlin,并在源码路径下添加依赖配置 Dependencies.kt
object Dependencies {
	const val ANDROIDX_CORE_KTX = "androidx.core:core-ktx:1.3.2"
	const val ANDROIDX_APPCOMPAT = "androidx.appcompat:appcompat:1.2.0"
	const val GOOGLE_MATERIAL = "com.google.android.material:material:1.3.0"
}
  • 在各个 module 中的 build.gradle.kts 文件中使用依赖
...

	dependencies {
    	implementation(Dependencies.ANDROIDX_CORE_KTX)
    	implementation(Dependencies.ANDROIDX_APPCOMPAT)
    	implementation(Dependencies.GOOGLE_MATERIAL)
    }

这个方案的优点正如上面所说的,能够快速方便的定位到依赖的定义及使用,其确定就在于因为需要 Kotlin 支持,所以需要向项目中引入 Kotlin 的依赖,并且各个 module 的 build.gradle 配置文件需要转换为 build.gradle.kts 格式。

使用 Composing Builds 配置

Composing Builds 方案的本质和 buildSrc 方案是一样的,都是将对应 module 中的代码编译作为插件,在 build.gradle.kts 中可以直接引用,那为什么还要有 Composing Builds 这种方案呢?这是因为 buildSrc 方案中,如果 buildSrc 中的配置有修改,会导致整个项目都会进行重新构建,如果项目较小可能影响不大,但如果项目过大,那这个缺点显然是无法接受的,Composing Builds 方案应运而生。

使用方式:

  • 在项目根目录创建 module 文件夹,名称随意,这里使用 plugin-version,并在文件夹中创建 build.gradle.kts 配置文件,内容如下:
plugins {
    id("java-gradle-plugin")
    id("org.jetbrains.kotlin.jvm") version "1.7.10"
}
repositories {
    google()
    mavenCentral()
    gradlePluginPortal()
}
java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

dependencies {
    // 添加Gradle相关的API,否则无法自定义Plugin和Task
    implementation(gradleApi())
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
}

gradlePlugin {
    plugins {
        create("version") {
            // 添加插件,下面是包名
            id = "xx.xx.xx"
            // 在源码路径创建类继承 Plugin<Project>
            implementationClass = "xx.xx.xx.VersionPlugin"
        }
    }
}
  • 创建源码目录及包路径 src/main/kotlin/xx.xx.xx,在包中新建类 VersionPlugin 继承 org.gradle.api.Plugin
class VersionPlugin : Plugin<Project> {
    override fun apply(target: Project) {
    }
}
  • 在项目根目录下的 settings.gradle.kts 文件中添加 includeBuild("plugin-version")
  • 最后和 buildSrc 方案一样,在源码路径下新增相关依赖配置,在各个 module 中引用即可。

Version Catalogs 配置

从 Gradle 7.0 开始,Gradle 新增了 Version Catalogs 功能,用于在项目之间共享依赖项版本, Gradle 文档中列出的一下优点:

  • 对于每个 Catelog ,Gradle 都会生成类型安全的访问器,可以轻松的在 IDE 中使用,完成添加依赖;
  • 每个 Catelog 对生成的所有项目都可见,可以确保依赖版本同步到所有子项目;
  • Catelog 可以声明依赖关系包,这些捆绑包是通常在一起使用的依赖关系组;
  • Catelog 可以将依赖项的组、名称和实际版本分开,改用版本引用,从而可以在多个依赖项中共享版本声明。

接下来我们来学习这种方案的具体使用。

开始使用

使用 Version Catalogs 首先当然是需要项目 Gradle 版本高于 7.0,之后在项目根路径下的 settings.gradle.kts 中添加配置(因为作者项目用的是 .ktsgroovy 按对应语法添加即可)

dependencyResolutionManagement {
    // 版本目录配置
    versionCatalogs {
        // 创建一个名称为 libs 的版本目录
        create("libs") {
            // 声明 groovy 依赖
            library("groovy-core", "org.codehaus.groovy:groovy:3.0.5")
        }
    }
}

在上面的配置之后,你就可以在项目中使用对应依赖了。例:build.gradle.kts

dependencies {
    implementation(libs.groovy.core)
}

这里有细心的小伙伴就会发现,我们声明的是 groovy-core,使用的时候却是 libs.groovy.core,这是因为 Version Catalogs 在根据别名生成依赖时对安全访问器的映射要求,别名必须由 ascii 字符组成,后跟数字,中间分隔只支持 短划线-下划线_点.,因此声明别名时可以使用groovy-coregroovy_coregroovy.core,最终生成的都是 libs.groovy.core

使用 settings.gradle.kts 配置

就如上面的示例中,我们就是在 settings.gradle.kts 中声明了 groovy-core 的依赖,并且需要的地方使用,接下来我们详细说明对依赖项声明的语法:

dependencyResolutionManagement {
    // 版本目录配置
    versionCatalogs {
        // 创建一个名称为 libs 的版本目录
        create("libs") {
            // 声明 kotlin 版本
            version("kotlin", "1.7.10")
            // 声明 groovy 版本
            version("groovy", "3.0.5")

            // 声明 groovy 依赖
            library("groovy-core", "org.codehaus.groovy:groovy:3.0.5")
            // 声明 groovy 依赖
            library("groovy-nio", "org.codehaus.groovy", "groovy-nio").version("3.05")
            // 声明 groovy 依赖使用版本引用
            library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")

            // 声明 groovy 依赖组
            bundle("groovy", listOf("groovy-core", "groovy-json", "groovy-nio"))

            // 声明 kotlin 序列化插件
            plugin("kotlin-serialization", "org.jetbrains.kotlin.plugin.serialization").versionRef("kotlin")
        }
    }
}

这种方式相对统一了依赖版本,却无法做到多项目统一。

使用 libs.versions.toml 配置

还是先看示例代码:

dependencyResolutionManagement {
    // 版本目录配置
    versionCatalogs {
        // 创建一个名称为 libs 的版本目录
        create("libs") {
            // 不能如此配置,会抛出异常
            from(files("./gradle/libs.versions.toml"))
            // 可以添加此配置
            from(files("./gradle/my-libs.versions.toml"))
        }
        // 创建一个名称为 configLibs 的版本目录
        create("configLibs") {
            // 添加配置文件
            from(files("./gradle/configLibs.versions.toml"))
        }
    }
}

在配置版本目录后,出了直接在 .kts 里面添加依赖定义,还可以通过 from 方法从 .toml 文件中加载,.toml 文件一般放在项目根路径下的 gradle 文件夹中。

这里需要注意的是,gradle 有一个默认配置名称为 libs,如果你创建的版本目录名称是 libs,那么你就无需通过 from 方法加载 libs.versions.toml 文件,因为 gradle 会默认此配置,你只需在 ./gradle 路径下创建 libs.versions.toml 文件即可,重复添加会导致编译失败;如果你已经有了一个 libs.versions.toml 你也可以在添加以下配置来修改默认配置名称:

dependencyResolutionManagement {
    defaultLibrariesExtensionName.set("projectLibs")
}

如果你创建的版本目录名称不是默认配置名称,那么就需要你手动添加 from 方法加载配置;所有版本目录名称建议以 Libs 结尾,否则会有 warning,提示后续将不支持此命名。

接下来我们来看 .toml 文件的配置规则:

# 声明版本号
[versions]
kotlin = "1.7.10"
groovy = "3.0.5"

# 声明依赖
[libraries]
# groovy
groovy-core = "org.codehaus.groovy:groovy:3.0.5"
groovy-json = { module = "org.codehaus.groovy:groovy-json", version = "3.0.5" }
groovy-nio = { group = "org.codehaus.groovy", name = "groovy-nio", version.ref = "groovy" }

# 声明依赖组
[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]

# 声明插件
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }

这种方式在统一单一项目依赖版本的同时,可以通过分享 .toml 文件来达成多项目依赖版本的统一,但是同样的,同样的文件在不同项目中不可避免是会被修改的,用着用着就不一致了。

使用插件配置

虽然从本地文件导入很方便,但是并不能解决多项目共享版本目录的问题,gradle 提供了新的解决方案,我们可以在一个独立的项目中配置好各个三方依赖,然后将其发布到 maven 等三方仓库中,各个项目再从 maven 仓库中统一获取依赖

插件配置

为了实现此功能,gradle 提供了 version-catalog 插件,再配合 maven-publish 插件,就能很方便的生产插件并发布到 maven 仓库。

新建 gradle 插件项目,修改 build.gradle.kts

plugins {
    `maven-publish`
    `version-catalog`
}

// 版本目录配置
catalog {
    versionCatalog {
        // 在这里配置各个三方依赖
        from(files("./gradle/libs.versions.toml"))
        version("groovy", "3.0.5")
        library("groovy-json", "org.codehaus.groovy", "groovy-json").versionRef("groovy")
    }
}

// 配置 publishing
publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["versionCatalog"])
        }
    }
}

这里需要注意的是,插件项目的 gradle 版本必须要高于 7.0 并且低于使用该插件的项目的版本,否则将无法使用。

插件使用

配置从 maven 仓库加载版本目录

dependencyResolutionManagement {
    // 版本目录配置
    versionCatalogs {
        // 创建一个名称为 libs 的版本目录
        create("libs") {
            // 从 maven 仓库获取依赖
            from("io.github.wangjie0822:catalog:1.1.3")
        }
    }
}

重写版本

从 maven 仓库中获取版本目录一般来讲就不应该修改了,但是仅一份依赖清单怎么满足我们的开发需求呢,不说各个依赖库都在不断的持续更新,如果我们需要使用的依赖没有在版本目录里面声明呢?我们不可能为了修改一个依赖的版本或者添加一个依赖就频繁的发布Catalog插件版本,这样成本太高,这就需要我们进行个性化配置了

dependencyResolutionManagement {
    // 版本目录配置
    versionCatalogs {
        // 创建一个名称为 libs 的版本目录
        create("libs") {
            // 从 maven 仓库获取依赖
            from("io.github.wangjie0822:catalog:1.1.3")
            // 添加仓库里面没有的依赖
            library("tencent-mmkv", "com.tencent", "mmkv").version("1.2.14")
            // 修改groovy版本
            version("groovy", "3.0.6")
        }
    }
}

请注意,我们只能重写版本目录里面定义的版本号,所以在定义版本目录时尽量将所有版本号都是用版本引用控制。

使用方式

上面说了那么多的配置定义方式,下面来看看Version Catalogs的使用方式:

plugins {
    // 可以直接使用定义的 version 版本号
    kotlin("plugin.serialization") version libs.versions.kotlin
    // 也可以直接使用定义的插件
    alias(libs.plugin.kotlin.serialization)
}

android {
    defaultConfig {

        // 其它非依赖的字段可以在版本目录的版本中定义 通过 versions 获取
        minSdk = configLibs.versions.minSdk.get().toInt()
        targetSdk = configLibs.versions.targetSdk.get().toInt()

        versionCode = configLibs.versions.versionCode.get().toInt()
        versionName = configLibs.versions.versionName.get()
    }
}

dependencies {
    // 使用 groovy 依赖
    implementation(libs.groovy.core)

    // 使用包含 groovy-core groovy-json groovy-no 三个依赖的依赖组
    implementation(libs.bundles.groovy)

    // 使用 configLibs 中定义的依赖
    implementation(configLibs.groovy.core)
}

上面我们已经说过这种方案的优点,可以让我们在所有项目中保持依赖版本的统一,甚至可以分享出去让其他开发者使用;同时也有着和 buildSrcComposing Builds一样的可跳转、可追溯的优点;

但是相比于这两个方案,Version Catalogs生成的代码只有默认的注释,并且无法直接看到使用的依赖的版本号,而在 buildSrcComposing Builds 中我们能够对依赖的功能进行详细的注释,甚至添加上对应的使用文档地址、Github 地址等,如果支持自定义注释,那这个功能就更完美了。

总结

Android 发展至今,各种新技术层出不穷,版本管理也出现了很多方案,这些方案并没有绝对的优劣,还是需要结合实际项目需求来选择的,但是新的方案还是需要学习了解的。

到此这篇关于Android Gradle 三方依赖管理详解的文章就介绍到这了,更多相关Android Gradle内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • AndroidStudio Gradle第三依赖统一管理的实现方法

    AndroidStudio由于使用了gradle的进行项目构建,使我们开发app方便很多,今天我就给大家列出几点是用gradle的方便之处. 一.AndroidStudio Gradle第三依赖统一管理 二.AndroidStudio Gradle基于友盟的多渠道打包 三.AndroidStudio安全管理签名文件keystroe和签名密码 这三篇文章很好的讲解了gradle的在打包和项目依赖管理的优点,大家可以参考一下,来提高自己的开发效率,增强签名文件的安全性. 在很多时候我们使用Andro

  • Android Gradle依赖管理、去除重复依赖、忽略的方式

    常用依赖 //1.直接依赖第三方开源库,一般是托管在 jitpack 或者 jcenter implementation 'com.google.code.gson:gson:2.2.4' implementation 'com.android.support:cardview-v7:25.0.0' implementation 'com.android.support:design:25.0.0' //2.直接依赖本地的aar文件,一般是在libs目录下 implementation(name

  • 详解Android使用Gradle统一配置依赖管理

    在介绍使用 Gradle 统一配置依赖管理前我们先来简单介绍一下 Gradle, Gradle 是一个基于 JVM 的构建工具,也是一款非常灵活强大的构建工具,支持  jcenter.maven.Ivy 仓库,支持传递性依赖管理(即 A 依赖 B,B 依赖 C,那么 A 也就可以依赖 C,不用再单独去依赖),而不需要远程仓库或者是 pom.xml 和 ivy.xml 配置文件,抛弃了各种繁琐,基于 Groovy,build 脚本使用 Groovy 编写 而在我们的 Android studio

  • Android Gradle 三方依赖管理详解

    目录 发展历史 最原始的依赖 使用 .gradle 配置 使用 gradle.properties 配置 使用 buildSrc 配置 使用 Composing Builds 配置 Version Catalogs 配置 开始使用 使用 settings.gradle.kts 配置 使用 libs.versions.toml 配置 使用插件配置 插件配置 插件使用 重写版本 使用方式 总结 发展历史 Gradle 的依赖管理是一个从开始接触 Android 开发就一直伴随着我们的问题(作者是An

  • Crashlytics Android 异常报告统计管理(详解)

    简介 Crashlytic 成立于2011年,是专门为移动应用开者发提供的保存和分析应用崩溃信息的工具.Crashlytics的使用者包括:支付工具Paypal, 点评应用Yelp, 照片分享应用Path, 团购应用GroupOn等移动应用. 2013年1月,Crashlytics被Twitter收购,成为又一个成功的创业产品.被收购之后,由于没有了创业公司的不稳定因素,我们更有理由使用它来分析应用崩溃信息. 使用Crashlytics的好处有: 1.Crashlytics不会漏掉任何应用崩溃信

  • Android DaggerActivityComponent错误解决办法详解

    Android DaggerActivityComponent错误解决办法详解 在使用dagger2的过程中,如果修改了某个类的内容,第一次编译运行时总会报错:错误: 找不到符号 符号: 类 DaggerActivityComponent 位置: 程序包 com--的错误,然后再重新编译一次,才会正常运行,经过仔细的检查终于找到问题的根源: 错误的原因是build.gradle(Module:app)引入'com.google.dagger:dagger-compiler:2.0.2'使用的是c

  • Gradle的使用教程详解

    Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具.它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,目前也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置. 面向Java应用为主.当前其支持的语言限于Java.Groovy.Kotlin和Scala,计划未来将支持更多的语言. 一.相关介绍 Gradle是一个好用的构建工具 ,使用它的原因是: 配置相关依赖代码量少,不会像maven一样xm

  • Android组件之服务的详解

    目录 一.服务的概念 二.Android的多线程编程 2.1 线程的基本用法 2.2 在子线程中更新UI 更新方式一 更新方式二 2.3 解析异步消息处理机制 2.4 使用AsyncTask 三.服务的基本用法 3.1 首先定义一个服务 3.2 MyService类里重写几个方法 3.3 在注册文件中完成对服务的注册 3.4 启动和停止服务 3.5 活动和服务进行通信 四.服务的生命周期 五.服务的更多技巧 5.1 使用前台服务 5.2 服务中的多线程问题&IntentService 一.服务的

  • Android多渠道打包神器ProductFlavor详解

    目录 一.什么是多渠道打包 1.多版本 2.多环境 3.多渠道 二.多渠道打包的方式(ProductFlavor&&多渠道打包插件) 1.ProductFlavor 1.1 如何是使用ProductFlavor 1.2 如何是使用ProductFlavor加载apk包 1.3 该如何获取不同渠道包的信息 1.4 使用ProductFlavor加载apk包的优缺点 2.多渠道打包插件 一.什么是多渠道打包 在不同的应用市场可能有不同的统计需求,需要为每个应用市场发布一个安装包,这里就引出了A

  • Android Google AutoService框架使用详解

    目录 AutoService的使用 关于SPI SPI示例 APT技术 AutoService源码 AutoService源码分析 一般我们用它来自动帮我们注册APT文件(全称是Annotation Process Tool,或者叫注解处理器,AbstractProcessor的实现).很多生成SPI文件的框架也是抄袭它的源码,可见它的作用还不小. APT其实就是基于SPI一个工具,是JDK留给开发者的一个在编译前处理注解的接口.APT也是SPI的一个应用.关于SPI和APT下文会详细讲到. 先

  • kotlin android extensions 插件实现示例详解

    目录 前言 原理浅析 总体结构 源码分析 插件入口 配置编译器插件传参 编译器插件接收参数 注册各种Extension IrGenerationExtension ExpressionCodegenExtension StorageComponentContainerContributor ClassBuilderInterceptorExtension PackageFragmentProviderExtension 总结 前言 kotlin-android-extensions 插件是 Ko

  • Android的搜索框架实例详解

    基础知识 Android的搜索框架将代您管理的搜索对话框,您不需要自己去开发一个搜索框,不需要担心要把搜索框放什么位置,也不需要担心搜索框影响您当前的界面.所有的这些工作都由SearchManager类来为您处理(以下简称"搜索管理器"),它管理的Android搜索对话框的整个生命周期,并执行您的应用程序将发送的搜索请求,返回相应的搜索关键字. 当用户执行一个搜索,搜索管理器将使用一个专门的Intent把搜索查询的关键字传给您在配置文件中配置的处理搜索结果的Activity.从本质上讲

  • Android pdf viewer在android studio应用问题说明详解

    之前一直是做.NET开发的,最近需要弄一个新闻app,能力有限,只能借助HTML5 WebAPP+android studio来完成这项工作. android studio主要用WebView来加载发布好的WebApp,打包生产APP. 其中由于显示一些pdf文档,所以研究了一下,记录一下心得,同时也希望帮助到新手们. android 显示网络pdf,基本原理:先将pdf文件通过DownloadManager下载到手机sdk某个文件夹中,然后通过android-pdf-viewer插件进行显示.

随机推荐