Gradle learning series (four): Gradle dependency

Overview

Started a new series, this series of learning Gradle, the goal is to thoroughly understand Gradle, mainly to make notes that you understand, to prevent forgetting

Gradle series (1): Groovy learning

Gradle learning series (two): Gradle core decryption

Gradle learning series (3): Gradle plugin

Gradle learning series (four): Gradle dependency

Introduction

In normal use, dependency is a hurdle that cannot be escaped. Compilation errors are always reported due to various reasons. Today we will understand the dependency and the solution of common problems.

Dependent type

Gradle dependencies are respectively 直接依赖,项目依赖,本地jar arr依赖,传递依赖, and the meaning of these dependencies are distinguished below

  • Direct dependency: The dependency imported directly in the project is the direct dependency
dependencies {
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    }
  • Transitive dependency: Project A depends on okhttp, and okhttp depends on okio. Finally, project A also depends on okio, which means that the dependency is transitive.

Local Libary module dependency

    implementation project(':mylibary')

This way of dependency is directly dependent on this project libary module, this libary moduleneeds to setting.gradlebe configured in

Local binary dependency

This mainly includes local jar file dependency, aar file dependency and local so file dependency

Local jar file dependency, generally including these two forms

//直接依赖某文件
implementation files('libs/foo.jar', 'libs/bar.jar')
//配置某文件夹作为依赖项
implementation fileTree(dir: 'libs', include: ['*.jar'])

Local arr file dependency, generally including these two forms

    //依赖单个arr文件
    implementation(name: 'facesdk', ext: 'aar')
    //依赖某个文件夹中的所有aar文件
    implementation fileTree(include: ['*.aar'], dir: 'libs')

The location of the arr folder needs to be set before use

// 声明本地 aar 文件地址
repositories {
	flatDir {
		dirs 'libs'
	}
}

so file dependency

The .so file is the same as the .java file. It will be viewed by Gradle as a local code resource. You only need to set the resource path of the so to get the so file.

Depends on the so file, generally there are two forms

  • Use the default file path of the android plugin to store the so file, so that android will find the so according to the default path, the default path is /src/main/jniLibs
  • The other is that we manually set the so file path location
// 设置 .so 资源路径
android{
   sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

Remote dependency

GradleThere is no remote warehouse of its own, so to add remote dependencies, you must declare which remote warehouse to use. Each Gradlescript needs to declare the warehouse. The first version is in the build.gradleconfiguration sub project-repository of the root directory.

allprojects {
    repositories {
        jcenter()

        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }

    }
}

Then you can remotely depend on the configuration

implementation 'com.example.android:app-magic:12.3'

The above is a shorthand, the full version is written as follows:

implementation group: 'com.example.android', name: 'app-magic', version: '12.3'

group name version Co-locating a remote warehouse, version is best to write a fixed version number to prevent problems in the build

The core of dependency management

Gradle dependency management relies on two classpaths:compileClasspath、runtimeClasspath

  • compileClasspath: Code and classes that can be used during compilation. When a component participates in compilation, Gradle will put it in compileClasspath

  • runtimeClasspath: Code and classes used at runtime, when a component participates in packaging, Gradle will put it in the runtimeClasspath

  • Compile time: the code is still in the writing stage, as long as it has not been compiled into a class, it is compile time

  • Runtime: When compiled into a class file, it is called runtime when it runs on the machine

  • The code and class library contained in compileClasspath are the class libraries we need to use when writing code. If there is no class library in it, we will not find the class when we write it.

  • RuntimeClasspath mainly includes the class libraries needed during app runtime. If there is no library included in this, then the class cannot be found during runtime and crash

  • Operators such as implementation and api are just different operation methods for dependent libraries. The core logic is compileClasspathwhether the library pulled from the remote is placed in the middle or runtimeClasspathis it still俩个都放

Dependent management configuration

The dependency configuration supported by the current Gradle version implementation、api、compileOnly、runtimeOnly 和 annotationProcessorhas been deprecated.compile、provided、apk、providedCompile

Below we use implementation and api to understand compileClasspathandruntimeClasspath

implementation

Dependencies will be added to the compilation path, and the dependencies will be packaged and output to aar/apk, but the dependencies will not be exposed to other moudles during compilation

比如:A implementation B B implementation C

  • In B, you can use the class library in C
  • In A, you cannot use the class library only given by C, but you can use the class library in B
  • This is because the implementationintroduced dependency will add C to the compileClasspathsum of B, and runtimeClasspathadd C to A'sruntimeClasspath
  • Because C does not join A's compileClasspath, A has no way to access the class library in C at compile time, and because C joins A's runtimeClasspath, A can access the C class library at runtime

