添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

自定义Gradle二进制插件

二进制插件

我们出于自己的目的,要开发实际业务场景的插件来辅助项目构建。 自定义二进制插件,可以使用 java,kotlin,或者 groovy 来编码,因为他们都是基于JVM的编程语言,最终都会生成class交给JVM去执行。groovy提供了更多插件相关的api,有一些情况用groovy能直接达成效果,而不需要去引入其他类库。

以kotlin为例:

创建一个java library

每个androidStudio版本的操作界面可能各不相同,这是 Android Studio Electric Eel | 2022.1.1 Patch 2 版本的截图。

引入 必要的 依赖

包括两部分,一个是gradleApi,必须引入。

另外就是其他的,我们编写编码需要用到的其他依赖库,比如 发送网络请求的 okhttp,生成二维码的zxing ,接入华为云的 obs等等。

plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm'  // kotlin依赖
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation gradleApi() // 必须的gradle依赖
    // 引入其他工具类库
    implementation 'com.squareup.okhttp3:okhttp:3.14.6' // 使用最新版okhttp居然无法引用,很诡异
    implementation 'com.huaweicloud:esdk-obs-java-bundle:3.21.8' // 引入 华为云
    implementation 'com.google.zxing:core:3.4.1' // 二维码生成器
    implementation 'org.springframework:spring-core:2.5.6'
    implementation 'net.dongliu:apk-parser:2.5.3' // apk解析工具

新建一个Project实现类

