An overview of the

I have started a new series on Gradle. The goal of this series is to understand Gradle thoroughly, mainly by taking notes of my own understanding so that I don’t forget

Gradle series 1: Learning Groovy

Gradle Core Decryption

Gradle plugins

Gradle dependencies

Introduction to the

In the usual use of dependency is an unavoidable obstacle, always because of a variety of reasons lead to compiler error, today we will have a good understanding of dependency, as well as the solution of common problems

Depend on the type

Gradle dependencies are direct dependencies, project dependencies, local JAR arr dependencies, and transitive dependencies

  • Direct dependencies: Dependencies imported directly into a project are called direct dependencies
dependencies {
    implementation 'androidx. Constraintlayout: constraintlayout: 1.1.3'
    }
Copy the code
  • Transitive dependencies: Project A relies on OKHTTP, which in turn relies on OKIO, which in turn relies on OKIO, meaning that dependencies are transitive

Local Libary module dependency

    implementation project(':mylibary')
Copy the code

This dependency depends directly on the libary module of this project, which needs to be configured in setting.gradle

Local binary dependencies

This includes local JAR file dependencies, AAR file dependencies, and local SO file dependencies

Local JAR file dependencies generally include both of these forms

Implementation files('libs/foo.jar', 'libs/bar.jar'); implementation fileTree(dir: 'libs', include: ['*.jar'])Copy the code

Local ARR file dependencies generally include both of these forms

    // Rely on a single ARR file
    implementation(name: 'facesdk', ext: 'aar')
    // Depends on all aar files in a folder
    implementation fileTree(include: ['*.aar'], dir: 'libs')
Copy the code

You need to set the location of the ARR folder before using it

// Declare the local AAR file address
repositories {
	flatDir {
		dirs 'libs'}}Copy the code

So file dependency

.so files, like.java files, are treated as local code resources by Gradle. You only need to set the resource path to get the so files

Depending on the SO file, there are generally two forms

  • Use the default path of the Android plugin to store the so file, so android will find the default path of so, the default path is/SRC /main/jniLibs
  • The other is that we manually set the so file path location
// Set the.so resource path
android{
   sourceSets {
        main {
            jniLibs.srcDirs = ['libs']}}}Copy the code

Long-range dependence

Gradle does not have its own remote repository, so to add a remote dependency to declare which remote repository to use, each Gradle script needs to declare the repository

