Android:Gradle 依赖相关

  • Post author:
  • Post category:其他


一:依赖配置

目前 Gradle 版本支持的依赖配置有:implementation、api、compileOnly、runtimeOnly 和 annotationProcessor

1)implementation:会将依赖打包到输出(aar或apk),在编译时不会将依赖的实现暴露给其他module,也就是只有在运行时其他module才能访问这个依赖中的实现。

2)api :会将依赖打包到输出(aar 或apk),这个依赖可以传递,其他 module 无论在编译时和运行时都可以访问这个依赖的实现。

举个例子,A 依赖 B,B 依赖 C,如果都是使用 api 配置的话,A 可以直接使用 C 中的类(编译时和运行时)。而如果是使用 implementation 配置的话,在编译时,A 无法访问 C 中的类。

3)compileOnly :编译时使用,不会打包到输出(aar 或 apk)。这可以减少输出的体积,在只在编译时需要,在运行时可选的情况,很有用。

4)runtimeOnly :只在生成apk的时候参与打包,编译时不会参与,很少用

5)annotationProcessor :用于注解处理器的依赖配置。



依赖类型

1)本地源码依赖 : implementation project(“:mylibrary”)

2)本地libs目录jar包等依赖 : implementation fileTree(dir: ‘libs’, include: [‘*.jar’])

3)远程Maven仓库等依赖 : implementation ‘com.example.android:app-magic:12.3’



查看依赖关系

1)./gradlew (moudle 名称):dependencies

2) 通过as 提供的工具 :

依次选择:view > Tool Windows > Gradle

依次展开:appName > Tasks > android > androidDependencies 。gradle执行该任务后,系统会打印依赖关系

二:解决Gradle的依赖冲突

1)force 强制使用某个版本的库

force : force = true 强制使用某个版本。出现冲突时,优先使用该版本解决。

2)transitive 关闭依赖传递

transitive : 是否传递本身的依赖给宿主程序(使用传递依赖时,Gradle 会将传递依赖一起下载下来。 默认是开启传递依赖

transitive = true,依赖同于没有使用 exclude 排除依赖 ,每个包的依赖项都会被递归分析并添加进来。

transitive = false,则依赖关系同于用 exclude 排除依赖。

3)exclude 排除某项库

三:统一管理版本号

如果通过相同的方式引入不同版本的依赖库,默认会选择最新版本,不同的方式引入则会产生依赖冲突。


方案1

:在根目录下的build.gradle文件下添加 ext{ …. }

ext{
   //dependencies
   supportLibraryVersion ='26.1.0'
   gsonVersion = '2.8.0'
}


方案2

:使用自定义gradle

第一步:我们在项目根目录下创建一个任意命名的xxx.gradle文件. 例如 : config.gradle

ext {
        android = [
                compileSdkVersion: 26,
                buildToolsVersion: "25.0.0",
                minSdkVersion    : 14,
                targetSdkVersion : 22,
                versionCode      : 17,
                versionName      : "1.7",
                applicationId    : "com.ml.xx",
        ]

        dependencies = [
                appcompatv7: "com.android.support:design:22.2.0",
                loadtoast: "net.steamcrafted:load-toast:1.0.6",
                constraintlayout: "com.android.support.constraint:constraint-layout:1.0.2"
        ]
    }

第二步:在 根目录下的build.gradle于引用当前gradle:

apply from : “config.gradle”

第三步:在app下的build.gradle先定义出引用:

def cfg = rootProject.ext.android
def dpc = rootProject.ext.dependencies

完整代码:

def cfg = rootProject.ext.android
def dpc = rootProject.ext.dependencies
android {
     compileSdkVersion cfg.compileSdkVersion
     buildToolsVersion cfg.buildToolsVersion
      ...
}

四:dependencies 依赖分析

先来谈谈符号,它们的目的仅用于格式化:

+- – – : 是依赖分支库的开始。

|  : 标识还是在之前的依赖库中的依赖,显示它依赖的库。

\- – – : 是依赖库的末尾。

* : 在依赖库的末尾,意味着该库的进一步依赖关系不会显示,因为它们已经列在其他某个子依赖树中。

-> : 如果 Gradle 发现多个依赖库都依赖到同一个库但是不同版本,那么它必须做出选择。毕竟包含同一个库的不同版本是没有意义的。在这种情况下,Gradle 默认选择该库的最新版本。

五:依赖冲突三类

在引用依赖时经常会有这样的问题:某些间接引用的依赖项是不需要的;产生了依赖冲突。此时需要排除一些依赖。



