Gradle统一管理依赖

news/2024/5/20 1:39:16 标签: android, gradle

背景

随着项目越来越大,module 越来越多,依赖的库也越来越多,依赖管理也越来越混乱。
我们一般会有以下需求:
1.  项目依赖统一管理,在单独文件中配置
2.  不同 Module 中的依赖版本号统一

管理 Gradle 依赖

说明:下面所有示例都是基于 Gradle 7.3  版本,AGP 7.3.0 版本

一、原始粗暴式

在 module 的 build.gradle 中直接引入,就像下面代码一样

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 33
    defaultConfig {
        applicationId "com.example.gradle"
        minSdk 21
        targetSdk 33
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.9.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

优点:方便快捷,依赖的时候复制粘贴一气呵成

缺点:多模块中可能会存在不同版本的依赖,进行版本升级的时候改动非常麻烦。

二、ext 式

Gradle 提供了 ext 关键字可以让我们去定义自身所需要的扩展属性,我们可以通过 ext 关键字对我们工程中的依赖进行全局配置。

1. 直接在 project 的 build.gradle 中编写 ext 。

ext {
    versions = [
            compileSdk      : 33,
            minSdk          : 21,
            targetSdk       : 33,
            versionCode     : 1,
            versionName     : "1.0.0",

            core_ktx        : "1.9.0",
            appcompat       : "1.6.1",
            material        : "1.6.1",
            constraintlayout: "2.1.4"
    ]

    libraries = [
            core_ktx        : "androidx.core:core-ktx:${versions.core_ktx}",
            appcompat       : "androidx.appcompat:appcompat:${versions.appcompat}",
            material        : "com.google.android.material:material:${versions.material}",
            constraintlayout: "androidx.constraintlayout:constraintlayout:${versions.constraintlayout}"
    ]
}

在 module 的 build.gradle 中的使用如下 

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk versions.compileSdk
    defaultConfig {
        applicationId "com.example.gradle"
        minSdk versions.minSdk
        targetSdk versions.targetSdk
        versionCode versions.versionCode
        versionName versions.versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation libraries.core_ktx
    implementation libraries.appcompat
    implementation libraries.material
    implementation libraries.constraintlayout
}

这样,所有的 module 需要更新依赖库版本的时候,去修改 ext 下的代码即可

2. 在另一个 gradle 脚本中进行编写 ext

随着依赖项越来越多,ext 中的代码也越来越庞大,为了更好地管理。我们会把代码写在一个 .gradle ( config.gradle )文件中。

 config.gradle 中的代码如下

ext {
    versions = [
            compileSdk      : 33,
            minSdk          : 21,
            targetSdk       : 33,
            versionCode     : 1,
            versionName     : "1.0.0",

            core_ktx        : "1.9.0",
            appcompat       : "1.6.1",
            material        : "1.6.1",
            constraintlayout: "2.1.4"
    ]

    libraries = [
            core_ktx        : "androidx.core:core-ktx:${versions.core_ktx}",
            appcompat       : "androidx.appcompat:appcompat:${versions.appcompat}",
            material        : "com.google.android.material:material:${versions.material}",
            constraintlayout: "androidx.constraintlayout:constraintlayout:${versions.constraintlayout}"
    ]
}

在 project 的 build.gradle 中的中引用 config.gradle 文件,方式如下图:

在 module 的 build.gradle 中的使用不变

优点:依赖的版本统一管理,版本升级只用修改config.gradle 文件中的 ext 属性。

缺点: 在 module 的 build.gradle 中使用时,不支持代码提醒,不支持点击跳转,多 moudle 开发时,不同 module 的依赖需要 ctrl+c/v 导致开发的效率降低

三、kotlin+buildSrc式

ext 可以帮我们很好地解决了管理依赖的问题,美中不足的是它不支持点击跳转、自动补全的问题。这就轮到 buildSrc 大显身手了。

运行 gradle 时,它首先会检查项目中是否存在一个叫 buildSrc 的目录,如果有的话,gradle 会自动编译并测试这段代码,并将其放入构建脚本的类路径中。

  1. 在 project 的根目录下创建 buildSrc 目录

  2. 在 buildSrc 中新建 build.gradle 文件

    apply plugin: 'kotlin'
    
    buildscript {
        // 这里保持与主工程版本一致
        ext.kotlin_version = '1.7.20'
        repositories {
            mavenCentral()
            google()
        }
        dependencies {
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        }
    }
    
    repositories {
        mavenCentral()
        google()
    }
  3. 在 buildSrc 中创建 /src/main/kotlin目录,然后在新建 com.gradle 包名,最后创建 Dependencies.kt 文件

     4. Dependencies.kt 中编写依赖管理的代码,如下

object Versions {
    const val compileSdk = 33
    const val minSdk = 21
    const val targetSdk = 33
    const val versionCode = 1
    const val versionName = "1.0.0"

    const val core_ktx = "1.9.0"
    const val appcompat = "1.6.1"
    const val material = "1.6.1"
    const val constraintlayout = "2.1.4"
}

object Libraries {
    const val core_ktx = "androidx.core:core-ktx:${Versions.core_ktx}"
    const val appcompat = "androidx.appcompat:appcompat:${Versions.appcompat}"
    const val material = "com.google.android.material:material:${Versions.material}"
    const val constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}"
}

     5. 在 module 的 build.gradle 中使用如下 