allprojects {
    repositories {
        jcenter()

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

Then you can configure remote dependencies

implementation 'com. The example. The android: app - magic: 12.3'
Copy the code

The full version is as follows:

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

Group name Version Co-locate a remote repository. It is best to write a fixed version number for version in case of build problems

The heart of dependency management

Gradle dependency management relies on two classpath compileClasspath and runtimeClasspath

  • CompileClasspath: code and classes that can be used at compile. when a component is compiled, Gradle puts it in compileClasspath

  • RuntimeClasspath: Code and classes used at runtime. When a component participates in packaging, Gradle places it in runtimeClasspath

  • Compile time: The code is still being written, so it is compile time if it has not been compiled to class

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

  • CompileClasspath contains the code and libraries you need to use when writing code. If you don’t have one, you won’t find the class

  • RuntimeClasspath contains the library required by the app runtime. If the library does not contain the library, the runtime will not find the class and crash

  • The implementation and API operators are just different ways of handling dependent libraries. The logic at the heart of this is whether a library pulled from a remote can be put into compileClasspath or runtimeClasspath or both

Dependency Management Configuration

Gradle versions currently support dependency configurations implementation, API, compileOnly, runtimeOnly and compileOnly AnnotationProcessor deprecates compile, Provided, APK, and providedCompile

Now let’s use implementation and API to understand compileClasspath and runtimeClasspath

implementation

Dependencies are added to the compile path and are packaged and output to AAR/APK, but are not exposed to other moudles at compile time

For example: A implementation B B implementation C

  • In B, you can use the C class library
  • In A, you cannot use the library given only by C, but you can use the library in B
  • This is becauseimplementationIntroducing a dependency that will add C to BcompileClasspathandruntimeClasspathWill add C to AruntimeClasspath
  • C doesn’t add to A’s compileClasspath, so A can’t access C’s libraries at compile time, and C adds to A’s runtimeClasspath, so A can access C’s libraries at runtime

api

Dependencies are added to the compile path and are packaged and output to AAR/APK. Unlike implementation, this dependency can be passed

For example: A implementation B API C

  • In B, you can use the C class library
  • In A, you can use either the B library or the C library
  • That’s because the API introduces a dependency that adds C to BcompileClasspathandruntimeClasspathI’m going to add C to AcompileClasspathandruntimeClasspath, so A can also access C class libraries at compile time

compileOnly

Dependencies are only used at compile time and are not packaged into the AAR/APK runtime

For example, A implementation B B compileOnly C

  • A can’t access C code, B can access C, and C is not packaged into APK

runtimeOnly

Dependencies are not available at compile time and are packaged for use by the AAR/APK runtime

For example: A implementation B B runtimeOnly C

  • Neither AB can call C code, but C is packaged into APK

Relying on remote libraries

Every component has its own compileClasspath and runtimeClasspath and Gradle puts it in compileClasspath and every component in compileClasspath, Gradle puts it in runtimeClasspath

How do you decide whether to put it into compileClasspath or runtimeClasspath if you rely on a remote repository?

In fact, when Maven uploads a component, not only does it upload a binary file (such as aar), but it also uploads a pop.xml file that contains the dependency information.

Here is a POM file from Gradle and Android building primer. Thank you for your output

There will be two dependency files in the POM file, which will also be divided into Runtime and compile. Runtime will not compile, compile will package, compile will compile and package

Suppose A depends on B, and B depends on C

In Gradle 4.4, A can still call C code. This problem was fixed after Gradle 5.0

Rely on the conflict

A depends on B, A depends on C, B depends on VERSION D 1.0, and C depends on version D 1.1. At this time, dependency conflict occurs in D, and we need to determine whether to use version 1.0 or 1.1 of D

How can dependency conflicts be resolved

  • When compiling, B relies on version 1.0 of D while C relies on version 1.1 of D. However, it is version 1.1 of D that is packaged into APK eventually. This is because of the conflict of version numbers, so the latest version is selected
  • Gradle also provides a number of ways to resolve dependency conflicts: disallow dependency passing, exclude a dependency, and enforce the use of a version

Enforce the use of a dependent version

isForce

IsForce specifies the dependency that forces the use of this version

dependencies {
    implementation('3.1' org. Hibernate: hibernate.) {
        // Version 3.1 is preferred in case of version conflicts
        isForce = true}}Copy the code

strictly

Strictly is a strong version of the constraint that can be used (!!) shorthand

dependencies {
    implementation("IO. Reactivex. Rxjava2: rxjava: 2.2.0!!") 
    implementation("io.reactivex.rxjava2:rxjava") {
        version {
            strictly("2.2.0")}}}Copy the code

Exclude removes a dependency

In implementation in Gradle {… } provides a exclude setting that allows you to ignore specified dependencies. Ignored dependencies are treated as if they never existed. In my tests so far, this only applies to remote dependencies

 dependencies {
   implementation('3.1' org. Hibernate: hibernate.) {
     // Exclude specific dependencies
     exclude module: 'cglib' //by artifact name
     exclude group: 'org.jmock' //by group
     exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group}}Copy the code

We can exclude by group or module, or group and module together

Here’s what groups and modules stand for

implementation("Org. Hibernate hibernate: 3.1")

group = org.hibernate
module = hibernate
version = 3.1
Copy the code

Dependency passing is not allowed

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

     // Disable dependency passing
     A => B => C; B => C;
     // If A is dependent on B, then A can use B
     // dependencies in C,
     // The default is open, which is true
     transitive = false}}Copy the code

The jar conflicts

If your app references an AAR and the ARR references xx.jar again, you need to tell the AAR jar operator to use compileOnly instead of implementation

reference

Gradle Pit Crawl Guide – Dependency Management

Gradle and Android building primer