排除依赖的方式:


1)

在dependency中排除 : 这种方式是粒度最细的,也是最为繁琐的。此时可以考虑全局设置。

dependencies {
   compile('com.malei:xxx:1.0') {
      exclude module: 'cglib' //by artifact name
      exclude group: 'org.jmock' //by group
      exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
   }
}


2)

在全局配置中排除

configurations {
   compile.exclude module: 'cglib'
   all*.exclude group:'org.unwanted', module: 'iAmBuggy'
}



禁用传递依赖方式:


1)

在dependency中禁用

compile('com.malei:xxx:1.0') {
   transitive = false
}


2)

在全局配置中禁用

configurations.all {
   transitive = false
}


3)

使用@jar : 在单个依赖项中使用@jar标识符忽略传递依赖

compile 'com.zhyea:ar4j:1.0@jar'



强制使用版本方式:

如果某个依赖项是必需的,而又存在依赖冲突时,此时没必要逐个进行排除,可以使用force属性标识需要进行依赖统一

1)在dependency强制使用版本

compile('com.malei:xxx:1.0') {
   force = true
}

2)在全局配置中强制使用版本

configurations.all {
   resolutionStrategy {
      force 'org.hamcrest:hamcrest-core:1.3'
   }
}

实践:

1)

implementation (‘com.alibaba:arouter-api:1.3.1’)

依赖关系:

\--- com.alibaba:arouter-api:1.3.1
     +--- com.alibaba:arouter-annotation:1.0.4
     \--- androidx.legacy:legacy-support-v4:1.0.0
          +--- androidx.core:core:1.0.0 -> 1.3.1 (*)   
          |    |    \--- androidx.core:core:1.0.0 -> 1.3.1 (*)
          |    \--- androidx.cursoradapter:cursoradapter:1.0.0 (*)
          \--- androidx.fragment:fragment:1.0.0 -> 1.1.0 (*)

2)

添加 exclude


implementation (‘com.alibaba:arouter-api:1.3.1’) {


exclude module : ‘fragment’

}

结论:我们发现androidx.fragment:fragment 包没有了

\--- com.alibaba:arouter-api:1.3.1
     +--- com.alibaba:arouter-annotation:1.0.4
     \--- androidx.legacy:legacy-support-v4:1.0.0          
          \--- androidx.legacy:legacy-support-core-ui:1.0.0
               |    \--- androidx.core:core:1.0.0 -> 1.3.1 (*)
               \--- androidx.cursoradapter:cursoradapter:1.0.0 (*)、


3)

添加 transitive

transitive : 依赖传递特性,使用的时候,通常设置为 false 。即关闭依赖传递

例如项目中不希望 recyclerview 使用它所依赖的库 :

结论:transitive默认就是true

 implementation ('com.alibaba:arouter-api:1.3.1') {
        transitive = true
}

依赖图:
\--- com.alibaba:arouter-api:1.3.1
     +--- com.alibaba:arouter-annotation:1.0.4
     \--- androidx.legacy:legacy-support-v4:1.0.0
          +--- androidx.core:core:1.0.0 -> 1.3.1 (*)   
          |    |    \--- androidx.core:core:1.0.0 -> 1.3.1 (*)
          |    \--- androidx.cursoradapter:cursoradapter:1.0.0 (*)
          \--- androidx.fragment:fragment:1.0.0 -> 1.1.0 (*)



 implementation ('com.alibaba:arouter-api:1.3.1') {
        transitive = false  //transitive为false表示单独依赖,true为默认树状依赖
    }
依赖图

+--- project :router_core
\--- com.alibaba:arouter-api:1.3.1 //下面没有任何的依赖了

4)

force : 强制指定依赖版本

先看没有添加前的依赖图:

|    |    +--- androidx.fragment:fragment:1.3.4
|    |    |    +--- androidx.annotation:annotation:1.1.0 -> 1.2.0
|    |    |    +--- androidx.core:core:1.2.0 -> 1.5.0 (*)
|    |    |    +--- androidx.collection:collection:1.1.0 (*)
|    |    |    +--- androidx.viewpager:viewpager:1.0.0
|    |    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.2.0
|    |    |    |    +--- androidx.core:core:1.0.0 -> 1.5.0 (*)
|    |    |    |    \--- androidx.customview:customview:1.0.0
|    |    |    |         +--- androidx.annotation:annotation:1.0.0 -> 1.2.0
|    |    |    |         \--- androidx.core:core:1.0.0 -> 1.5.0 (*)

