This article was first published on the wechat public account “Houchangcun Mannong”

Why use Gradle now? Gradle’s Core ideas (4) Seem useless, There are three ways to customize Gradle add-ons for Android. Gradle is designed for Android

preface

In this article, I will introduce you to some of the most important aspects of Gradle’s advanced software, such as signature configuration and dependency management. In this article, I will introduce you to some of the most important aspects of Gradle’s advanced software.

1. Configure the Android signature file

In the average company, when the team is small, the App signature information is put into the project, or even uploaded to Github, which is very convenient. However, as the team grows, this becomes more risky because signature information is an important resource, so signatures cannot be uploaded to Github and should not be configured directly in build.gradle. The solutions are as follows: 1. Customize a signature profile 2. Local ~ /. Gradle/gradle. Configuration properties file signature information

1.1 User-defined signature information file

First, create a new folder under the project directory to store signature files and signature information files internally. The signature file is gradleDemo. JKS, and the signature file is keystore.properties. The configuration in keystore.properties is as follows.

STORE_FILE=.. /signfiles/gradledemo.jks KEY_ALIAS=gradle STORE_PASSWORD=jinjiesanbuqu KEY_PASSWORD=jinjiesanbuquCopy the code

Don’t forget to omit gradledemo. JKS and keystore.properties in.gitignore. Build. Gradle and build. Gradle. Add the following code to the build.gradle module.

apply plugin: 'com.android.application'
android {
 ...
}
def setSigningProperties(a){
    def propFile = file('.. /signfiles/keystore.properties')
    if (propFile.canRead()){
        def Properties props = new Properties()
        props.load(new FileInputStream(propFile))
        if(props! =null && props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
            android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
            android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
            android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
            android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']}else {
            throw new Exception("some key missing")}}else {
        throw new Exception("keystore.properties not found:" + propFile.absolutePath)

    }
}
Copy the code

The setSigningProperties method is used to read information about the signature file in the keystore.properties file. Finally, call the setSigningProperties method in the SigningConfigs block of the build.gradle module.

apply plugin: 'com.android.application'

android {
 ...
    signingConfigs {
        release {
            setSigningProperties()
        }
    }
}
Copy the code

1.2 Adding a Signature File locally

You can also place signature files and signature information files locally. Such as the signature file in ~ /. Gradle/gradledemo JKS, signature information file in ~ /. Gradle/keystore. Properties. Neither the signature file nor the signature information file will be submitted to Github. The content of keystore.properties is as follows.

GRADLEDOME_RELEASE_STORE_FILE=~/.gradle/release-key.keystore
GRADLEDOM_RELEASE_KEY_ALIAS=key-alias
GRADLEDOM_RELEASE_STORE_PASSWORD=pass
GRADLEDOM_RELEASE_KEY_PASSWORD=pass
Copy the code

Configure the signature in the SigningConfigs block in the module build.gradle, as shown below.

signingConfigs {
        release {
            storeFile file(GRADLEDOME_RELEASE_STORE_FILE)
            storePassword GRADLEDOME_RELEASE_STORE_PASSWORD
            keyAlias GRADLEDOME_RELEASE_KEY_ALIAS
            keyPassword GRADLEDOME_RELEASE_KEY_PASSWORD
        }
    }
Copy the code

In addition to these two points, signature files and signature information files can be placed on a dedicated packaging server and read at packaging time. This involves a lot of content, will not be explained in this article.

2.Gradle library dependencies

Nowadays, an Android project usually needs to introduce other libraries, such as JAR, AAR, Module, etc. Let’s take a look at them separately. The following example code is written in the build.gradle module unless otherwise specified. Gradle’s local library dependencies on jar dependencies can be written as follows. You can specify one or more jars.

// Dependencies import all jars under liBS
implementation fileTree(dir:'libs',include:['*.jar'])

// Specify a dependency on one or more jars
implementation files('libs/XXX.jar'.'libs/XXX.jar')
Copy the code

Aar dependencies require additional statements, as shown below.

android {
    ...
    repositories { 
        flatDir {
            dirs "libs"
        }
    }
}    
dependencies {
implementation fileTree(dir:'libs',include:['*.aar'])
implementation(name:'XXX',ext:'aar')
}
Copy the code

Gradle’s local Module dependencies When there are multiple modules in a project, we need to introduce them in settings. Gradle, as shown below.

