Gradle系列(2)——如何自定以Gradle 插件

Android studio版本对用的gradle版本和插件版本(注意事项) Android Studio 构建系统以 Gradle 为基础,并且 Android Gradle 插件添加了几项专用于构建 Android 应用的功能。虽然 Android 插件通常会与 Android Studio 的更新步调保持一致,但插件(以及 Gradle 系统的其余部分)可独立于 Android Studio 运行并单独更新。 阅读详情

声明:本篇以及系列Gradle相关帖子均是基于gradle-7.3.3版本

1.简介gradle plugin

每一个gradle release版本分3中类型,以7.3.3版本为例:

在wrapper>gradle-wrapper.properties内:
以
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip声明使用的gradle版本。

  • 7.3.3-doc,类型只有文档
  • 7.3.3-bin,只有源代码
  • 7.3.3-all ,l既有文档又有源代码

附国内 腾讯gradle release镜像

1.1 什么是gradle plugin

gradle plugin是应用在AndroidStudio编译脚本中的插件,是一种用于扩展和定制Gradle构建系统功能的机制。
其中打包了可重复利用的编译逻辑,这些逻辑可以是一些便捷的功能便于我们快速实现编译逻辑,也可以包含特定的逻辑实现特定的功能,包括执行测试,打包,生成文档等等,
gradle plugin提供了构建灵活性,可以分享给不同的人,并在不同的项目中应用;
r如“com.android.application”,“com.android.library”,

1.2 编写语言

DSL(Domain Specific Language)领域特定语言,它是编程语言赋予开发者的一种特殊能力,通过它我们可以编写出一些看似脱离其原始语法结构的代码,从而构建出一种专有的语法结构。

gradle5.0之后开始支持Kotlin

Groovy 是Apache旗下的一种强大的、可选类型的和动态的语言,具有静态类型和静态编译功能,用于Java平台,旨在通过简洁、熟悉和易于学习的语法提高开发人员的生产力。它与任何Java程序顺利集成,并立即为您的应用程序提供强大的功能,包括脚本功能、领域特定语言创作、运行时和编译时元编程以及函数编程。
并且,Groovy可以与Java语言无缝衔接,可以在Groovy中直接写Java代码,也可以在Java中直接调用Groovy脚本,非常丝滑,学习成本很低。

7.0之后,project 下的build.gradle 发生改变,默认只有plugin配置,其它的逻辑挪到setting.gradle

2. gradle 生命周期

  • initialization(初始化)阶段

在这个阶段,Gradle 会读取settings.gradle。这个文件内包含插件管理,插件仓库管理,项目依赖仓库管理,最重要的是要读取module,gradle会为每一个module创建一个project。

  • Configuration (配置)阶段

在这个阶段,Gradle 会读取包含的所有构建脚本,应用插件,使用DSL配置构建,并在最后注册Task。

  • Execution (执行)阶段

Gradle会根据Task的依赖关系按序执行每一个Task。

2.1 监听gradle生命周期

在setting.gradle内:


println("this is settings")
gradle.addBuildListener(object : BuildListener {

    override fun beforeSettings(settings: Settings) {
        super.beforeSettings(settings)
        println("beforeSettings")
    }

    override fun settingsEvaluated(settings: Settings) {
        println("settingsEvaluated")
    }

    override fun projectsLoaded(gradle: Gradle) {
        println("projectsLoaded:rootProject.name:" + gradle.rootProject.name + ",projectNum:" + gradle.rootProject.allprojects.size)
    }

    override fun projectsEvaluated(gradle: Gradle) {
        println("projectsEvaluated:rootProject.name:" + gradle.rootProject.name + ",projectNum:" + gradle.rootProject.allprojects.size)

    }

    override fun buildFinished(result: BuildResult) {
        println("buildFinished")
    }
})


在app module里添加


println("in main module")
android {
    println("android config")

    //...
}


点击同步,看build输出:


this is settings
settingsEvaluated
projectsLoaded:rootProject.name:BoosterApply,projectNum:3

> Configure project :app
-----------------gradle-rocket start-----------
[SignatureConfigImpl]: start apply signature config >>> 
    isApplication:true
    taskName:[]
    configProguardFile buildType:debug
    configProguardFile buildType:release
