Android Studio unified dependency management composition builds

background

In our AS projects, we often refer to multiple modules and many people participate in project development. Under this background, we will often encounter version conflicts and different compilesdkversions, resulting in larger packages and longer project running time. Therefore, the only way to optimize a project is to unify the dependent version.

You may encounter such a problem
In the architecture design phase, your dependency library is like this

After colleagues developed in parallel and merged the code, this became the case

Hahaha, this is the consequence of not doing a good job in dependency management! Here are three dependency management methods. If you are familiar with the first two, you can directly jump to the third composition builds. The third is recommended.

1, Alternative to Groovy ext extension functions

When we use Groovy language to build a project, we extract config.gradle as the global variable control, and use ext extension function to uniformly configure dependencies, as follows:

Example code:

ext {
    android = [
            compileSdkVersion: 29,
            buildToolsVersion: "29",
            minSdkVersion    : 17,
            targetSdkVersion : 26,
            versionCode      : 102,
            versionName      : "1.0.2"
    ]
version = [
        appcompatVersion       : "1.1.0",
        coreKtxVersion         : "1.2.0",
        supportLibraryVersion  : "28.0.0",
        androidTestVersion     : "3.0.1",
        junitVersion           : "4.12",
        glideVersion           : "4.11.0",
        okhttpVersion          : "3.11.0",
        retrofitVersion        : "2.3.0",
        constraintLayoutVersion: "1.1.3",
        gsonVersion            : "2.7",
        rxjavaVersion          : "2.2.2",
        rxandroidVersion       : "2.1.0",
        ..........ellipsis...........
]

dependencies = [
        //base
        "constraintLayout"      : "androidx.constraintlayout:constraintlayout:${version["constraintLayoutVersion"]}",
        "appcompat"             : "androidx.appcompat:appcompat:${version["appcompatVersion"]}",
        "coreKtx"               : "androidx.core:core-ktx:${version["coreKtxVersion"]}",
        "material"              : "com.google.android.material:material:1.2.1",

        //multidex
        "multidex"              : "com.android.support:multidex:${version["multidexVersion"]}",

        //okhttp
        "okhttp"                : "com.squareup.okhttp3:okhttp:${version["okhttpVersion"]}",
        "logging-interceptor"   : "com.squareup.okhttp3:logging-interceptor:${version["okhttpVersion"]}",

        //retrofit
        "retrofit"              : "com.squareup.retrofit2:retrofit:${version["retrofitVersion"]}",
        "converter-gson"        : "com.squareup.retrofit2:converter-gson:${version["retrofitVersion"]}",
        "adapter-rxjava2"       : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitVersion"]}",
        "converter-scalars"     : "com.squareup.retrofit2:converter-scalars:${version["retrofitVersion"]}",
		..........ellipsis...........
]
}

After the dependency is written, build.gradle in the root path
Add apply from: "config.gradle"

Then in build.gradle under the module that needs to be dependent

dependencies {
	...
    // Retrofit + okhttp dependent packages
    api rootProject.ext.dependencies["retrofit"]
    ...
    }

The above is the dependency management method of Groovy ext extension function. This method can achieve version dependency, but the biggest disadvantage is that it is unable to track the code. To find the dependency of rootProject.ext.dependencies["retrofit"] in the above example code, you need to manually switch to config.gradle to search and find, which is very readable.

2, Using buildSrc+kotlin

buildSrc is a particularly popular version dependent management method in recent years. It has the following advantages:

  • Support two-way tracking
  • buildSrc is the default plug-in for Android. This is the only place that can be modified globally
  • Support the code completion of Android Studio. The following demonstration example is from the network


Refer to: Kotlin + buildSrc for Better Gradle Dependency Management

Disadvantages: buildSrc dependency update will rebuild the whole project. The larger the project, the longer the reconstruction time, resulting in unnecessary waste of time.

3, Composing builds

Composing builds : A composite build is simply a build that includes other builds. In many ways a composite build is similar to a Gradle multi-project build, except that instead of including single projects, complete builds are included. (Composing builds is just a build that contains other builds. In many ways, composite builds are similar to gradle multi project builds, except that it includes a complete build rather than a single project.)

The advantages of using this method are:
1. Support one-way tracking
2. Automatic completion
3. When relying on updates, the entire project will not be rebuilt