api

The dependency will be added to the compilation path, and the dependency will be packaged and output to aar/apk. Unlike implementation, this dependency can be passed

For example: A implementation BB api C

  • In B, you can use the class library in C
  • In A, you can use the class library in B, or you can use the class library in C
  • This is because the dependency introduced by api will add C to the compileClasspathsum of B, and runtimeClasspathat the same time add C to the compileClasspathsum runtimeClasspathof A, so A can also access the class library in C at compile time

compileOnly

Dependencies are only used at compile time, not packaged into aar/apk and cannot be used at runtime

For example: A implementation BB compileOnly C

  • A cannot access the code of C, B can access C, and C will not be packaged in the apk

runtimeOnly

Cannot be used when relying on compilation, it will only be packaged into aar/apk runtime for use

For example: A implementation BB runtimeOnly C

  • AB can not call the code in C, but C will be packaged into APK

Depend on remote library

In fact, every component has its own compileClasspath 和 runtimeClasspath
each component involved when compiled, Gradle will put it compileClasspath in
every component involved in packaging, Gradle will put him in runtimeClasspath

So if you rely on a remote warehouse, how to decide to put compileClasspath 还是 runtimeClasspathit in?

In fact, when maven uploads a component, it will not only upload a binary file (such as aar), but also upload a pom.xml file, and the dependency information is in this file.

The following is a pom file, the picture comes from Gradle and Android build entry
, thank you for your output

image.png

pom file will have both a dependency, will be divided runtimeand compile, runtime compiler will not participate, will be involved in packaging, compile will be involved in compiling and packaging

Suppose A depends on B, and B depends on C

BC is a remote warehouse. The dependency on C in B's POM is runtime.
In Gradle 4.4, A can still call C code. This problem was fixed after Gradle 5.0

Dependency conflict

ABC is the original Module, D is a remote dependency, A depends on B, A depends on C, B depends on D 1.0 version, and C depends on D 1.1 version. At this time, D has a dependency conflict. It is necessary to determine whether to use D version 1.0 or 1.1 version

How to resolve dependency conflicts

  • When compiling, B relies on version 1.0 of D when compiling, and C depends on version 1.1 of D when compiling, but the 1.1 version of D is finally packaged into the APK. This is because the version number conflicts and the latest version is selected.
  • Gradle also provides us with a series of methods for resolving dependency conflicts as follows: dependency transfer is not allowed, exclude removes a dependency, and force the use of a certain version

Mandatory use of a dependent version

isForce

isForce means to force the use of this version of the dependency

dependencies {
    implementation('org.hibernate:hibernate:3.1') {
        //在版本冲突的情况下优先使用3.1版本
        isForce = true
    }
}

strictly

Strictly is a kind of strong version constraint, you can use (!!) shorthand

dependencies {
    implementation("io.reactivex.rxjava2:rxjava:2.2.0!!") 
    implementation("io.reactivex.rxjava2:rxjava") {
        version {
            strictly("2.2.0")
        }
    }
}

exclude removes a dependency

Gradle provides an exclude setting in the implementation{...}, which can be set to ignore the specified dependencies, and the ignored dependencies are regarded as never dependent. According to the current situation of my testing, this only applies to remote dependencies.

 dependencies {
   implementation('org.hibernate:hibernate:3.1') {
     //排除特定的依赖
     exclude module: 'cglib' //by artifact name
     exclude group: 'org.jmock' //by group
     exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
   }
 }

We can use group or module, or group and module together as the basis for exclusion

The following is the meaning of group and module

implementation("org.hibernate:hibernate:3.1")

group = org.hibernate
module = hibernate
version = 3.1

Dependency passing is not allowed

 dependencies {
   implementation('org.hibernate:hibernate:3.1') {

     //禁用依赖传递
     // 传递依赖:A => B => C ,B 中使用到了 C 中的依赖,
     // 且 A 依赖于 B,如果打开传递依赖,则 A 能使用到 B 
     // 中所使用的 C 中的依赖,
     //默认都是打开,即 true
     transitive = false
   }
 }

jar conflict

If the app references an aar, there is a xx.jar in arr, and the app references this xx.jar again, at this time, you need to use compileOnly instead of implementation for the operator that references the jar in aar

reference

Gradle Crawling Guide-Dependency Management

Getting started with Gradle and Android build

Guess you like

Origin blog.csdn.net/qq_34760508/article/details/115007795
Recommended