[VersionConfigImpl]:start apply common-version config >>>
javaVersion:11,each:11
[DependenciesConfigImpl]:start apply dependencies configs >>>
[OtherConfigImpl]:start apply other config >>> 
-----------------gradle-rocket end -----------
booster config
in main module
android config

> Configure project :lib-support
-----------------gradle-rocket start-----------
[SignatureConfigImpl]: start apply signature config >>> 
    isApplication:false
    project is not app,Booster won`t apply signature
    configProguardFile buildType:debug
    configProguardFile buildType:release
[VersionConfigImpl]:start apply common-version config >>>
javaVersion:11,each:11
[DependenciesConfigImpl]:start apply dependencies configs >>>
[OtherConfigImpl]:start apply other config >>> 
-----------------gradle-rocket end -----------
projectsEvaluated:rootProject.name:BoosterApply,projectNum:3

> Task :prepareKotlinBuildScriptModel UP-TO-DATE
buildFinished

BUILD SUCCESSFUL in 2s

从输出可以看出,上述明显分为3个阶段:

第一阶段读取Settings,然后加载project,这个时候出现3个project(两个子module+rootProject);

第二阶段就是读取module里的build.gradle,配置对应的project。可以看到,在上述先后配置两个module project。"gradle-rocket"是一个插件。

第三阶段,开始执行task,最后buildFinish(此处我只是同步项目,不是打包,但是都是一样的)。

我们的插件就是要在configure阶段做我们的事情。

3.gradle plugin实现

3.1 集成方式

例如我在项目编译完成之后提示编译完成:

在module build.gradle内



class GreetingPlugin:Plugin<Project>{

    override fun apply(target: Project) {
        println("this is my greetingPlugin !")
        //eg:添加一个依赖
        target.dependencies.add("api","com.google.code.gson:gson:2.10")
        //eg:配置完成输入一段日志
        target.afterEvaluate{
            println("Greeting plugin ,afterEvaluate")
        }
    }
}
apply<GreetingPlugin>()


在这个plugin中,做了两件事:添加一个依赖,配置完成输出一段日志。

输出结果:


this is settings
settingsEvaluated
projectsLoaded:rootProject.name:BoosterApply,projectNum:3

> Configure project :app

this is my greetingPlugin !
Greeting plugin ,afterEvaluate

> Configure project :lib-support

projectsEvaluated:rootProject.name:BoosterApply,projectNum:3

> Task :prepareKotlinBuildScriptModel UP-TO-DATE
buildFinished

BUILD SUCCESSFUL in 4s


可以看到输出了我们插件的日志。

然后我们使用gradle app:dependencies命令查看依赖是否添加成功:


+--- project :app (*)
+--- androidx.test:runner:1.5.2

+--- com.android.support.test.espresso:espresso-core:3.0.2 -> androidx.test.espresso:espresso-core:3.1.0-alpha3

+--- androidx.test.ext:junit:1.1.3

+--- androidx.appcompat:appcompat:1.4.1

...

+--- com.google.code.gson:gson:2.10
+--- androidx.databinding:viewbinding:7.1.2
|    \--- androidx.annotation:annotation:1.0.0 -> 1.3.0
+--- com.alibaba:fastjson:2.0.31
...
\--- androidx.lifecycle:lifecycle-common:{strictly 2.4.0} -> 2.4.0 (c)



可以看到打印的依赖树(删减部分)中有在插件中添加的gson。

这种实现插件的方式简单快捷,但会导致项目的配置文件臃肿,不易阅读维护,同时也不方便项目之间共享

3.2 buildSrc

复杂的构建逻辑适合封装在单独的插件中,而且自定义任务和插件的实现也不应该放在build.gradle中。这些逻辑应该自成一体,独立存放,所以buildSrc应用而生,buildSrc就非常的方便了,它在单个项目中使用非常的方便。

buildSrc是一个特殊的included module,无需显式的声明在setting.gradle中;一个项目只能存在一个且必须存在根目录中,gradle会自动识别编译这个目录;buildSrc的执行顺序优先于childProject。

接下来就是实现:

3.2.1 初始化buildSrc
  • 创建buildSrc/main 目录

  • 创建 buildSrc/build.gradle.kts(当前dsl我是用的是kotlin,也可以使用groovy),添加以下内容:


plugins{
//    `kotlin-dsl`
//    `groovy`
    `java-gradle-plugin`
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

然后同步之后就可以看到:

![buildSrc tree][1]

注意:Gradle6.4以前需要依赖gradleApi(),之后的版本默认提供支持

3.2.2 创建开发目录以及plugin

在上一步应用的plugins中,有3中方案:

  • groovy
  • kotlin-dsl
  • java-library

三种plugin对应我们插件的3种实现语言,选择某一种语言,就要在main下创建对应的目录。

eg:我们当前选择java语言,那么使用java-library,随后就需要在创建buildSrc/main/src/java/目录

加入测试类:



public class JavaPlugin implements Plugin<Project> {
    @Override
    public void apply(Project target) {
        System.out.println("hello from javaPlugin ");
    }
}


eg:如果使用kotlin语言,即kotlin-dsl,就需要创建buildSrc/main/src/kotlin/目录

加入测试类:


class GreetingPlugin :Plugin<Project> {
    override fun apply(target: Project) {
        println("hello from kotlin plugin !")
    }
}

3.2.3 绑定plugin
  • 首先需要确定你的插件id,插件id:eg:com.example.plugin

  • 创建buildSrc/main/resources/META-INF/gradle-plugins/目录

  • 在该目录创建以你的id命名的文件:com.example.plugin.properties,

内容为:implementation-class=JavaPlugin

此处JavaPlugin对应你的插件的类名称

3.2.4 使用你的插件

在其它module build.gradle内:



plugins {
    id("com.android.library")
    //---应用我的插件
    id("com.example.plugin")
}

android {
    namespace = "com.avatr.support"
    compileSdk = 31
    defaultConfig {

        targetSdk = 31
        minSdk = 28
    }
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

dependencies {
    //使用我的插件内定义的三方库
    implementation(Libs.appCompat)
}

到这一步,我们插件已经很强大了,可以给项目的不同module使用,不同module都可以复用相同的逻辑,减少了很多不必要的配置

但是!还是不符合我们团队化使用,不能够在项目&&团队之间共享。

插入一个版本三方库管理方案:

便捷的版本管理方案

相信大家都碰到一个场景,一个项目里有多个module,module需要进行sdk版本管理,三方库管理,java版本等版本管理,每次创建一个新的module都需要花点时间配置一下。

通常的方案是项目根目录创建一个config.gradle,在ext里面统一声明这些内容,然后在build.gradle apply from config.gradle ,然后就可以引用ext里的内容。

在7.0以后,官方推出了一个版本管理方案,Version Catalogs,是一种新的依赖管理方式,其中一种是通过.toml文件定义所有依赖项和版本信息。这个方法的一个优点是能够集中管理所有依赖的版本,减少版本冲突的可能性。步骤如下

  • 在项目的根目录下创建一个名为dependencies.toml的.toml文件,定义依赖项。

# dependencies.toml

[dependencies]
appCompat = "com.android.support:appcompat-v7:28.0.0"
firebaseCore = "com.google.firebase:firebase-core:20.0.0"
# 添加更多依赖...

  • 在主项目的settings.gradle.kts文件中,指定Version Catalogs的位置:

// settings.gradle.kts

dependencyResolutionManagement {
    // 指定Version Catalogs的位置
    versionCatalogs {
        create("dependencies") {
            from("${rootProject.projectDir}/dependencies.toml")
        }
    }
}

  • 在module的build.gradle.kts文件中引用Version Catalogs,并使用其中的依赖项:

// build.gradle.kts

dependencies {
    // 使用Version Catalogs中的依赖项
    implementation dependencies.appCompat
    implementation dependencies.firebaseCore
    // 添加更多依赖...
}

这种方案优点非常明显,使用简单,非常适用于大型多module项目,轻松管理依赖,减少版本冲突,并且可以做到检测升级;小小的缺点就是需要一点小小的学习成本

我们的buildSrc也可以实现三方库版本管理,而且跟为方便。

以我们java语言为例

在buildSrc/src/main/java加入一个依赖管理类


public interface Libs {
    String appCompat = "androidx.appcompat:appcompat-resources:1.6.1";
}


gradle给的支持非常强大,你在编辑后面的库信息时,gradle可以自动提示;

  • 使用插件的三方库

在module的build.gradle


dependencies {
    implementation(Libs.appCompat)
}

这两步,非常简单由直观!

3.3 单独的plugin项目

第二种方案相较于第一种方案,已经灵活便捷很多了,但是这种方案仍然有弊端,它并不是一个独立的个体,而是依附在项目里,依赖项目整体的编译,这种方案适用于单个项目多个module的情况。

我们的目标是最大化的通用性,不仅要实现module之间,更是要在项目和团队之间共享,因此第二种方案还是不够,所以我们介绍第三种这种方案,也是官方推荐的方案,也是大家都采用的方案。

在单独的gradle plugin项目专注于plugin开发,不仅可以进行以上两种方案的实现,更是可以将插件单独发布(虽然第二种方案也可以),但是它具有独立性,专一性。

这一段不进行详细的讲解,详细的讲解将在实战片段讲解。

4.gradle plugin

4.1 初始化项目

初始化的方式可以用手动创建空项目,然后创建名为plugin的module,然后进行后续配置,但是Gradle 为gradle plugin开发提供了更为便捷的方案:

在你的workSpace打开终端:
在这里插入图片描述

4.2 明确需求

  • sdk、java版本配置

通常每一个module创建都会有相同的android sdk版本,java版本配置。

  • 公共的库依赖

例如单元测试,appCompat,网络等等

  • 特性配置

例如viewBinding等等。

4.3 实现sdk版本配置

抽象一个config类:


public interface IRocketConfig {

    /**
     * 
     * @param project 当前module
     * @param rootExtension 当前module应用的plugin:com.android.library/com.android.application
     */
    void applyConfig(Project project, IRootExtension rootExtension);
}


sdk版本配置实现类


public class VersionConfigImpl implements IRocketConfig {
    private static final String TAG = "[VersionConfigImpl]:";

    @Override
    public void applyConfig(Project project, IRootExtension extension, BoosterPlatformConfig platformConfig) {
        System.out.println(TAG + "start apply common-version config >>>");

        //设置sdk版本号
        extension.setCompileSdkVersion(33);
        extension.getDefaultConfig().setMinSdkVersion(28);
        extension.getDefaultConfig().setTargetSdkVersion(33);
        extension.getDefaultConfig().testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner");
        //java 版本
        extension.getCompileOptions().setSourceCompatibility(JavaVersion.VERSION_11);
        extension.getCompileOptions().setTargetCompatibility(JavaVersion.VERSION_11);

    }
}


4.4 实现依赖配置

  • 实现一个三方库管理类
public interface RocketLibs {

    //------------------------------------------Base-------------------------------------------

    String androidTestRunner = "androidx.test:runner:" + LibsVersion.androidTestRunner;
    String jUnit = "junit:junit:" + LibsVersion.jUnit;
    String extjUnit = "androidx.test.ext:junit:" + LibsVersion.extjUnit;

    //------------------------------------------View-------------------------------------------

    String recyclerView = "androidx.recyclerview:recyclerview:" + LibsVersion.recyclerView;
    String appCompat = "androidx.appcompat:appcompat:" + LibsVersion.appCompat;
}



public interface LibsVersion {

    String androidTestRunner = "1.5.2";
    String espressoCore = "3.0.2";
    String jUnit = "4.12";

    String recyclerView = "1.3.0";
    String appCompat = "1.4.1";

 }

  • 实现三方库配置类:
public class DependenciesConfigImpl implements IRocketConfig Config {
    private static final String TAG = "[DependenciesConfigImpl]:";

    @Override
    public void applyConfig(Project project, IRootExtension rootExtension) {
        System.out.println(TAG + "start apply dependencies configs >>>");
        DependencyHandler dependencies = project.getDependencies();
        dependencies.add("androidTestImplementation", RocketrLibs.androidTestRunner);
        dependencies.add("androidTestImplementation", RocketLibs.espressoCore);
        dependencies.add("androidTestImplementation", RocketLibs.extjUnit);
        dependencies.add("testImplementation", BoosterLibs.jUnit);
//        dependencies.add("api", RocketLibs.commonUtilsAndroid);
        dependencies.add("api", RocketLibs.appCompat);
//        dependencies.add("api", RocketLibs.okHttp3);
//        dependencies.add("api", RocketLibs.recyclerView);
    }
}

4.5 特性配置


public class FeatureConfigImpl implements IRocketConfig {
    private static final String TAG = "[OtherConfigImpl]:";

    @Override
    public void applyConfig(Project project, IRootExtension extension, BoosterPlatformConfig config) {
        System.out.println(TAG + "start apply other config >>> ");
        //使用ViewBinding
        if (config != null && config.featureConfig != null) {
            extension.getViewBinding().setEnabled(true);
        }
    }
}

4.6 应用配置

在Plugin内应用上述的实现类

    @Override
    public void apply(Project project) {


        //找到BaseExtension,主要确定module是Application还是Library
        final RootExtensionDetector rootExtensionDetector = new RootExtensionDetector(project);
        final IRootExtension rootExtension = rootExtensionDetector.getRootExtension();

		//签名配置
        IRocketConfig signatureConfig = new SignatureConfigImpl();
        signatureConfig.applyConfig(project, rootExtension, mAllPlatformConfig);
		//sdk版本配置
        IRocketConfig versionConfig = new VersionConfigImpl();
        versionConfig.applyConfig(project, rootExtension, mAllPlatformConfig);
		//依赖配置
        IRocketConfig dependenciesConfig = new DependenciesConfigImpl();
        dependenciesConfig.applyConfig(project, rootExtension, mAllPlatformConfig);
		//特性配置
        IRocketConfig otherConfig = new FeatureConfigImpl();
        otherConfig.applyConfig(project, rootExtension, mAllPlatformConfig);
		//flavor配置
        IRocketConfig flavorConfig = new FlavorConfigImpl();
        flavorConfig.applyConfig(project, rootExtension, mAllPlatformConfig);

    }

以上是应用全部实现我们插件需求的配置类,不再一一展开

4.7 发布插件

我之前的一篇帖子讲过maven-publish 如何发布项目到maven

在plugin的builde.gradle内


//公司仓库地址
val mavenBaseUrl = "http://maven.example.company"
//发布到本地
val isPublish2Local = true;

//绑定plugin
gradlePlugin {
    // kotlin版本
    val gradleBooster by plugins.creating {
        id = "gradle-booster"
        implementationClass = "com.example.RoecktPlugin"
    }
}

//注册发布任务
publishing {
    repositories {
        //仓库配置
        maven {
            url = uri(
                //发布到本地
                if (isPublish2Local) {
                    "../../WilsonMaven/Dependency"
                } else {
                    //发布到远程仓库
                    "$mavenBaseUrl /repository/cockpit-snapshots/"
                }
            )
            //发布到公司maven需要配置密码
            if (!isPublish2Local) {
                credentials {
                    username = avatrMavenUserName
                    password = avatrMavenUserPW
                }
            }
        }
    }
    //发布版本信息
    publications {
        create<MavenPublication>("booster") {
            groupId = "com.example.company"
            //插件id,和上面绑定的插件一致
            artifactId = "gradle-rocket"
            //插件版本号
            version = "0.0.0"
            from(components["java"])
        }

    }
}



然后同步之后,右侧gradle task里面会出现“publish”的task,双击运行这个task,提示发布成功可以查看

查看配置的目录下:
在这里插入图片描述

5 使用插件

  • 其它应用内根目录build.gradle(或setting.gradle)引入插件仓库


allprojects {
    //给项目配置
    repositories {
        google()
        mavenCentral()
        maven {
            allowInsecureProtocol = true
            url = "../WilsonMaven/Dependency"
        }
    }
}

buildscript {
    //给gradle配置插件仓库
    repositories {

        maven {
            allowInsecureProtocol = true
            url = "../WilsonMaven/Dependency"
        }

    }

    dependencies {
        classpath("com.android.tools.build:gradle:7.1.2")
        //引入插件
        classpath group: "com.example.company", name: "gradle-rocket", version: "0.0.0"
    }
}

classpath group: "com.example.company", name: "gradle-rocket", version: "0.0.0" 就是引入了我们的插件,可以看出来一个完整的插件包括group,name(对应插件id),version 和插件配置的内容是一一对应的。

  • 在项目的app mudle 应用插件

import com.example.company.libs.RocketLibs

plugins {
    id("com.android.application")
    //应用插件
    id("gradle-rocket")
}

android {
    namespace = "com.example.company.app"
    defaultConfig {
        applicationId = "com.example.company.app"
        versionCode = 1
        versionName = "1.0"
    }

    dependencies {
        //使用插件内的三方库
        implementation(RocketLibs.fastJson)
    }

}


  • library级别module配置:
plugins {
    id("com.android.library")
    //---应用我的插件
    id("gradle-rocket")
}

android {
    namespace = "com.example.support"
}


是不是十分简洁!!!

我们的插件内已经帮我们做了sdk版本配置,java版本配置,签名混淆配置等等我们需要一一去配置的东西


到此,做为一个平台化的gradle插件,已经实现了很多便捷的功能,但是各位大佬仍然可以展开你的想想实现更多的配置,上面我还提到了签名配置 渠道包配置,由于代码量比较大,我并未贴代码,各位可以自行实现,如果有需要可以找我要代码。

扩展:可以看到上述实例代码,很多配置都是写死的,假如不同的团队有不同的配置怎么办呢,是不是可以本地配置一个json文件,然后插件初始化的时候读取进来,根据文件里的配置来配置项目呢,嘿嘿嘿

下一篇讲如何自定义扩展

参考:

gradle官方文档

gradle系列精讲

gradle插件与gradle版本对应关系 目录概念gradle插件版本配置(project build.gradle):gradle版本配置(gradle-wrapper.properties):对应关系gradle下载慢解决方案 概念 Android studio会不定时更新版本,而Android相关插件也会跟着更新,比如gradle插件版本更新.gradle我们知道是Android studio自动化构建工具,其中gradle插件用于构建,编译,打包.只要gradle插件有新版本,那么就会有一个或一些对应的gradle发行版本,若对应不上,就会 阅读详情

相关推荐

Gradle系列——Gradle插件(基于Gradle文档7.5)day3-2

ext{注意,这只能在本项目中使用,其他项目无法使用Gradle插件打包了可重用的构建逻辑片段,可用于许多不同的项目和构建。Gradle允许您实现自己的插件,因此您可以重用您的构建逻辑,并与他人共享。你可以用任何你喜欢的语言来实现Gradle插件,只要实现最终编译为JVM字节码要创建Gradle插件,您需要编写一个实现Plugin接口的类。当插件应用于项目时,Gradle会创建插件类的实例并调用实例的Plugin.apply()方法。doLast{doFirst{...

qq_51553982的博客 1971

【Android】组件化

组件化 1 Gradle 1.1 打印信息 Gradle构建工具,Groovy脚本语言基本Java做了拓展,Gradle = JDK + Groovy 新建工程,在app的build.gradle中,添加: println("hello gradle") 或 println "hello gradle" 同步时,在Build中可以看到打印出来的信息: > Configure project :app hello gradle > Configure project :library hell

qq_30885821的博客 3377

Gradle系列之自定义插件

Gradle系列之Groovy基础 Gradle系列之Gradle基础 Gradle系列之自定义插件 Android构建流程(Android Plugin)源码解析系列一:主流程 什么是插件 插件,我们都很容易理解,它就是一个工具,帮助我们执行某个功能。gradle的插件就是在gradle编译的过程中执行特定业务的工具。gradle中的插件很常见,我们开发Android应用的时候,都会用...

ScheduledThreadPoolExecutor原理源码解析 797

网络代理问题:Task :prepareKotlinBuildScriptModel UP-TO-DATE

错误代码如下 > Task :prepareKotlinBuildScriptModel UP-TO-DATE IOException: https://dl.google.com/android/repository/addons_list-3.xml java.net.ConnectException: Connection refused: connect IOException: https://dl.google.com/android/repository/addons_list-2.xm

临木的博客 1万+

Gradle核心思想(六)自定义Gradle插件的三种方式

相关文章 Gradle核心思想(一)为什么现在要用Gradle? Gradle核心思想(二)Gradle入门前奏 Gradle核心思想(三)Groovy快速入门指南 Gradle核心思想(四)看似无用,实则重要的Gradle Wrapper Gradle核心思想(五)通俗易懂的Gradle插件讲解 前言 在上一篇文章Gradle核心思想(五)通俗易懂的Gradle插件讲解中,我介绍了什么是Gra...

Android进阶三部曲 - 刘望舒 1847

自定义gradle插件

自定义gradle插件通过这个内容,我们能够解释一些在平时android开发中的一些困惑1.我们每次用到的android域从何而来?2.为什么在android域内设置一些属性,会在项目中生效 首先,因为用到gradle的大部分都是android开发者,我们来看一个project中的gradle脚本apply plugin: 'com.android.application'android {

悠悠吾心的专栏 1377

手把手带你自定义 Gradle 插件 —— Gradle 系列(2)

Gradle 本质上是高度模块化的构建逻辑,便于重用并与他人分享。例如,我们熟悉的 Android 构建流程就是由 Android Gradle Plugin 引入的构建逻辑。在这篇文章里,我将带你探讨 Gradle 插件的使用方法、开发步骤和技巧总结。

pengxurui的博客 1320

Android SDK Tools

Android SDK "Failed to fetch URL https://dl-ssl.google.com/android/repository/repository.xml"问题处理文件

gradle build finished 之后还一直_SpringBoot 2.4.0 Gradle构建系列之三

SpringBoot 2.4.0 Gradle使用插件去掉POJO的Getter和Setter方法编者: wRitchie(吴理琪) 来源:http://www.bj9420.comSpringBoot2.4.0项目采用Grale构建,插件MyBatis Generator是一个Mybatis工具项目,用于生成Mybatis的Model、Mapper、Dao持久层的代码,而使用lombok插件,对...

weixin_34642354的博客 494

【重磅更新】CT/MRI LI-RADS 2024:肝细胞癌局部区域治疗后反应评估的核心突破与临床实践指南

减少过度治疗:辐射 LRT 的 Nonprogressing 类别避免了 “持续强化 = 存活” 的误判,降低不必要的再治疗风险;提高检出效率:非辐射 LRT 的辅助特征升级减少了 Equivocal 比例,更早识别存活肿瘤;统一评估语言:标准化的分类标准为放射科、肝病科、肿瘤科、肝移植科的多学科协作(MDT)提供了统一 “沟通工具”,助力治疗方案的精准制定。

楚山之石的博客 1224

【GIS效率手册】告别C盘爆满:三步重置ArcMap默认地理数据库路径

本文针对ArcMap用户C盘空间常被占满的问题,提供了三步重置默认地理数据库路径的详细教程。通过修改地图文档属性,将数据存储位置从C盘迁移至其他驱动器,不仅能有效释放系统盘空间,还能提升数据管理效率与安全性,是GIS数据规范化管理的关键一步。

g2h3i4j5的博客 542

Android Gradle和Gradle插件区别

引言 什么是Gradle?什么是Gradle插件? build.gradle中依赖的classpath 'com.android.tools.build:gradle:2.1.2'和gradle-wrapper.properties中的distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip有什

jinrall的专栏 1万+

鱼眼双目测距实战:从OpenCV标定到SGBM匹配的完整流程解析

本文详细解析了鱼眼双目测距的完整流程,从OpenCV标定到SGBM匹配,涵盖标定、校正、匹配和测距四个关键阶段。通过实战经验分享,帮助开发者解决鱼眼镜头强畸变带来的测距挑战,提升测距精度至5%以内。特别适合机器人导航、自动驾驶和VR领域的开发者参考。

weixin_27298377的博客 122

Gradle理论与实践四:自定义Gradle插件

文章目录Gradle插件1、Java Gradle插件2、Android Gradle插件2.1、应用Android Gradle插件 Gradle插件 Gradle可以认为是一个框架,负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译 Java 有 Java 插件,编译 Groovy 有 Groovy 插件,编译 Android APP 有 Android APP 插件,编...

小马快跑的博客 8956

【生信】全基因组测序(WGS)

1、全基因组测序(WGS) 的定义 2、GWS流程 2.1准备工作——分析软件 2.2原始数据质控 2.3数据预处理 2.4变异检测

weixin_40695088的博客 4万+

TPS5430/54302调试血泪史:从‘烫手山芋’到冒烟烧板,我的5V电源到底怎么了?

本文深入剖析了TPS5430/TPS54302 DCDC电源芯片调试中的常见问题,包括异常发热、电压漂移等,并提供了从热设计到PCB布局的全面解决方案。通过实战案例,揭示了数据手册中未明确的‘潜规则’,帮助工程师避免烧板风险,提升电源系统稳定性。

weixin_28744423的博客 499

【Gradle 多模块系列3】如何开发自定义Gradle插件

Gradle插件是**封装可重用的构建逻辑**的一种方式,可以**在许多不同的项目和构建中**使用。Gradle允许您**实现自己的插件,以便重用您的构建逻辑**,并与他人共享。

wang2leee的博客 1406

Golang实现企业级AI智能体安全合规自动化检测系统

需求:自动化解析欧盟AI法案、中国网络安全法、美国NIST框架等多国法规,提取具体合规要求并映射到企业技术实现。技术挑战法规文本非结构化,语义复杂,存在大量法律术语与技术术语交叉多语言支持(中文、英文、欧盟24种官方语言)法规动态更新(平均每季度更新2-3次)架构创新性:提出了"规则引擎+AI模型+实时监控"的混合架构,兼顾了合规要求的明确性与智能体行为的动态性。性能突破:通过Golang协程、多级缓存、数据库优化等技术,实现了12,800 req/s的高吞吐量和38ms的低延迟。准确性提升。

shao.bing的专栏 721

自定义Android Gradle插件

转载请注明出处:https://blog.csdn.net/binbinqq86/article/details/81033746 前言 gradle插件可以帮助我们干很多事情,类似一个工具,可以根据你自己想要的效果去定制自己的插件,本文就讲解一下怎么去实现自己的一个插件。根据官网描述,自定义插件一共有三种方式: Build script——gradle文件,构建脚本内,不过这种只能在文件内使用 buildSrc project——buildSrc工程,可以在自己的工程内随意使用,但是其他工程就无法使

Water的博客 5536

Matlab实现雷达波位编排

1 简介 %本程序用于雷达球坐标系到正弦空间坐标系的转换,以及相控阵雷达的波位编排。 2 完整代码 ​%070228添加波位数据保存clear allclose allclc%波束宽度,单位:度BeamWidth = 3.6;theta05 = round(sin(BeamWidth*pi/180)*1000)/1000;%雷达作用空域AZ = [-15 15]; %方位角范围(雷达球坐标系),单位:度EL = [0 30]; %俯仰角范围(雷

qq_59747472的博客 2478

第1集:认识 Claude Code —— AI 编程新纪元

1. 定义 Claude Code:终端中的 AI 编程代理Claude Code 是 Anthropic 公司于 2025 年 5 月正式推出的命令行 AI 编程工具,它不只是一个代码补全工具,而是一个能够理解项目、自主执行任务的**终端 AI 代理(Agent)。它的核心理念是 **"生于终端,活于终端"** (lives in your terminal)。与深度嵌入图形界面(GUI)的工具不同,Claude Code 选择直接融入开发者最原始、最核心的工作环境——命令行。

dianziyao_的博客 864

自定义 Gradle 插件

Android 中许多优秀的开源框架都会自定义 Gradle 插件,比如,热修复的 Tinker 。所以,这篇文章记录 Android Studio 中如何自定义 Gradle 插件。GradleGradle 是个的构建工具,也是Android Studio 默认的构建工具,与传统的 Ant 、maven 相比,Gradle 更加强大。利用 Gradle 这个工具,我们能做很多事情,例如热修复、插件

Deemons's Blog 2306

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

gradle自定义插件

插件实现方式解释说明buildScript脚本把插件写在build.gradle文件中,一般用于简单的逻辑,只在该build.grade文件可见buildSrc目录将插件源代码放在buildSrc/src/main中,只对该项目可见独立项目个独立的Java项目/模块,可以将文件包发布到仓库(Jecenter,Maven),使其他项目方便引入比如说新建一个Library。

qq_38056514的博客 1527

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Gradle自定义插件编写

Gradle 简介 Gradle是一个基于JVM的构建工具,它提供了: 像Ant一样,通用灵活的构建工具 可以切换的,基于约定的构建框架 强大的多工程构建支持 基于Apache Ivy的强大的依赖管理 支持maven, Ivy仓库 支持传递性依赖管理,而不需要远程仓库或者是pom.xml和ivy.xml配置文件。 对Ant的任务做了很好的集成 基于Groovy,build脚本使用Groovy编写...

huchao_lingo的博客 2339

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Gradle系列之Gradle插件

阅读本文之前可以先阅读同系列文章: Gradle系列之初识Gradle Gradle之Groovy基础篇 Gradle系列之构建脚本基础 Gradle系列之认识Gradle任务 Gradle 内置了很多常用的插件,Gradle 中的插件可在一定的场景中可以帮助我们提高开发效率,可以通过扩展现有的插件来实现更多功能,比如 Android Gradle 插件就是基于内置的 Java 插件来实现的。...

躬行之 756
上一篇: maven-publish 如何发布项目到maven
下一篇: Android插件化原理(三)——加载插件资源
cry kid
博客等级 码龄10年 144粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值