import com.gradle.Libraries
import com.gradle.Versions

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk Versions.compileSdk
    defaultConfig {
        applicationId "com.example.gradle"
        minSdk Versions.minSdk
        targetSdk Versions.targetSdk
        versionCode Versions.versionCode
        versionName Versions.versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation Libraries.core_ktx
    implementation Libraries.appcompat
    implementation Libraries.material
    implementation Libraries.constraintlayout
}

 使用时 Android Stuido 自动提示如下

优点:这种方式支持 IDE 输入代码会有提示,会自动完成,并且支持 AndroidStudio 单击跳转。

缺点:依赖更新将重新构建整个项目,对编译速度有一定的影响。而且 buildSrc 是编译期才生效,并且其生命周期在project 的 build.gadle 执行之后,所以没办法把插件相关的配置给维护起来。

四、Verison Catalogs 管理

4.1 Version Catalogs 特点

  • 对所有 module 可见,可统一管理所有 module 的依赖,Gradle 会为每个依赖目录生成一个类型安全的访问器,同时可以管理 project 的 build.gradle 中的插件依赖。

  • 依赖项除了可以声明为单个依赖目录,还可以将多个依赖项声明为依赖目录组。即支持声明依赖bundles, 即总是一起使用的依赖可以组合在一起,

  • 支持版本号与依赖名分离,可以在多个依赖间共享版本号

  • 支持在单独的 libs.versions.toml 文件中配置依赖

  • 支持在项目间共享依赖

4.2 启用 Version Catalogs

在 Gradle 低版本中, Version Catalogs 属于孵化中的特效,使用它之前需要启用该特性。

在 settings.gradle 中添加如下代码:

pluginManagement {
    ...
}

enableFeaturePreview("VERSION_CATALOGS")

dependencyResolutionManagement {
   ...
}

...

4.3 使用 Version Catalogs

在 settings.gradle 中声明,如下:

...
dependencyResolutionManagement {
    ...
    // 编写版本目录的依赖库
    versionCatalogs {
        libs {
            // 版本
            version('compileSdk', '33')
            version('minSdk', '21')
            version('targetSdk', '33')
            version('versionCode', '1')
            version('versionName', '1.0.0')

            /**
             * 声明依赖
             * 例如:别名('coreKtx')、groupId('androidx.core')、artifactId('core-ktx')以及版本('1.9.0')
             * alias 在AGP的低版本中使用,高版本中使用 library
             */
            // alias('coreKtx').to('androidx.core', 'core-ktx').version('1.9.0')
            library('coreKtx', 'androidx.core', 'core-ktx').version('1.9.0')
            library('appcompat', 'androidx.appcompat', 'appcompat').version('1.6.1')
            library('material', 'com.google.android.material', 'material').version('1.6.1')
            library('constraintlayout', 'androidx.constraintlayout', 'constraintlayout').version('2.1.4')


            // 除了单个依赖声明,我们也可以将多个依赖项声明为一个依赖组
            bundle('appBaseLib', ['coreKtx', 'appcompat', 'material', 'constraintlayout'])

            // 针对多个相同版本号的依赖,我们可以定一个通用版本号,即将依赖与版本单独声明并引用
            version('lifecycle', '2.2.0')
            library('lifecycleExtensions', 'androidx.lifecycle', 'lifecycle-extensions').versionRef('lifecycle')
            library('lifecycleRuntimeKtx', 'androidx.lifecycle', 'lifecycle-runtime-ktx').versionRef('lifecycle')

            /**
             * 声明插件(在高版本的 Gradle 中才有)
             */
            plugin('androidApplication', 'com.android.application').version('7.3.0')
            plugin('kotlinAndroid', 'org.jetbrains.kotlin.android').version('1.7.20')
        }
    }
}

...

在 project 的 build.gradle 中的使用如下

plugins {
//    id 'com.android.application' version '7.3.0' apply false
//    id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
    /* 依赖插件 等同于上面注释掉的代码 */
    alias(libs.plugins.androidApplication) apply false
    alias(libs.plugins.kotlinAndroid) apply false
}

在 module 的 build.gradle 中的使用如下

plugins {
//    id 'com.android.application'
//    id 'org.jetbrains.kotlin.android'
    /* 依赖插件 等同于上面注释掉的代码 */
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.kotlinAndroid)
}

android {
    compileSdk libs.versions.compileSdk.get().toInteger()
    defaultConfig {
        applicationId "com.example.gradle"
        minSdk libs.versions.minSdk.get().toInteger()
        targetSdk libs.versions.targetSdk.get().toInteger()
        versionCode libs.versions.versionCode.get().toInteger()
        versionName libs.versions.versionName.get()
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    // 依赖单个指定的版本
//    implementation libs.coreKtx
//    implementation libs.appcompat
//    implementation libs.material
//    implementation libs.constraintlayout

    // 依赖项包
    implementation libs.bundles.appBaseLib
  
    implementation libs.lifecycleExtensions
    implementation libs.lifecycleRuntimeKtx

}

这种方式支持 IDE 输入代码会有提示,会自动完成,并且支持 AndroidStudio 单击跳转。但是这种方式会导致 settings.gradle 非常臃肿

通过 toml 文件声明 version catalogs

除了在 settings.gradle 文件中直接声明依赖目录,官方更推荐使用 toml 文件来声明依赖目录,而且在 toml 中编写代码时 Android Studio 会有提示,非常的方便。

首先在项目根目录下创建 libs.versions.toml 文件,文件名可以任意取,并编写如下依赖内容:

[versions]
agp = "7.3.0"
kotlin = "1.7.20"
compileSdk = "33"
minSdk = "21"
targetSdk = "33"
versionCode = "1"
versionName = "1.0.0"

coreKtx = "1.9.0"
appcompat = "1.6.1"
material = "1.6.1"
constraintlayout = "2.1.4"
lifecycle = "2.2.0"

[libraries]
coreKtx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
material = { module = "com.google.android.material:material", version.ref = "material" }
constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
lifecycleExtensions = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "lifecycle" }
lifecycleRuntimeKtx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }

[bundles]
appBaseLib = ["coreKtx", "appcompat", "material", "constraintlayout"]

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

toml 文件的使用说明

1. toml 文件由 4个主要部分组成

[versions] 用于声明可以被依赖项引用的版本

[libraries] 用于声明依赖的别名

[bundles] 用于声明依赖包(依赖组)

[plugins] 用于声明插件(Gradle 低版本不支持)

2. 声明 libraries 时,可以使用

coreKtx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }

或者

coreKtx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }

随后在 setting.gradle 中引用该 toml 文件

...
dependencyResolutionManagement {
    ...
    // 编写版本目录的依赖库
    versionCatalogs {
        libs {
            from(files("./libs.versions.toml"))
        }
    }
}

...

在 module 的 build.gradle 中的使用方式不变。

注意:Version Catalogs 中变量命名大小写敏感,且以小写字母开头, 命名中可以如包含 “-” 或者 “_” 或者 “.” ,在相当于分组了。

举例说明:

lifecycle_runtime_ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }

在使用时

implementation libs.lifecycle.runtime.ktx

4.4 发布到远端

如果你没有共享依赖的需求,那么上面的方式已经足够使用了。

但是现在基本上都是组件化开发了,特别是当组件数量比较多或者公司内有其他 App 时,大概率就会有统一依赖版本以及共享依赖的需求了。那我们可以把 Version Catalog 发布到远端,其他项目需要时直接依赖然后使用即可,这样就很方便的实现了版本的统一以及快速依赖了。毕竟拷贝来拷贝去非常麻烦且不好维护。

Version Catalog发布也比较简单,按照 官方文档 来即可。

总结

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


http://www.niftyadmin.cn/n/5392030.html

相关文章

springsecurity+vue前后端分离适配cas认证的跨域问题

0. cas服务搭建参考:CAS 5.3服务器搭建_cas-overlay-CSDN博客 1. 参照springsecurity适配cas的方式, 一直失败, 无奈关闭springssecurity认证 2. 后端服务适配cas: 参考前后端分离项目(springbootvue)接入单点登录cas_前后端分离做cas单点登录-CSDN博客 1) 引入maven依赖 …

【Python笔记-设计模式】前端控制器模式

一、说明 常作为MVC(Model-View-Controller)模式的一部分,用来处理用户请求并将其分发给相应的处理程序(即路由匹配)。 (一) 解决问题 将请求的处理流程集中管理,统一处理所有的请求 (二) 使用场景 需…

PyTorch深度学习实战(37)——CycleGAN详解与实现

PyTorch深度学习实战(37)——CycleGAN详解与实现 0. 前言1. CycleGAN 基本原理2. CycleGAN 模型分析3. 实现 CycleGAN小结系列链接 0. 前言 CycleGAN 是一种用于图像转换的生成对抗网络(Generative Adversarial Network, GAN),可以在不需要配…

ChatGPT国内快速上手指南

ChatGPT简介 ChatGPT是由OpenAI团队研发的自然语言处理模型,该模型在大量的互联网文本数据上进行了预训练,使其具备了深刻的语言理解和生成能力。 GPT拥有上亿个参数,这使得ChatGPT在处理各种语言任务时表现卓越。它的训练使得模型能够理解上…

如何理解三大微分中值定理

文章看原文,自己写的只是备份 高等数学强化2:一元函数微分学 中值定理 极值点 拐点_一元函数中值定理-CSDN博客 高等数学强化3:一元函数积分学 P积分-CSDN博客 高等数学强化3:定积分几何应用-CSDN博客

【办公类-22-08】周计划系列(4)“育儿知识(家园小报)“ (2024年调整版本)

作品展示 背景需求: 制作“育儿知识(家园小报)”,查询发现去年就没有做 因为“家园小报”基本没有段落文字,都是“文本框文字、艺术字“,很难用python提取文字。 由于只有6篇,因此去年采用的就…

五种多目标优化算法(MOFA、NSWOA、MOJS、MOAHA、MOPSO)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解流程通常包括以下几个步骤: 1. 定义问题:首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数,这些目标函数可能…

sql-函数

函数:一段可以直接被另一段程序调用的程序或代码。 字符串函数 函数功能CONCAT(s1, s2, …, sn)字符串拼接,将s1, s2, …, sn拼接成一个字符串LOWER(str)将字符串全部转为小写UPPER(str)将字符串全部转为大写LPAD(str, n, pad)左填充,用字符…