01.前言
在实际项目中,我一直想怎样以一种优雅的方式,解决build.gradle配置文件问题,我想你和我一定有同样的感受,在组件化亦或者模块化开发中,我相信我们都会进行同一种操作,为每个module配置一个build.gradle文件来构建我们的工程,但配置不能出错,版本得统一等许多细节,一旦出错,项目就无法构建。
02.为什么使用plugin方式
正如前言提到,我们在构建项目时,都要为module配置build.gradle项,繁琐,要细心,不能出错,并且文件还臭长,不易阅读,不易查找。为了解决这一问题,通过学习了解发现,自定义plugin就可以完美解决,我们可以像写业务代码一样,编写我们的gradle插件。
03.项目地址
https://gitee.com/zhuhuitao/componentization
04.传统apply from 引入方式
为了对每个module版本进行统一,会建一个config.gradle文件如下:
ext {
android = [
compileSdkVersion : 29,
buildToolsVersion : "30.0.2",
applicationId : "com.xionggouba.bearseller",
minSdkVersion : 19,
targetSdkVersion : 30,
versionCode : 27,
versionName : "3.9.1",
defaultPublishConfig: 'release',
publishNonDefault : true,
multiDexEnabled : true,
mapKey : 'c7e1ee468aa1bf8a6739',
pushKey : '65aae199a0059eb1dbe7',
pushChannel : 'developer-default',
]
appid = [
app : "com.xionggouba.bearseller",
login : "com.huitao.login",
home : "com.huitao.home",
webview : "com.huitao.webview",
main : "com.huitao.main",
productManager: "com.huitao.productmanager",
personal : "com.huitao.personalcenter",
map : "com.huitao.map",
bluetooth : "com.huitao.bluetooth",
push : "com.huitao.push",
markketing : "con.huitao.marketing",
printer : "com.huitao.printer"
]
versions = [
"lifecycle_version": "2.2.0",
"arch_version" : "2.1.0",
"retrofit_version" : "2.6.2",
"dialog_version" : "3.3.0",
"glide_version" : "4.9.0",
"hilt" : "2.28-alpha",
"kotlin_version" : "1.4.10",
"fragment_version" : "1.2.5",
"room_version" : "2.2.6"
]
architecture = [
"viewmodel" : "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions['lifecycle_version']}",
"livedata" : "androidx.lifecycle:lifecycle-livedata-ktx:${versions['lifecycle_version']}",
"lifecycleruntime" : "androidx.lifecycle:lifecycle-runtime-ktx:${versions['lifecycle_version']}",
"savedstate" : "androidx.lifecycle:lifecycle-viewmodel-savedstate:${versions['lifecycle_version']}",
// alternately - if using Java8, use the following instead of lifecycle-compiler
"lifecyclecommon" : "androidx.lifecycle:lifecycle-common-java8:${versions['lifecycle_version']}",
// Saved state module for ViewModel
"viewmodelsavedstate": "androidx.lifecycle:lifecycle-viewmodel-savedstate:${versions['lifecycle_version']}",
"lifecycleextentions": "androidx.lifecycle:lifecycle-extensions:${versions['lifecycle_version']}",
"retrofit2" : "com.squareup.retrofit2:retrofit:${versions['retrofit_version']}",
"gson" : "com.squareup.retrofit2:converter-gson:${versions['retrofit_version']}",
"persistentcookiejar": "com.github.franmontiel:PersistentCookieJar:v1.0.1",
"glide" : "com.github.bumptech.glide:glide:${versions['glide_version']}",
"glidecompiler" : "com.github.bumptech.glide:compiler:${versions['glide_version']}",
"oss" : "com.aliyun.dpa:oss-android-sdk:2.9.1",
"luban" : "top.zibin:Luban:1.1.8"
]
]
在我们工程的根目录build.gradle
apply from"config.gradle"
这里config文件中仅仅是部分代码,实际项目中远远不止这几行,其实我们都感觉很难阅读,找一个东西就得靠搜索,逐一查找。
05.对比buildSrc方式
这里有讲述buildSrc的缺陷,https://flywith24.gitee.io/2020/04/15/Tips-includeBuild/
06. 自定义plugin+includeBuild
1,通过新建library的方式新建一个version,如下图:2,修改version中的build.gradle.kts,我们以kotlin方式编写,如下:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
// 由于使用的 Kotlin 须要须要添加 Kotlin 插件,这里使用最新的kotlin插件
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32")
}
}
plugins {
`kotlin-dsl`
`java-gradle-plugin`
}
repositories {
// 须要添加 jcenter 不然会提示找不到 gradlePlugin
jcenter()
google()
}
dependencies {
compileOnly(gradleApi())
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32")
compileOnly("com.android.tools.build:gradle:4.1.1")
}
kotlinDslPluginOptions {
experimentalWarning.set(false)
}
gradlePlugin {
plugins {
create("version") {
// 在 app 模块须要经过 id 引用这个插件
id = "com.huitao.version"
// 实现这个插件的类的路径
implementationClass = "com.huitao.version.VersionConfigPlugin"
}
}
}
3,在工程setting.gradle中引入version插件:
然后进行同步,这样便于我们在插件编写kotlin代码有提示,
4,修改工程的builde.gradle.kts,也采用kotlin方式编写:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.huitao.version") apply (false)
}
buildscript {
//这里需要和version module中的kotlin版本统一,实际测试中如果不统一好像编译不通过
val kotlinVersion by extra("1.4.32")
val android by extra("com.android.tools.build:gradle:4.1.2")
repositories {
google()
jcenter()
}
dependencies {
//kotlin的写法
classpath(android)
classpath(kotlin(module = "gradle-plugin", version = kotlinVersion))
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url = uri("https://jitpack.io") }
}
}
subprojects {
// 子项目统一应用插件
project.apply(plugin = "com.huitao.version")
when (name) {
//判断如果module是app则引入com.android.application插件
"app" -> apply(plugin = "com.android.application")
//如果不是则引入com.android.library插件,这里可以灵活编写
else -> apply(plugin = "com.android.library")
}
}
tasks.register("clean") {
delete(buildDir)
}
5,新建VersionConfigPlugin 继承Plugin
/**
*author : huitao
*e-mail : [email protected]
*date : 2021/5/12 20:52
*desc :
*version :
*/
class VersionConfigPlugin : Plugin {
override fun apply(project: Project) {
project.plugins.config(project)
}
private fun PluginContainer.config(project: Project) {
whenObjectAdded {
when (this) {
is AppPlugin -> {
//公共插件
project.configCommonPlugin()
//公共android配置
project.extensions.getByType().applyAppCommons(project)
//公共依赖
project.configAppDependencies()
}
is LibraryPlugin -> {
//公共插件
project.configCommonPlugin()
//公共android配置
project.extensions.getByType().applyLibraryCommons(project)
//公共依赖
project.configLibraryDependencies()
}
is KotlinAndroidPluginWrapper -> {
//根据 project build.gradle.kts 中的配置动态设置 kotlinVersion
project.getKotlinPluginVersion()?.also { kotlinVersion ->
GradlePlugins.kotlinVersion = kotlinVersion
}
}
}
}
}
///library module 公共依赖
private fun Project.configLibraryDependencies() {
dependencies.apply {
add(api, fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
add(implementation, GradlePlugins.kotlinStdlib)
//如果module 的 name 不是common则引入common模块,不加次判断,活报错,提示我们common
//module自己引入自己,相当于递归了
if (name != "common") {
add(implementation, project(":common"))
}
//引入autoService服务,主要为后续的组件化开发做准备,Kotlin中要使用kapt方式
add(kapt, ThirdParty.autoService)
add(compileOnly, ThirdParty.autoService)
configTestDependencies()
}
}
//app module
private fun Project.configAppDependencies() {
dependencies.apply {
add(implementation, fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
//添加library工程,不用在build中编写
add(implementation, GradlePlugins.kotlinStdlib)
add(implementation, (project(":login")))
add(implementation, project(":order"))
add(implementation, project(":common"))
configTestDependencies()
}
}
/// test 依赖配置
private fun DependencyHandler.configTestDependencies() {
testImplementation(Testing.testLibraries)
androidTestImplementation(Testing.androidTestLibraries)
}
///kotlin插件
private fun Project.configCommonPlugin() {
//添加android 或者 kotlin插件
plugins.apply("kotlin-android")
plugins.apply("kotlin-android-extensions")
plugins.apply("kotlin-kapt")
}
///app module 配置项 此处固定了applicationId
private fun AppExtension.applyAppCommons(project: Project) {
defaultConfig {
applicationId = BuildConfig.applicationId
}
applyBaseCommons(project)
}
/// app module 配置项
private fun LibraryExtension.applyLibraryCommons(project: Project) {
applyBaseCommons(project)
}
///配置android闭包下的公共环境
private fun BaseExtension.applyBaseCommons(project: Project) {
compileSdkVersion(BuildConfig.compileSdkVersion)
buildToolsVersion(BuildConfig.buildToolsVersion)
defaultConfig {
minSdkVersion(BuildConfig.minSdkVersion)
targetSdkVersion(BuildConfig.targetSdkVersion)
versionCode = BuildConfig.versionCode
versionName = BuildConfig.versionName
testInstrumentationRunner = BuildConfig.runner
manifestPlaceholders(
mapOf(
jPushPackageName to BuildConfig.applicationId,
jPushAppKey to "7e88bec095d30e8ced40654cc",
jPushChannel to "developer-default"
)
)
}
signingConfigs {
register(BuildConfig.release) {
keyAlias = "bear"
keyPassword = "BEARSELLER"
storePassword = "bearseller"
storeFile = File("bearSeller.jks")
}
/* register(BuildConfig.debug) {
keyAlias("bear")
keyPassword("BEARSELLER")
storePassword("bearseller")
storeFile(File("../bearSeller.jks"))
}*/
}
buildTypes {
getByName(BuildConfig.release) {
isMinifyEnabled = false
signingConfig = signingConfigs.getByName(BuildConfig.release)
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
getByName(BuildConfig.debug) {
signingConfig = signingConfigs.getByName(BuildConfig.debug)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dataBinding {
isEnabled = true
}
project.tasks.withType {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
}
6,在common module中的build.gradle中:
dependencies{
api(AndroidX.constraintlayout)
api(AndroidX.appcompat)
api(AndroidX.coreKtx)
api(AndroidX.material)
}
上面这段代码是可以直接直接写在versionPlugin中的,个人喜欢,你想写在哪就写在哪,
7,验证module是否正确引入了common:
在common library中新建工具类Util,然后在module order中是否可以正确使用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Util.logD("测试")
}
}
总结
通过自定义plugin+including的方式,我们可以完全通过kotlin代码方式编写我们的gradle配置,让我们的build.gradle中没有一行代码,且阅读性很高,便于跟踪代码,如果你有get到,欢迎点赞关注谢谢!~~