include ':app'
include ':library1'.':library2'
Copy the code

It is then introduced in the build.gradle module.

implementation project(':library1')
Copy the code

When you create a new project in Android Studio, you will see the following code in the project build. Gradle:

buildscript {
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com. Android. Tools. Build: gradle: 3.4.0'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        
    }
}
Copy the code

This code is provided by default, in the BuildScript and AllProjects blocks, with repositories for introducing Google’s Maven and JCenter libraries. The first thing to look for is Google’s Maven library, or JCenter library if you can’t find one. Then add the following code to the build.gradle module to introduce the remote library.

implementation group:'com.android.support',name:'appcompat-v7',version:'28.0.0'
/ / short
implementation 'com. Android. Support: appcompat - v7:28.0.0'
Copy the code

3.Gradle library dependency management

As Gradle relies on more and more libraries, there will inevitably be some problems, such as the problem of dependency conflict. To solve the problem of dependency conflict, we need to first understand the technical points of Gradle library dependency management.

3.1 Gradle dependency passing

Gradle supports dependency passing by default, so it is a must to know when using Gradle dependencies. So what is dependency passing? Take the simplest example. ProjectC depends on projectB, projectB depends on projectA, and projectC depends on projectA. Dependency passing can cause problems such as duplicate dependencies and dependency errors, and can be disabled via transitive.

   implementation('com. XXX. XXX, XXX: 3.6.3') {
        transitive false
    }
Copy the code

Com.xxx.xxx: XXX :3.6.3 library dependencies can be disabled by using the following statement: com.xxx.xxx: XXX :3.6.3 library dependencies

configurations.all {
   transitive = false
}
Copy the code

Except that this would require manually adding dependencies for each library of the current module, which is usually not the case.

3.2 Gradle dependency checks

With dependency checking, we can solve problems that arise from dependencies. Dependency checking can be done in many different ways.

In Windows, run the CMD command to enter the root directory of the project and execute Gradle :app:dependencies. App is the default module name when you create a project. The log output is quite large. Here is a sample:

+ - com. Android. Support: appcompat - v7:28.0.0 | + -- -- -- com. Android. Support: support - annotations: 28.0.0 / / 1 | + -- -- -- Com. Android. Support: support - compat: 28.0.0 / / 2 | | + -- -- -- com. Android. Support: support - annotations: 28.0.0 | | + -- -- -- Com. Android. Support: collections: 28.0.0 | | | \ - com android. Support: support - annotations: 28.0.0 | | + -- -- -- Android. Arch. Lifecycle: the runtime: 1.1.1 | | | + -- -- - android. The arch. The lifecycle: common: 1.1.1 | | | | \ -- -- -- Com. Android. Support: support - annotations: 26.1.0 - > 28.0.0 / / 3 | | | + -- -- - android. The arch. The core: common: 1.1.1 | | | | \ -- -- -- Com. Android. Support: support - annotations: 26.1.0 - > 28.0.0 | | | \ - com android. Support: support - annotations: 26.1.0 - > 28.0.0 | | \ - com android. Support: versionedparcelable: 28.0.0 | | + -- -- -- com. Android. Support: support - annotations: 28.0.0 | | \ - com. Android. Support: collections: 28.0.0 (*)Copy the code

Above is a small part of the dependency tree for the AppCompat-v7:28.0.0 library, which relies on the libraries at comment 1 and 2, 2 of the library depends on com. Android. Support: support – annotations: 28.0.0 and com. The android. Support: collections: 28.0.0, So when we introduced AppCompat-v7:28.0.0, all the libraries that it relied on to pass were automatically downloaded. As noted in comment 3, Gradle automatically upgrades the version of the library in which the dependency is passed. By default, the highest version of the library is used.

In addition to the command line, you can also use the Gradle panel on the right of Android Studio to locate the App module. Expand it and find dependencies in the Help directory, as shown in the following figure.

implementation 'com. Squareup. Retrofit2: retrofit: server'
Copy the code

When the dependency check command is executed, the following log about RetroFIT is printed:

+ - com. Squareup. Retrofit2: retrofit: server | \ - com squareup. Okhttp3: okhttp: 3.12.0 | \ -- -- -- Com. Squareup. Okio: okio: 1.15.0Copy the code

