Main contents of this paper:
- Dependency management: Gradle plug-in 7.0 and above uses version Catalog for dependency management
- General build extended property management: configures common extension properties, plug-ins, and dependencies for each subproject in the plug-in project
- Plug-in engineering: Hybrid compilation of the plug-in project and the main project, and how gradle plug-ins 7.0 and above are published to the Jitpack.
Now the project is basically multi-module structure, each new module will copy the minSdk, targetSdk and other general extension attributes will be more troublesome, should use the general plug-in to manage.
1 Use of Plug-ins
Use case: Plugin /sample
Plugin source: feature/plugin
1.1 Adding a Dependency
A:
// Project root directory build.gradle.kts
buildscript {
repositories {
maven { setUrl("https://jitpack.io") }
}
dependencies {
classpath("Com.github.Jadyli.com posing: config - plugin: 0.1.2.")}}Copy the code
Method 2 (Recommended) :
// The project root directory settings.gradle.kts
pluginManagement {
repositories {
maven { setUrl("https://jitpack.io") }
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"com.jady.lib.config-plugin" -> {
useModule("Com.github.Jadyli.com posing: config - plugin: 0.1.2.")}}}}}Copy the code
1.2 Configuring the SDK Version:
Method 1: Configure it in the gradle.properties file in the root directory of the project
minSdk=21
targetSdk=31
compileSdk=31
javaMajor=11
javaVersion=11
compose=1.1. 0-beta04
Copy the code
Method 2 (recommended) : In the project root directory build.gradle. KTS
// Here is the version catalog. You can also directly replace it with the corresponding version number, refer to Method 1
ext {
set("minSdk", libs.versions.minSdk.get())
set("targetSdk", libs.versions.targetSdk.get())
set("compileSdk", libs.versions.compileSdk.get())
set("javaMajor", libs.versions.java.major.get())
set("javaVersion", libs.versions.java.asProvider().get())
set("compose", libs.versions.compose.get()}Copy the code
For compose, you can add the compose dependency and configuration by default. If you don’t need it, you can add it and leave a comment.
1.3 Application in module
/ / way (recommended), with the version catalog can be written as alias (libs. Plugins. Config. The plugin)
plugins {
id("com.jady.lib.config-plugin")}2 / / way
apply(from = "com.jady.lib.config-plugin")
Copy the code
Once added, a Library configuration file will be very concise, with just a few plug-ins and dependencies needed for modules.
@file:Suppress("UnstableApiUsage")
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.hilt.android)
alias(libs.plugins.config.plugin)
}
dependencies {
// official library
implementation(libs.bundles.compose.core)
implementation(libs.hilt.runtime)
kapt(libs.bundles.hilt.compiler)
// other module
api(projects.framework.utils)
}
Copy the code
2 Dependency Management
Gradle sharing depends on the official document: docs.gradle.org/current/use…
Toml official website: Toml. IO /en/
2.1 version of the catalog
In the past, there has been no uniform way to manage dependencies. Either by setting dependencies in the project properties file (such as creating a dependencies. Gradle file), or by creating a plug-in project to put all dependencies in the plug-in. The advantage of this is that the plug-in can be shared by multiple projects and used as a variable when retrieved. The Version Catalog is similar to this plug-in, except that the Version Catalog is a generic TOML format file for defining dependencies.
[versions]
# build config
compileSdk = "31"
# official library
kotlin = "1.6.0"
compose = "1.1.0 - beta04"
androidx-appcompat = "1.4.0"
[libraries]
# official library
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-activity-compose = "Androidx. Activity: activity - compose: 1.4.0." "
compose-material = { module = "androidx.compose.material3:material3", version = "1.0.0 - alpha02" }
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0 [", prefer="3.9" } }
[plugins]
android-application = { id = "com.android.application", version.ref = "android-plugin" }
[bundles]
compose-core = ["androidx-activity-compose"."compose-uiTooling"."compose-material"]
Copy the code
To sum up:
- Gradle supports four types of nodes:
[versions]
Used to define the version number, which must be a string.[libraries]
For defining dependencies, refer to the example above for the supported format[plugins]
Used to define plug-ins[bundles]
Used to define a dependency group
- Version number You can specify a single version and a range of versions. You can refer to the specific rulesVersionConstraintClass comments are also available for referenceDeclaring Rich Versions, here is a brief explanation:
- Version ranges are represented by ranges.
(
,)
Represents the open interval,[
,]
Represents a closed interval.[
I put it on the right-hand side of the interval)
, such as[1, 2 [
The equivalent of[1, 2)
.]
I put it on the left-hand side of the interval(
, such as] 1, 2]
The equivalent of(1, 2]
. - There are four version matching modes that can be specified:
strictly
,require
,prefer
,reject
. require
(When no mode is specified,require
Is the default mode) version or version range corresponding toVersionConstraintIn thegetRequiredVersion()
Required Version Indicates the lowest supported version, which can be higher but not lower.strictly
The strict version, literally,prefer
,reject
Also literally.
- Version ranges are represented by ranges.
The dependencies defined can be used locally or after publication.
2.2 Local Use
There is no rule for the location of the toml file. You can customize the location. In general, you can save the toml file in the gradle directory or your own configuration file directory, as long as it can be referenced in the script file. Now you can define the Version Catalog container, refer to:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("${rootDir.path}/.config/dependencies-common.toml"))}}}Copy the code
After sync, Java code is generated from the toml file. You can use libs variables in build.gradle. Here’s an example:
[versions]
kotlin = "1.6.0"
kotlin-coroutines = "1.6.0 - RC2"
[libraries]
kotlin-stdlib-jdk7 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk7", version.ref = "kotlin" }
[bundles]
compose-core = ["androidx-activity-compose"."compose-uiTooling"."compose-material"]
[plugins]
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"} the corresponding code call is:val kotlinVersion = libs.versions.kotlin.asProvider().get(a)val kotlinCoroutinesVersion = libs.versions.kotlin.coroutines.get()
implementation(libs.kotlin.stdlib.jdk7)
implementation(libs.bundles.compose.core)
// The current version of AS does not support the version catalog. Add @suppress.
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.kotlin.android)
}
Copy the code
2.3 Publishing to the Warehouse
Release code:
@file:Suppress("UnstableApiUsage")
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
`maven-publish`
`version-catalog`
}
catalog {
versionCatalog {
from(files("${rootDir.path}/.config/dependencies-common.toml"))
}
}
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "com.jady.lib"
artifactId = "dependencies"
version = "1.0.0"
from(components["versionCatalog"])
}
}
repositories {
maven {
setUrl("repo.url")
credentials {
username = project.property("repo.username").toString()
password = project.property("repo.password").toString()
}
}
}
}
Copy the code
After the release, change the dependencyResolutionManagement mentioned above. Other projects can also share dependencies in this way.
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from("Com. Mycompany: catalog: 1.0")}}}Copy the code
3 Plug-in Engineering
Here the extension attribute refers to something like this (BaseAppModuleExtension) :
android {
compileSdk 30
defaultConfig {
applicationId "com.jady.sample"
minSdk 21
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'}}Copy the code
With multiple modules, it’s not too much trouble to configure properties like buildTypes and compileOptions for each module. The trouble is that every module needs to be changed every time it changes, which is very maintenance unfriendly. It is a good idea to dispose of these attributes in the plug-in.
Let’s start by creating a plug-in project. In my opinion, Composing builds have been available for a few years but do not appear to be widely used in the country. In my opinion, Composing build is my preference to be called mixed build, although some of it can be translated into composite build or combination build, I don’t care, my name is mixed build 🧐.
In short, the main function of hybrid compilation is that small modules can be compiled and run as independent projects or as part of a larger project. At present, the basic idea of compiling acceleration in China is module AAR. For a project of dozens of modules, aar compilation is used for modules that have not been changed, and source code compilation is used for modules that have been changed. In fact, if the module is relatively independent, it can also be a little faster, is mixed compilation, a single module as an independent project development and debugging, after the development of nothing need to change, with a big project package.
You can see our pluginThe master branch.
Note that the plugin is a separate project and can be compiled and run separately. You can check the plugin source code in the feature/ Plugin branch.
So the plugin project is a hybrid compilation, includeBuild(“plugins”) in the settings.gradle file of the main project, and then use everything else as described in section 1. Isn’t that amazing? Even if we set the dependency address for the plugin ID in pluginManagement, the project will still use our plugin source code! When we’re done, we just publish the new version and comment out includeBuild(“plugins”).
Let’s configure build.gradle for the plugin.
plugins {
`kotlin-dsl`
`maven-publish`
}
group = "com.jady.lib"
version = "0.1.2"
gradlePlugin {
plugins.register("config") {
id = "com.jady.lib.config-plugin"
implementationClass = "com.jady.lib.config.ConfigPlugin"}}Copy the code
Import the plug-in, set the group and version, define the plug-in ID and entry, and you’re done. Regardless of how the plug-in is implemented, let’s see how it is published to the Jitpack. The jitpack is compiled using Java 1.8 by default. We are using Java 11, so we need to configure the jitpack.
jdk:
- openjdk11
Copy the code
And then commit, add a tag to the commit, and then run on the Jitpack (jitpack address), and hit Get It to do the compilation.
See the output at the end of the log file:
Build artifacts:
com.github.Jadyli.composing:config-plugin:0.12.
com.github.Jadyli.composing:com.jady.lib.config-plugin.gradle.plugin:0.12.
Copy the code
You’ll notice there are two of them, so let’s just use the first one, refer to the first one.
Let’s write the plug-in:
@Suppress("UnstableApiUsage")
class ConfigPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.run {
plugins.all {
when (this) {
is LibraryPlugin -> configureLibraryPlugin()
is AppPlugin -> configureAppPlugin()
}
}
}
}
private fun Project.configureLibraryPlugin(a) {
configCommonPlugin()
configCommonDependencies()
extensions.getByType<LibraryExtension>().configCommonExtension(this@configureLibraryPlugin)}private fun Project.configureAppPlugin(a) {
configCommonPlugin()
configCommonDependencies()
extensions.getByType<BaseAppModuleExtension>().run {
configCommonExtension(this@configureAppPlugin)
defaultConfig {
splits {
abi {
isEnable = true
reset()
include("x86"."armeabi-v7a"."arm64-v8a")
isUniversalApk = false}}}... }}private fun BaseExtension.configCommonExtension(project: Project) {
setCompileSdkVersion(project.property("compileSdk").toString().toInt())
...
}
private fun Project.configCommonPlugin(a) {
plugins.apply("org.jetbrains.kotlin.android")... }private fun Project.configCommonDependencies(a){... }}Copy the code
Plug-ins are very simple, you can configure attributes, plug-ins, dependencies, see the code to understand, nothing to say, we have requirements can comment, the above split should be some projects can not be used, but also according to their own needs fork a copy out at will.