import com.android.build.gradle.AppExtension
import com.tw.lib.bean.AutoUploadBean
import org.gradle.api.Plugin
import org.gradle.api.Project
class AutoUploadPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        println("======== 自动上传插件初始化 =========")
        // 配置外来参数, 表示插件的使用者可以在gradle文件中写 相关的参数
        val autoUploadBean = project.extensions.create("autoUpload", AutoUploadBean::class.java)
        project.afterEvaluate {
            val appExtension = it.extensions.getByType(AppExtension::class.java)
            appExtension.applicationVariants.all { v ->
                v.outputs.all { out ->
                    val file = out.outputFile // 输出的apk文件
                    val name = out.name
                    project.tasks.create(
                        "auto_upload_$name",
                        AutoUploadTask::class.java,
                        file,
                        autoUploadBean

比如上面我要做一个实现自动上传的插件 AutoUploadPlugin ,它必须实现

Plugin<Project>接口,并实现其中的apply方法。方法内部写上你要做的操作。

一个project是由多个Task组合而成,下面的代码中,我我在apply方法中创建了一个名叫 autoUpload的 额外参数,并创建了一个名为 AutoUploadTask的 任务。

创建 AutoUploadTask 任务

public class AutoUploadTask extends DefaultTask {
    private File file;
    private final AutoUploadBean autoUploadBean;
    @Inject
    public AutoUploadTask(File file, AutoUploadBean autoUploadBean) {
        setGroup("autoUpload");
        this.file = file;
        this.autoUploadBean = autoUploadBean;
    @TaskAction
    public void action() throws IOException {
        System.out.println("做你想做的事情");

这里有一些要素必须提到,

首先,setGroup是自定任务的分组,这个分组最终会呈现在androidStudio右侧的gradle面板中。

其次,步骤3中执行了这么一段代码:

                    project.tasks.create(
                        "auto_upload_$name",
                        AutoUploadTask::class.java,
                        file,
                        autoUploadBean

这其实是在反射创建 AutoUploadTask对象,后面的file和autoUploadBean其实就是入参,所以我们必须提供一个带这两个参数的构造函数。

最后,在接收到 file和 autoUploadBean 外来参数之后,我们可以在 重写的action方法中使用它们来完成我们自己想要的的操作。

AutoUploadBean类的内容为:

open class AutoUploadBean {
    // 华为OBS账号
    var userName: String? = null
    // 华为OBS密码
    var pwd: String? = null
    // 华为OBS桶
    var domain: String? = null
    // 是否使用分段上传
    var usePartUpload: Boolean = false
    // 下载二维码的输出目录
    var buildRootDir: String? = null

到这里,插件基本上就编写完成了。

每一个插件都有全局唯一一个 id ,这个id注册在 /src/main/resources/META-INF/gradle-plugins中,我们在 这个目录下,创建一个 自定义名称的com.tw.autoUpload.properties文件,自定义的名称就是我们插件的唯一ID,文件内容为:implementation-class=com.tw.lib.AutoUploadPlugin ,也就是我们自定义Plugin的全类名。

在 要使用插件模块的build.gradle中

apply plugin:'com.tw.autoUpload'
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android' 
    id 'com.tw.autoUpload'  // 使用插件

并且指定插件的额外参数:

autoUpload {
    userName 'c00293388'
    pwd 'Wd2A@zFJ1234'
    domain 'hwstaff_DigitalPayment'
    usePartUpload false
    buildRootDir 'C:\Users\zwx1245985\Desktop\saved'

执行插件任务

至此完成,经过编译之后,我们就能在 任务分组 autoupload之下,使用 auto_upload任务去执行上传操作了。

插件的发布

发布二进制插件有两种方式,

发布到naven仓库

此处以 发布到localMaven为例说明:

编写发布脚本

在我们创建的java library的 build.gradle中,写入内容:

publishing {
    publications {
        AutoUploadPlugin(MavenPublication) {
            from components.java
            groupId 'com.tw'
            artifactId 'aotuUpload'
            version '1.0'

上面有4处需要我们做修改:

  • AutoUploadPlugin 这是自定义插件的名称,直接用 我们创建的继承 org.gradle.api.Plugin<Project>的类名
  • groupId 插件发布的群组
  • artifactId 群组下的插件名称
  • version 版本
  • 后面3项直接决定了插件的唯一性。

    建立mavenLocal环境

    在 本地建立localMaven环境(如何创建环境,看这里!www.jianshu.com/p/cb941c74a… ),然后执行 本工程的 publishToMavenLocal 命令,将它发布到本地maven仓库下。

    发布之后就是引用插件:

    buildscript {
        repositories {
            mavenLocal()
        dependencies {
            classpath 'com.tw:aotuUpload:1.0'
    

    随后的 apply plugin:'com.tw.autoUpload'之后的步骤就参照前文使用插件章节。

    直接引用jar包

    我们创建了一个 autoUploadPlugin 的java library ,在编译之后,module下会存在一个 jar包 autoUploadPlugin.jar, 它的效果和本地maven相同,只不过 引用的方式必须是在 build.gradle中:

    buildscript{
        dependencies {
            classpath files('lib/autoUploadPlugin.jar')
    

    同样,apply plugin:'com.tw.autoUpload' 之后的步骤也参照前文使用插件章节。

    Gradle插件

    纯gradle插件则简单很多,以下是一个简单案例:

    在app 目录下 创建一个 config.gradle 文件,内容为:

    ext {
        dependenciesx = [            appcompat          : [name: 'androidx.appcompat:appcompat', version: '1.6.1'],
                material           : [name: 'com.google.android.material:material', version: '1.8.1'],
                constraintlayout   : [name: 'androidx.constraintlayout:constraintlayout', version: '2.1.4'],
                navigation_fragment: [name: 'androidx.navigation:navigation-fragment', version: '2.5.3'],
                navigation_ui      : [name: 'androidx.navigation:navigation-ui', version: '2.5.3'],
                junit              : [name: 'junit:junit', version: '4.13.2'],
                junitx             : [name: 'androidx.test.ext:junit', version: '1.1.5'],
                espresso_core      : [name: 'androidx.test.espresso:espresso-core', version: '3.5.1'],
    

    其中放置了很多第三方依赖的 name 和 version

    apply from: "config.gradle"

    如果想把 config.gradle发布到远程(内网或外网)的话,

    则可以使用 apply from :"http://xxx.com/config.gradle" 的方式引入。

    dependencies {
        dependenciesx.each { dependencyName, dependency ->
            implementation "${dependency.name}:${dependency.version}"
    

    很简洁的三步走。

    两种方式的对比

    它们具有不同的优缺点,具体情况下可以根据项目的特点和需求来决定应该使用哪种方式。

    二进制插件(Binary Plugin):

  • 性能更好:二进制插件是使用 JVM 字节码编写的,因此它们通常比纯 Gradle 插件的脚本执行速度更快,尤其是对于大型项目来说。
  • 可以使用其他语言:二进制插件可以使用许多编程语言编写(如 Kotlin、Groovy、Java 等),因此你可以选择熟悉的语言来编写插件。
  • 开发复杂度高:二进制插件的开发需要实现插件的接口和声明插件的元数据。在一些简单的场景下,这可能会增加不必要的开发复杂性。
  • 部署和依赖管理稍复杂:使用二进制插件时,你需要构建插件并将其发布到仓库,然后才能在项目中引用并配置依赖关系。
  • 项目的规模和复杂度:对于较大、复杂的项目,二进制插件可能更适合,可以提供更好的性能和扩展性。
  • 开发资源和技能:如果你已经熟悉了 Groovy 或 Kotlin,那么纯 Gradle 插件可能更容易上手和开发。而如果你有其他语言的开发经验,二进制插件则提供了更多选择。
  • 部署和依赖管理的要求:如果你希望将插件发布到仓库并作为独立的模块使用,那么二进制插件是更合适的选择。而纯 Gradle 插件则更适合内部使用或作为项目本身的一部分。
  • 综上所述,二进制插件和纯 Gradle 插件各有优劣,选择哪种方式要根据具体项目的要求和约束来进行决策。

    全部评论
    天翼云科技有限公司
    校招火热招聘中
    官网直投

    相关推荐

    点赞 评论 收藏
    分享
    点赞 收藏 评论
    分享

    全站热榜

    正在热议
    # 应届生应该先就业还是先择业 #
    25285次浏览 182人参与
    # 你最近一次加班是什么时候? #
    12631次浏览 109人参与
    # 荣耀校招 #
    49811次浏览 1308人参与
    # 牛友的志愿填报指南 #
    13558次浏览 127人参与
    # 许愿池 #
    148456次浏览 2131人参与
    # 你的房租占工资的比例是多少? #
    5432次浏览 32人参与
    # 联影秋招 #
    20860次浏览 307人参与
    # 机械人怎么评价今年的华为 #
    115600次浏览 884人参与
    # 软件开发薪资爆料 #
    1437221次浏览 16537人参与
    # 视觉/交互/设计工作体验 #
    11956次浏览 166人参与
    # 产品人专业大盘点 #
    26889次浏览 246人参与
    # 你都收到了哪些公司的感谢信? #
    84299次浏览 1178人参与
    # 数据人offer决赛圈怎么选 #
    79933次浏览 1129人参与
    # 晒一晒我的offer #
    6045441次浏览 75946人参与
    # 在国企工作的人,躺平了吗? #
    203615次浏览 2925人参与
    # vivo求职进展汇总 #
    55437次浏览 376人参与
    # 我想象的工作vs实际工作 #
    268338次浏览 3542人参与
    # offer决赛圈,我是怎么选的 #
    362621次浏览 3255人参与
    # 校招过来人的经验分享 #
    575417次浏览 16951人参与
    # 安利/避雷我的岗位 #
    277230次浏览 3945人参与
    # 正在实习的碎碎念 #
    1101557次浏览 11994人参与
    # 没有实习经历,还有机会进大厂吗 #
    649819次浏览 11759人参与