【Android gradle】自定义一个android gradle插件之buildSrc

news/2024/5/20 5:08:18 标签: android, gradle

文章目录

  • 1. 前言
  • 2. 简单使用
  • 3. 其余用法
    • 3.1 依赖&版本管理
    • 3.2 插件版本自增
    • 3.3 其余
  • 4. 链接

1. 前言

在【Android gradle】自定义一个android gradle插件,并发布到私有Artifactory仓库这篇文章中介绍了定义一个gradle插件,然后发布到远程或者本地仓库,最后在项目中使用的流程。但实际上还是过于复杂化了。对于自己的项目工程来说,我们希望简化这个流程,而buildSrc这个目录就运应而生了。

2. 简单使用

在项目目录下执行下面的操作:

# 1. 创建buildSrc目录,当然也可以用下面的命令来创建多个
mkdir buildSrc

首先,根据你自己期望的java或者groovy语言来创建目录:

# 2. 插件源代码目录
mkdir buildSrc\src\main\java

然后同步一下项目,可以看见这个目录就被识别了:
在这里插入图片描述
然后在其下创建对应的Plugin实现类以及对应的Task,比如:

public class HelloPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {
        project.getTasks().create("firstTask", FirstTask.class);
    }
}

public class FirstTask extends DefaultTask {

    @TaskAction
    void doSomething() {
        getProject().getLogger().warn("=========> firstTask:doSomething...");
    }
}

然后,类似的我们需要在resources目录下创建META-INF/gradle-plugins两级目录,然后创建对应的自己定义的插件名.properties文件(完整路径:buildSrc/src/main/resources/META-INF/gradle-plugins/sample.properties),其中做关联:

implementation-class=com.mengfou.HelloPlugin

最后就是在我们的项目的build.gradle中进行apply

apply plugin: 'com.mengfou.HelloPlugin'

再次同步后,就可以看到我们定义的firstTask
在这里插入图片描述
最后可以通过执行这个task来看看是否定义成功:

gradlew firstTask

在这里插入图片描述

可以看见就执行了。而且这个过程中我们并没有添加:

import org.gradle.api.Plugin;
import org.gradle.api.Project;

等相关的依赖,这里却可以很方便的使用,较上一篇文中的定义插件的方式确实方便了很多。

3. 其余用法

3.1 依赖&版本管理

比如我们可以使用buildSrc来管理依赖,比如我们可以定义一个Deps.java的文件来进行依赖的版本管理,在这个新建的demo工程的app模块的build.gradle文件中有这些依赖:

dependencies {

    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

我们可以将其进行改造,即:

public class Deps {
    public static final String appCompat = "androidx.appcompat:appcompat:1.3.0";
    public static final String material = "com.google.android.material:material:1.4.0";
    public static final String constraintLayout = "androidx.constraintlayout:constraintlayout:2.0.4";
    public static final String junit = "junit:junit:4.13.2";
    public static final String ext_junit = "androidx.test.ext:junit:1.1.3";
    public static final String espresso = "androidx.test.espresso:espresso-core:3.4.0";
}

然后同步一下,最终我们在build.gradle中可直接导包后使用:

import com.mengfou.deps.Deps
dependencies {
    implementation Deps.appCompat
    implementation Deps.material
    implementation Deps.constraintLayout
    testImplementation Deps.junit
    androidTestImplementation Deps.ext_junit
    androidTestImplementation Deps.espresso
}

3.2 插件版本自增

为了更方便的管理(自增)发布插件/aar/apk的版本,我们可以写一个插件做一个简单的版本管理。可以简单定义一个修改文件名的Task

public class ApkVersionTask extends DefaultTask {
    private Project mProject;
    private String mVariant;

    @TaskAction
    public void modifyFileName() {
        AppExtension appExtension = mProject.getExtensions().getByType(AppExtension.class);
        for (ApplicationVariant applicationVariant : appExtension.getApplicationVariants()) {
            if(mVariant.equals(applicationVariant.getName())) {
                try {
                    String stringBuilder = mProject.getBuildDir().getAbsolutePath() +
                            File.separator +
                            "outputs" +
                            File.separator +
                            "apk" +
                            File.separator +
                            applicationVariant.getBuildType().getName();
                    File parent = new File(stringBuilder);
                    for (File file : Objects.requireNonNull(parent.listFiles())) {
                        if (file.getName().endsWith(".apk")) {
                            File outputNewFile = new File(parent, "mengfou-" + getConfigVersion() + "-" + mVariant.toLowerCase() + ".apk");
                            file.renameTo(outputNewFile);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private String getConfigVersion() {
        try {
            File file = new File(mProject.getBuildFile().getParent(), "versions.properties");
            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int len = -1;
            StringBuilder stringBuffer = new StringBuilder();
            while((len = fileInputStream.read(buffer)) != -1) {
                stringBuffer.append(new String(buffer, 0, len));
            }
            if(stringBuffer.toString().trim().length() != 0) {
                String[] split = stringBuffer.toString().split("=");
                if(split.length == 2 && split[0].equals("apk-version")) {
                    return split[1];
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "empty";
    }

    public void setProject(Project project) {
        mProject = project;
    }

    public void setVariant(String variant) {
        mVariant = variant;
    }
}

getConfigVersion为从app/versions.properties文件中读取一个apk-version的配置,即:

apk-version=1.2.0

然后我们需要做的就是将ApkVersionTask插入到插件的合适的位置中去,通过命令:

>gradlew assemDeb --console=plain --stacktrace

可以看见最终执行的task

> Task :app:packageDebug
> Task :app:createDebugApkListingFileRedirect
> Task :app:assembleDebug

所以我们只需要将自定义的Task放置在packageDebug之后,assembleDebug之前即可。

public class HelloPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {
        AppExtension appExtension = project.getExtensions().getByType(AppExtension.class);
        project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                for (ApplicationVariant applicationVariant : appExtension.getApplicationVariants()) {
                    System.out.println("applicationVariant is: " + applicationVariant.toString());
                    try {
                        ApkVersionTask apkVersionTask = project.getTasks().create(getTaskName("reName", "Apk", applicationVariant.getName()), ApkVersionTask.class);
                        apkVersionTask.setProject(project);
                        apkVersionTask.setVariant(applicationVariant.getName());

                        Class<? extends ApplicationVariantImpl> aClass = ((ApplicationVariantImpl) applicationVariant).getClass();
                        Method variantData = aClass.getDeclaredMethod("getVariantData");
                        variantData.setAccessible(true);
                        BaseVariantData baseVariantData = (BaseVariantData) variantData.invoke(applicationVariant);

                        Task packageTask = project.getTasks().findByName(baseVariantData.getTaskContainer().getPackageAndroidTask().getName());
                        Task createApkListingFileRedirectTask = project.getTasks().findByName(getTaskName("create", "ApkListingFileRedirect", applicationVariant.getName()));
                        apkVersionTask.dependsOn(packageTask);
                        apkVersionTask.dependsOn(createApkListingFileRedirectTask);
                        Task assembleTask = project.getTasks().findByName(getTaskName("assemble", "", applicationVariant.getName()));
                        assembleTask.dependsOn(apkVersionTask);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    public String getTaskName(String prefix, String suffix, String variantName) {
        String name = variantName.substring(0, 1).toUpperCase() + variantName.substring(1);
        return prefix + name + suffix;
    }

}

运行后:
在这里插入图片描述
可以看见达到了预期。

3.3 其余

待填坑…

4. 链接

代码地址:https://gitee.com/weizu_cool/gradle-plugin-demo.git


http://www.niftyadmin.cn/n/27020.html

相关文章

【JavaSE】数据类型与变量

数据类型与变量数据类型与变量1. 字面常量2. 数据类型3. 变量3.1 变量概念3.2 语法格式3.3.1 整型变量3.3.2 长整型变量3.3.3 短整型变量3.3.4 字节型变量3.3 浮点型变量3.4.1 双精度浮点型3.4.2 单精度浮点型3.4 字符型类型3.5 布尔型变量3.6 类型转换3.7.1 自动类型转换&…

[数据结构复习]自用大纲

内容多基于王道和李春葆《数据结构教程》&#xff0c;做复习提纲之用 基本内容回顾 顺序队 队列是线性表&#xff08;具有逻辑上的前驱后继关系&#xff09;。头插尾删&#xff0c;先进先出。 队列的实现至少需要维护如下内容&#xff08;一数组&#xff0c;二指针&#xff…

一灯大师,基于imx6ull点亮LED灯

一.imx6ull GPIO原理1. STM32 GPIO回顾我们一般拿到一款全新的芯片&#xff0c;第一个要做的事情的就是驱动其 GPIO&#xff0c;控制其 GPIO 输出高低电平&#xff0c;我们学习 I.MX6U 也一样的&#xff0c;先来学习一下 I.MX6U 的 GPIO。在学习 I.MX6U的 GPIO 之前&#xff0c…

Python asyncio异步编程简单实现

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容是Python asyncio异步编程简单实现。 一、asyncio事件循环简介 asyncio引入了事件循环的概念。事件循环是一个死循环&#xff0c;还循环会检测并执行某些代码。在Python中&#xff0c;引入了asyncio模块后&#xff…

C++STL之vector的模拟实现

由于vector和string的接口使用方法类似&#xff0c;这里便不再详细讲解vector各种接口的使用了&#xff0c;可以参考之前所发布的string的使用&#xff0c;或者从官方文档中获取详细的使用方法. 目录 vector介绍 构造函数&#xff08;有参&#xff0c;无参&#xff0c;迭代器…

Debian 命令行配置网络并切国内源

背景 因为debian11 连网安装非常的久&#xff0c;我又不太清楚在安装程序中切换国内的源。于是我就断网安装。安装完了默认是没有网的&#xff0c;于是就要命令中配置网络了。 配置 一、对于有线网络&#xff0c;如果默认没有安装图形界面&#xff0c;进入了 multi-user.tar…

【文件操作】C语言

目录1. 为什么使用文件2. 什么是文件2.1 程序文件2.2 数据文件2.3 文件名3. 文件的打开和关闭3.1 文件指针3.2 文件的打开和关闭4. 文件的顺序读写5. 文件的随机读写5.1 fseek5.2 ftell5.3 rewind6. 文本文件和二进制文件7. 文件读取结束的判定8. 文件缓冲区1. 为什么使用文件 …

PyTorch实例3——迁移学习

传送门&#xff1a;蓝桥云课实验 目录1. 实验环境2. 实验目的3. 相关原理4. 实验步骤4.1 数据收集4.1.1加载数据4.1.2 GPU运算4.2 数据预处理4.3 创建模型4.3.1 构建迁移模型4.3.2 训练模型测试绘制图表4.3.2.1 预训练模式4.3.2.2 固定值模式4.4 结论1. 实验环境 Jupyter Note…