添加如下:

implementation (‘androidx.core:core:1.6.0’){


force=true

}

或者:

configurations.all {


resolutionStrategy {


force ‘androidx.core:core:1.6.0’

}

}

结论:所有的都变成了1.6.0版本了

查看依赖图:

|    |    +--- androidx.fragment:fragment:1.3.4
|    |    |    +--- androidx.core:core:1.2.0 -> 1.6.0 (*)
|    |    |    +--- androidx.viewpager:viewpager:1.0.0
|    |    |    |    +--- androidx.core:core:1.0.0 -> 1.6.0 (*)
|    |    |    |    \--- androidx.customview:customview:1.0.0
|    |    |    |         +--- androidx.annotation:annotation:1.0.0 -> 1.2.0
|    |    |    |         \--- androidx.core:core:1.0.0 -> 1.6.0 (*)
|    |    |    +--- androidx.loader:loader:1.0.0
|    |    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.2.0
|    |    |    |    +--- androidx.core:core:1.0.0 -> 1.6.0 (*)


5)

删除项目里所有的 androidx.core:core 依赖


configurations {


all*.exclude group: ‘androidx.core’, module: ‘core’

}

|    |    +--- androidx.fragment:fragment:1.3.4
|    |    |    +--- androidx.annotation:annotation:1.1.0 -> 1.2.0
|    |    |    +--- androidx.collection:collection:1.1.0 (*)

问题:

1)项目中多个模块依赖同一个依赖 D 的不同版本,如何保持每个模块直接使用自己本身 compile 的依赖版本呢?


app moduel 中的gradle依赖:


implementation ‘com.squareup.okhttp3:okhttp:3.6.0’


bbs module 中的gradle依赖:


implementation ‘com.squareup.okhttp3:okhttp:3.14.7’


然后我们依次看依赖情况:

MacBook-Pro:ComicFlutter malei$  ./gradlew :app:dependencies –configuration releaseCompileClasspath

> Task :app:dependencies

————————————————————

Project :app

————————————————————

+— com.squareup.okhttp3:okhttp:3.6.0 -> 3.14.7  //我们发现版本号已经被修改了

|    \— com.squareup.okio:okio:1.17.2

+— androidx.appcompat:appcompat:{strictly 1.3.0} -> 1.3.0 (c)

MacBook-Pro:ComicFlutter malei$ ./gradlew bbs:dependencies –configuration releaseCompileClasspath

> Task :app:dependencies

————————————————————

Project :bbs

————————————————————

+— com.squareup.okhttp3:okhttp:3.14.7

|    \— com.squareup.okio:okio:1.17.2

+— androidx.appcompat:appcompat:{strictly 1.3.0} -> 1.3.0 (c)

通过依赖树,我们发现 okhttp的依赖版本都变成了3.14.7 。 现在我们想要保持每个模块直接使用自己本身 compile 的依赖版本,该如何处理?

app.gradle中添加:

configurations.all {
    // 遍历所有的依赖,根据 moduleName 使用对应的版本。确实可行
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        System.out.println("MALEI: 打印 group : " + requested.group);
        System.out.println("MALEI: 打印 name : " + requested.name);
        if (requested.group == 'com.squareup.okhttp3') {
            if (requested.name.startsWith("app")) {
                details.useVersion '3.6.0'
            } else if (requested.name.startsWith("bbs")) {
                details.useVersion '3.14.7'
            } else {
                details.useVersion '3.6.0'
            }
        }
    }
}

然后我们在看下结果:

MacBook-Pro:ComicFlutter malei$ ./gradlew :app:dependencies –configuration releaseCompileClasspath

————————————————————

Project :app

————————————————————

+— com.squareup.okhttp3:okhttp:3.6.0  //版本号保持了

|    \— com.squareup.okio:okio:1.11.0

MacBook-Pro:ComicFlutter malei$ ./gradlew :bbs:dependencies –configuration releaseCompileClasspath

————————————————————

Project :bbs

————————————————————

+— com.squareup.okhttp3:okhttp:3.14.7

|    \— com.squareup.okio:okio:1.17.2

2)本地 jar 依赖和 本地 aar 依赖区别。

jar 文件只包含编译好的 .class 文件和清单文件,不包含资源文件。所以如果没有 res 资源文件,可以在打包时,将 packaging 配置为 jar 格式;

aar 文件包含 class 以及 /res 目录下的所有资源文件。



版权声明:本文为BunnyCoffer原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。