FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • AndroidUI

  • Android第三方SDK

  • Android混淆

  • Android仓库

  • Android新闻

  • Android系统开发

  • Android源码

  • Android注解AOP

  • Android脚本

    • Gradle入门系列(一) - groovy基础语法
    • Gradle入门系列(二) - groovy高级语法
    • Gradle入门系列(三) - 初识Gradle与Project
    • Gradle入门系列(四) - 初识Gradle Task
    • Gradle入门系列(五) - Gradle其它模块与Plugin插件
      • Gradle 其它模块
        • 一、Settings 类
        • 二、SourceSet 类
      • Gradle Plugin
        • 一、Gradle 插件(Plugin)是什么
        • 二、自定义 Plugin
        • 三、android 插件对 gradle 扩展
    • Android脚本 - 不一样的Gradle多渠道配置总结
    • Android脚本 - 不一样的Gradle多渠道配置总结2
  • AndroidTv开发

  • AndroidNDK

  • Android音视频

  • Android热修复

  • Android性能优化

  • Android云游戏

  • Android插件化

  • iOSUI

  • iOS工具

  • iOS底层原理与应用

  • iOS组件化

  • iOS音视频

  • iOS疑难杂症

  • iOS之Swift

  • iOS之RxSwift

  • iOS开源项目

  • iOS逆向

  • Flutter开发

  • 移动端
  • Android脚本
GitLqr
2019-01-05
目录

Gradle入门系列(五) - Gradle其它模块与Plugin插件

欢迎关注微信公众号:[FSA全栈行动 👋]

# Gradle 其它模块

# 一、Settings 类

settings.gradle(对应 Settings.java)决定哪些工程需要被 gradle 处理,占用了整个 gradle 生命周期的三分之一,即 Initialzation 初始化阶段。

# 二、SourceSet 类

对默认的文件位置进行修改,从而让 gradle 知道哪种资源要从哪些文件夹中去查找。

// sourceSets是可以调用多次的
android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
    sourceSets {
        main {
            res.srcDirs = ['src/main/res',
                           'src/main/res-ad',
                           'src/main/res-player']
        }
    }
}

// sourceSets一般情况下是一次性配置
android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
            res.srcDirs = ['src/main/res',
                           'src/main/res-ad',
                           'src/main/res-player']
        }
    }
}

// 使用编程的思想,配置sourceSets
this.android.sourceSets{
    main {
        jniLibs.srcDirs = ['libs']
        res.srcDirs = ['src/main/res',
                       'src/main/res-ad',
                       'src/main/res-player']
    }
}

# Gradle Plugin

# 一、Gradle 插件(Plugin)是什么

Gradle 中的 Plugin 是对完成指定功能的 Task 封装的体现,只要工程依赖了某个 Plugin,就能执行该 Plugin 中所有的功能,如:使用 java 插件,就可以打出 jar 包,使用 Android 插件,就可以生成 apk、aar。

# 二、自定义 Plugin

# 1、创建插件工程

  1. 在工程目录下创建 buildSrc 文件夹。
  2. 在 buildSrc 目录下,创建 src 文件夹、build.gradle 文件。
  3. 在 buildSrc/src 目录下,再创建 main 文件夹。
  4. 在 buildSrc/src/main 目录下,再分别创建 groovy、resources 文件夹。
  5. 在 buildSrc/src/main/resources 再创建一个 META-INF 文件夹,再在 META-INF 下创建一个 gradle-plugins 文件夹。
  6. 在 build.gradel 文件中输入如下脚本:
apply plugin: 'groovy'

sourceSets {
    main {
        groovy {
            srcDir 'src/main/groovy'
        }
        resources {
            srcDir 'src/main/resources'
        }
    }
}

最后,Async 一下工程,buildSrc 就会被识别出来了,整体目录如图:

# 2、创建插件类

与 java 一样,在 groovy 目录下,创建一个包,再创建一个插件类(如:com.lqr.gradle.study.GradleStudyPlugin),该插件类必须实现 Plugin<Project>接口。

