Gradle之自定义Extension

Extension

就是 Gradle 的 Extension,翻译成中文意思就叫扩展。它的作用就是通过实现自定义的 Extension,可以在 Gradle 脚本中增加类似 android 这样命名空间的配置,Gradle 可以识别这种配置,并读取里面的配置内容。

一般我们通过ExtensionContainer来创建Extension,这个类跟TaskContainer命名有点类似。TaskContainer是用来创建并管理Task的,而ExtensionContainer则是用来创建并管理Extension的,通过Project的以下API可以获取到ExtensionContainer对象

ExtensionContainer getExtensions()
ExtensionContainer主要api及用法
<T> T create(String name, Class<T> type, Object... constructionArguments)
<T> T create(Class<T> publicType, String name, Class<? extends T> instanceType, Object... constructionArguments)
  • publicType:创建的 Extension 实例暴露出来的类类型;
  • name:要创建的Extension的名字,可以是任意符合命名规则的字符串,不能与已有的重复,否则会抛异常;
  • instanceType:该Extension的类类型;
  • constructionArguments:类的构造函数参数值
相关代码示例:
//在project中添加一个名为groupId的属性
project.ext.groupId = "groupId"

// 使用ext块添加扩展属性
ext {
    versionExt = "1.0.2"
    email = "test@gihhub.com"
    artifactId='EasyDependency'
    config=[
            key:'value'
    ]
    android = [compileSdkVersion   : 25,
               buildToolsVersion   : '25.0.0',
               applicationId       : 'com.youdu',
               minSdkVersion       : 16,
               targetSdkVersion    : 23,
               versionCode         : 1,
               versionName         : '1.0.0']
    signConfigs = ['storeFile'    : 'abc.jks',
                   'storePassword': '123456',
                   'keyAlias'     : 'abc',
                   'keyPassword'  : '123456']
    dependence = ['libSupportV7'           : 'com.android.support:appcompat-v7:25.0.0',
                  'libSupportMultidex'     : 'com.android.support:multidex:1.0.1']
}

//打印各个扩展属性
task extParams {
    println versionExt + " " + email
    println android.each {
        it.key + it.value
    }
    println dependence.each {
        it.key + it.value
    }
}

//创建自定义Extension
class MyDefaultConfig {
    String applicationId
    String versionCode
    String versionName
    int targetSdkVersion
    @Override
    String toString() {
        return "applicationId = $applicationId , versionCode = $versionCode, versionName = $versionName, targetSdkVersion = $targetSdkVersion"
    }
}
//创建一个名为 myDefaultConfig 的Extension,每个 Extension 实际上与某个类是相关联的
getExtensions().create("myDefaultConfig", MyDefaultConfig)
//配置extention
myDefaultConfig {
    //myDefaultConfig里面能配置的属性与类 MyDefaultConfig 中的字段是一致的
    applicationId = "com.example"
    versionName = "1.0.1"
    versionCode = "1"
    targetSdkVersion 31
}
task taskExt {
    //能直接通过 project 获取到自定义的 Extension
    println project.myDefaultConfig
}
//打印 applicationId = com.example , versionCode = 1, versionName = 1.0.1, targetSdkVersion = 31


//父类
class Animal {
    String username
    int legs
    Animal(String name) {
        username = name
    }

    void setLegs(int c) {
        legs = c
    }

    String toString() {
        return "This animal is $username, it has ${legs} legs."
    }
}

//子类
class Pig extends Animal {
    int age
    String owner

    Pig(int age, String owner) {
        super("Pig")
        this.age = age
        this.owner = owner
    }

    String toString() {
        return super.toString() + " Its age is $age, its owner is $owner."
    }
}
//创建的Extension是 暴露出来Animal 类型,创建extension名称是name,该extension的类型是Pig,后面2个是参数
def aAnimal = getExtensions().create(Animal, "animal", Pig, 5, "pege")
//创建的Extension是 Pig 类型
def aPig = getExtensions().create(Pig, "pig", Pig, 3, "joge")
animal { //注:自定义扩展和属性没有提示
    legs = 4 //扩展属性配置对象值
}
pig {
    setLegs(2)
}
task animalExt {
    println aAnimal
    println aPig
}
嵌套Extension : NamedDomainObjectContainer

什么是NamedDomainObjectContainer?

顾名思义就是命名领域对象容器,它的主要功能有:

  • 通过DSL创建指定type的对象实例
  • 指定的type必须有一个public构造函数,且必须带有一个String name的参数
  • 它是一个实现了SortedSet接口的容器,所以所有领域对象的name属性都必须是唯一的,在容器内部会用name属性来排序

NamedDomainObjectContainer 需要通过 Project.container(...) API 来创建,其定义为:

<T> NamedDomainObjectContainer<T> container(Class<T> type)
<T> NamedDomainObjectContainer<T> container(Class<T> type, NamedDomainObjectFactory<T> factory)
<T> NamedDomainObjectContainer<T> container(java.lang.Class<T> type, Closure factoryClosure

需要完成此种嵌套扩展属性定义:

android {
    buildTypes {
        release {
            // 是否开启混淆
            minifyEnabled true
            // 开启ZipAlign优化
            zipAlignEnabled true
            //去掉不用资源
            shrinkResources true
            // 混淆文件位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 使用release签名
            signingConfig signingConfigs.hmiou
        }
        debug {
            signingConfig signingConfigs.hmiou
        }
    }
}
代码示例:
//  NamedDomainObjectContainer
//这是领域对象类型定义
class TestDomainObj {
    //必须定义一个 name 属性,并且这个属性值初始化以后不要修改
    String name
    String msg

    //构造函数必须有一个 name 参数
    public TestDomainObj(String name) {
        this.name = name
    }

    void msg(String msg) {
        this.msg = msg
    }

    String toString() {
        return "name = ${name}, msg = ${msg}"
    }
}

//创建一个扩展
class TestExtension {
    //定义一个 NamedDomainObjectContainer 属性
    NamedDomainObjectContainer<TestDomainObj> testDomains

    public TestExtension(org.gradle.api.Project project) {
        //在构造函数中通过 project.container(...) 方法创建 NamedDomainObjectContainer
        testDomains = project.container(TestDomainObj)
    }

    //让其支持 Gradle DSL 语法,注:该方法名要与Extension第二层的name一致
    void buildTypes(Action<NamedDomainObjectContainer<TestDomainObj>> action) {
        action.execute(testDomains)
    }

    void test() {
        //遍历命名领域对象容器,打印出所有的领域对象值
        testDomains.all {
            println(it)
        }
    }
}

//创建一个名为 test 的 Extension
def testExt = getExtensions().create("myandroid", TestExtension, project)
//该第三个参数project就传到TestExtention对象的构造参数中

//给 TextExtention对象配置 NamedDomainObjectContainer 属性
myandroid {
    buildTypes {
        release {
            msg "This is release config"
        }
        debug {
            msg "This is debug config"
        }
    }
}

task nameDomainTask {
    testExt.test() //执行TextExtention对象的test方法,打印配置的各个属性
    //domainx配置就成为了默认、必须的name属性 内部配置了msg属性
}
//打印
//name = debug, msg = This is debug config
//name = release, msg = This is release config

参考:
https://juejin.cn/post/6844903838290296846#comment
demo参考:
https://github.com/running-libo/GradleStudy

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容