Mode of use
1. Create a new module named VersionPlugin (from)
2. Add the following code to the build.gradle file under the new module:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // Because the Kotlin plug-in needs to be added
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10"
    }
}

apply plugin: 'kotlin'
apply plugin: 'java-gradle-plugin'

repositories {
//jcenter needs to be added, otherwise it will prompt that gradlePlugin cannot be found
jcenter()
google()
}

dependencies {
implementation gradleApi()
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10"
}

compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}

gradlePlugin {
plugins {
version {
//The plug-in needs to be referenced by id in the app module
id = 'com.controler.versionplugin'
//The path to the class that implements the plug-in
implementationClass = 'com.controler.versionplugin.VersionPlugin'
}
}
}

3. Create a new DependencyManager.kt file in VersionPlugin/src/main/java / package name / directory and add your dependency configuration, such as:

package com.controler.versionplugin
/**
 * Configuration and build related
 */
object BuildVersion {
    const val compileSdkVersion = 29
    const val buildToolsVersion = "29.0.2"
    const val minSdkVersion = 17
    const val targetSdkVersion = 26
    const val versionCode = 102
    const val versionName = "1.0.2"
}
/**
 * Project related configuration
 */
object BuildConfig {
    //AndroidX
    const val appcompat = "androidx.appcompat:appcompat:1.2.0"
    const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.0.4"
    const val coreKtx = "androidx.core:core-ktx:1.3.2"
    const val material = "com.google.android.material:material:1.2.1"
    const val junittest = "androidx.test.ext:junit:1.1.2"
    const val swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
    const val recyclerview = "androidx.recyclerview:recyclerview:1.1.0"
    const val cardview = "androidx.cardview:cardview:1.0.0"
   //Depend
    const val junit = "junit:junit:4.12"
    const val espresso_core = "com.android.support.test.espresso:espresso-core:3.0.2"
    const val guava = "com.google.guava:guava:24.1-jre"
    const val commons = "org.apache.commons:commons-lang3:3.6"
    const val zxing = "com.google.zxing:core:3.3.2"
    //leakcanary
    const val leakcanary = "com.squareup.leakcanary:leakcanary-android:2.4"
    //jetPack
    const val room_runtime = "androidx.room:room-runtime:2.2.5"
    const val room_compiler = "androidx.room:room-compiler:2.2.5"
    const val room_rxjava2 = "androidx.room:room-rxjava2:2.2.5"
    const val lifecycle_extensions = "android.arch.lifecycle:extensions:1.1.1"
    const val lifecycle_compiler = "android.arch.lifecycle:compiler:1.1.1"
    const val rxlifecycle = "com.trello.rxlifecycle3:rxlifecycle:3.1.0"
    const val rxlifecycle_components = "com.trello.rxlifecycle3:rxlifecycle-components:3.1.0"
    //Kotlin
    const val kotlinx_coroutines_core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
	...
}

4. Create a new VersionPlugin.kt under VersionPlugin/src/main/java / package name / directory,
The Plugin interface is implemented as follows:

package com.controler.versionplugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class VersionPlugin : Plugin<Project>{
    override fun apply(p0: Project) {
    }
    companion object{   
    }
}

Note: when creating a VersionPlugin module, other useless resources generated can be deleted and only those needed can be reserved, as follows:

5. Add includeBuild ("VersionPlugin") in the settings.gradle file. Note that it is includeBuild Oh ~, Rebuild project
6. You can use it in the gradle file you need to use later, such as build.gradle under app. Add the following content in the first line:

plugins {
    // Plug in ID defined in part 2
    id "com.controler.versionplugin"
}
// Defined dependent address
import com.controler.versionplugin.* 

Use the following

summary

1. Using groovy ext can't track dependencies, which is poor in readability and inconvenient for maintenance
2. Kotlin + BuildSrc is used to support two-way tracking, and the whole project will be rebuilt when relying on update
3. Using compositing builds supports one-way tracking, and the whole project will not be built when relying on updates

reference

Android ext
Kotlin + buildSrc for Better Gradle Dependency Management
Composing builds
Embrace Composing builds to improve Android compilation speed

Tags: Android Android Studio

Posted by doni49 on Wed, 22 Sep 2021 23:37:23 +0530