It is clear that Retrofit :2.6.0 relies on OKhttp :3.12.0, while okhttp:3.12.0 relies on okio:1.15.0. Try this with section 3.1 transitive and modify build.gradle:

  implementation ('com. Squareup. Retrofit2: retrofit: server') {
        transitive false
  }
Copy the code

When the dependency check command is executed, the following log about RetroFIT is printed:

+ - com. Squareup. Retrofit2: retrofit: serverCopy the code

If you find the first two methods inconvenient and unintuitive, you can also use the Android Studio Gradle View plugin. Go to File–>Settings–>Plugins and search for Gradle View. Find the Gradle View plug-in and restart the AS, AS shown in the following figure.

Go to View — >Tools Windows–Gradle View. You will find the Gradle View window at the bottom of the AS. It will display all the dependency trees for the current project, AS shown below.

3.3 Gradle dependency conflicts

Dependency conflicts are usually caused by the version of the library. For example, if you write build. Gradle:

    implementation 'com. Squareup. Retrofit2: retrofit: server'
    implementation 'com. Squareup. Okio: okio: 1.14.0'
Copy the code

In section 3.2, we learned that Retrofit :2.6.0 relies on version 1.15.0 of Okio, and that the version introduced here is version 1.14.0, causing dependency conflicts. The key to resolving dependency conflicts is Gradle’s dependency checking, which was covered in section 3.2, and the use of Gradle keywords. Using them properly is the key to resolving dependency conflicts. Transitive was introduced in section 3.1.

3.3.1 force

In some cases, we do not want to exclude a library, but we want to force the use of a uniform library version. Force can force the version of the module library, add the following code to the module build.gradle.

configurations.all {
    resolutionStrategy {
        force 'com. Squareup. Okio: okio: 2.1.0'} } dependencies { ... }Copy the code

Force the current module’s okio version to be 2.1.0, use dependency checking to check retrofit dependencies:

+ - com. Squareup. Retrofit2: retrofit: server | \ - com squareup. Okhttp3: okhttp: 3.12.0 | \ -- -- -- Com. Squareup. Okio: okio: 1.15.0 - > 2.1.0 \ - com squareup. Okio: okio: 1.14.0 - > 2.1.0Copy the code

As you can see, okio was forced to upgrade to 2.1.0, which resolved some dependency conflicts.

3.3.2 rainfall distribution on 10-12 exclude

You can use exclude when you need to exclude libraries that are involved in library dependency pass-throughs and you can’t solve the problem by turning off dependency pass-throughs. We know that com. Android. Support: appcompat – v7:28.0.0 depends on the com. Android. Support: support – annotations: 28.0.0, com. Android. Support: the support – compat: 28.0.0, com. Android. Support: cursoradapter: 28.0.0 libraries, at this moment we don’t want to rely on the support library – annotations, so to write.

configurations {
    all*.exclude group: 'com.android.support'.module: 'support-annotations'} dependencies { ... }Copy the code

Use dependency checking to see com. Android. Support: appcompat – v7:28.0.0 depends on:

+ - com. Android. Support: appcompat - v7:28.0.0 | + -- -- -- com. Android. Support: support - compat: 28.0.0 | | + -- -- -- Com. Android. Support: collections: 28.0.0 | | + -- -- - android. The arch. The lifecycle: the runtime: 1.1.1 | | | + -- -- -- Android. Arch. Lifecycle: common: 1.1.1 | | | \ - android arch. Core: common: 1.1.1 | | \ -- -- -- Com. Android. Support: versionedparcelable: 28.0.0 | | \ - com android. Support: collections: 28.0.0 | + -- -- -- Com. Android. Support: collections: 28.0.0 | + -- -- -- com. Android. Support: cursoradapter: 28.0.0Copy the code

And section 3.2, comparing to the log can be found that com. Android. Support: appcompat – v7:28.0.0 no longer rely on com. Android. Support: support – annotations: 28.0, the aim achieved.

Thanks to www.jianshu.com/p/c602e6c49… Blog.csdn.net/ouyang_peng… www.jianshu.com/p/82de510b4… Blog.csdn.net/zjpp2580369… Blog.fidroid.com/post/gradle…

For more information, check out my independent blog’s body of knowledge: liuwangshu.cn/system/


Here not only share big front end, Android, Java and other technologies, but also programmer growth class articles.