注意:gradle 插件类是.groovy 文件,不是.java 文件

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

/**
 * 自定义Gradle插件
 */
class GradleStudyPlugin implements Plugin<Project> {

    /**
     * 插件引入时要执行的方法
     * @param project 引入当前插件的project
     */
    @Override
    void apply(Project project) {
        println 'hello gradle study plugin. current project name is ' + project.name
    }
}

# 3、指定插件入口

在编写完插件类的逻辑之后,需要在 META-INF.gradle-plugins 目录下创建一个 properties 文件(建议以插件类包名来命名,如:com.lqr.gradle.study.properties),在该 properties 中声明插件类,以此来指定插件入口。

该 properties 文件的名字将作为当前 gradle 插件被 app 工程引用的依据。

implementation-class=com.lqr.gradle.study.GradleStudyPlugin
// 如果报错 Could not find implementation class 'xxx' 的话,一般是类全路径有问题,默认包不需要写包路径,修改如下即可:
// implementation-class=GradleStudyPlugin

# 4、使用自定义插件

打开 app 工程的 build.gradle,应用上面的自定义 gradle 插件,并 Async。

apply plugin: 'com.android.application'
apply plugin: 'com.lqr.gradle.study'

android {
  ...
}

可以看到,在 gradle 的配置阶段,就输出了前面自定义插件的 apply 方法中的日志。

# 5、创建扩展属性

插件往往会在 gradle 脚本中进行参数配置,如在 android{}中,可以配置 compileSdkVersion 等参数,其实本质上,就是在 gradle 脚本中使用闭包方式创建了一个 javaBean,并将其传递到插件中被插件识别读取而已。步骤如下:

1)创建一个实体类,声明成员变量,用于接收 gradle 中配置的参数。(可以理解为就是 javaBean,不过要注意,该文件后缀是.groovy,不是.java)

class ReleaseInfoExtension {
    String versionCode
    String versionName
    String versionInfo
    String fileName

    ReleaseInfoExtension() {}

    @Override
    String toString() {
        return "versionCode = ${versionCode} , versionName = ${versionName} ," +
                " versionInfo = ${versionInfo} , fileName = ${fileName}"
    }
}

2)在自定义插件中,对当前 project 进行扩展。

class GradleStudyPlugin implements Plugin<Project> {

    /**
     * 插件引入时要执行的方法
     * @param project 引入当前插件的project
     */
    @Override
    void apply(Project project) {
        // 这样就可以在gradle脚本中,通过releaseInfo闭包来完成ReleaseInfoExtension的初始化。
        project.extensions.create("releaseInfo", ReleaseInfoExtension)
    }
}

3)打开在 app 工程的 build.gradle,通过扩展 key 值命名闭包的方式,就可以配置指定参数了。

apply plugin: 'com.lqr.gradle.study'

releaseInfo {
    versionCode = '1.0.0'
    versionName = '100'
    versionInfo = '第一个app信息'
    fileName = 'release.xml'
}

4)接收参数,如:

def versionCodeMsg = project.extensions.releaseInfo.versionCode

# 6、创建扩展 Task

自定义插件无非就是封装一些常用 Task,所以,扩展 Task 才是自定义插件的最重要的一部分。

扩展 Task 也很简单,继承 DefaultTask,编写 TaskAction 注解方法,下面以 “把 app 版本信息写入到 xml 文件中”的 task 为例,注释很详细,不多赘述:

import groovy.xml.MarkupBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class ReleaseInfoTask extends DefaultTask {

    ReleaseInfoTask() {
        group 'lqr' // 指定分组
        description 'update the release info' // 添加说明信息
    }

    /**
     * 使用TaskAction注解,可以让方法在gradle的执行阶段去执行。
     * doFirst其实就是在外部为@TaskAction的最前面添加执行逻辑。
     * 而doLast则是在外部为@TaskAction的最后面添加执行逻辑。
     */
    @TaskAction
    void doAction() {
        updateInfo()
    }

    private void updateInfo() {
        // 获取gradle脚本中配置的参数
        def versionCodeMsg = project.extensions.releaseInfo.versionCode
        def versionNameMsg = project.extensions.releaseInfo.versionName
        def versionInfoMsg = project.extensions.releaseInfo.versionInfo
        def fileName = project.extensions.releaseInfo.fileName
        // 创建xml文件
        def file = project.file(fileName)
        if (file != null && !file.exists()) {
            file.createNewFile()
        }
        // 创建写入xml数据所需要的类。
        def sw = new StringWriter();
        def xmlBuilder = new MarkupBuilder(sw)
        // 若xml文件中没有内容,就多创建一个realease节点,并写入xml数据
        if (file.text != null && file.text.size() <= 0) {
            xmlBuilder.releases {
                release {
                    versionCode(versionCodeMsg)
                    versionName(versionNameMsg)
                    versionInfo(versionInfoMsg)
                }
            }
            file.withWriter { writer ->
                writer.append(sw.toString())
            }
        } else { // 若xml文件中已经有内容,则在原来的内容上追加。
            xmlBuilder.release {
                versionCode(versionCodeMsg)
                versionName(versionNameMsg)
                versionInfo(versionInfoMsg)
            }
            def lines = file.readLines()
            def lengths = lines.size() - 1
            file.withWriter { writer ->
                lines.eachWithIndex { String line, int index ->
                    if (index != lengths) {
                        writer.append(line + '\r\n')
                    } else if (index == lengths) {
                        writer.append(sw.toString() + '\r\n')
                        writer.append(line + '\r\n')
                    }
                }
            }
        }
    }
}

与创建扩展属性一样,扩展 Task 也需要在 project 中创建注入。

/**
 * 自定义Gradle插件
 */
class GradleStudyPlugin implements Plugin<Project> {

    /**
     * 插件引入时要执行的方法
     * @param project 引入当前插件的project
     */
    @Override
    void apply(Project project) {
        // 创建扩展属性
        // 这样就可以在gradle脚本中,通过releaseInfo闭包来完成ReleaseInfoExtension的初始化。
        project.extensions.create("releaseInfo", ReleaseInfoExtension)
        // 创建Task
        project.tasks.create("updateReleaseInfo", ReleaseInfoTask)
    }
}

再次 Async 工程之后,就可以在 Idea 的 gradle 标签里看到自定义好的 Task 了。

以上就是自定义 gradle 插件的核心内容了,但是,这种在工程下直接创建 buildSrc 目录编写的插件,只能对当前工程可见,所以,如果需要将我们自定义好的 grdle 插件被其他工程所使用,则需要单独创建一个库工程,并创建如 buildSrc 目录下所有的文件,最后上传 maven 仓库即可,这部分可自行百度了解。

# 三、android 插件对 gradle 扩展

译者序 | Gradle Android 插件用户指南翻译 (opens new window)

Manipulation tasks(操作 task) | Gradle Android 插件用户指南翻译 (opens new window)

自定义 Apk 输出位置:

this.afterEvaluate {
  this.android.applicationVariants.all { variant ->
    def output = variant.outpus.first() // 获取变体输出文件(outputs返回是一个集合,但只有一个元素,即输出apk的file)
    def apkName = "app-${variant.baseName}-${variant.versionName}.apk"
    output.outputFile = new File(output.outputFile.parent, apkName)
  }
}

variant.baseName : baidu-release variant.name : baiduRelease

#脚本#Gradle
Gradle入门系列(四) - 初识Gradle Task
Android脚本 - 不一样的Gradle多渠道配置总结

← Gradle入门系列(四) - 初识Gradle Task Android脚本 - 不一样的Gradle多渠道配置总结→

最近更新
01
Flutter - Xcode16 还原编译速度
04-05
02
AI - 免费的 Cursor 平替方案
03-30
03
Android - 2025年安卓真的闭源了吗
03-28
更多文章>
Theme by Vdoing | Copyright © 2020-2025 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×