Gradle之自定義Extension

Extension

就是 Gradle 的 Extension,翻譯成中文意思就叫擴(kuò)展。它的作用就是通過(guò)實(shí)現(xiàn)自定義的 Extension,可以在 Gradle 腳本中增加類似 android 這樣命名空間的配置,Gradle 可以識(shí)別這種配置,并讀取里面的配置內(nèi)容。

一般我們通過(guò)ExtensionContainer來(lái)創(chuàng)建Extension,這個(gè)類跟TaskContainer命名有點(diǎn)類似。TaskContainer是用來(lái)創(chuàng)建并管理Task的,而ExtensionContainer則是用來(lái)創(chuàng)建并管理Extension的,通過(guò)Project的以下API可以獲取到ExtensionContainer對(duì)象

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:創(chuàng)建的 Extension 實(shí)例暴露出來(lái)的類類型;
  • name:要?jiǎng)?chuàng)建的Extension的名字,可以是任意符合命名規(guī)則的字符串,不能與已有的重復(fù),否則會(huì)拋異常;
  • instanceType:該Extension的類類型;
  • constructionArguments:類的構(gòu)造函數(shù)參數(shù)值
相關(guān)代碼示例:
//在project中添加一個(gè)名為groupId的屬性
project.ext.groupId = "groupId"

// 使用ext塊添加擴(kuò)展屬性
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']
}

//打印各個(gè)擴(kuò)展屬性
task extParams {
    println versionExt + " " + email
    println android.each {
        it.key + it.value
    }
    println dependence.each {
        it.key + it.value
    }
}

//創(chuàng)建自定義Extension
class MyDefaultConfig {
    String applicationId
    String versionCode
    String versionName
    int targetSdkVersion
    @Override
    String toString() {
        return "applicationId = $applicationId , versionCode = $versionCode, versionName = $versionName, targetSdkVersion = $targetSdkVersion"
    }
}
//創(chuàng)建一個(gè)名為 myDefaultConfig 的Extension,每個(gè) Extension 實(shí)際上與某個(gè)類是相關(guān)聯(lián)的
getExtensions().create("myDefaultConfig", MyDefaultConfig)
//配置extention
myDefaultConfig {
    //myDefaultConfig里面能配置的屬性與類 MyDefaultConfig 中的字段是一致的
    applicationId = "com.example"
    versionName = "1.0.1"
    versionCode = "1"
    targetSdkVersion 31
}
task taskExt {
    //能直接通過(guò) 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."
    }
}
//創(chuàng)建的Extension是 暴露出來(lái)Animal 類型,創(chuàng)建extension名稱是name,該extension的類型是Pig,后面2個(gè)是參數(shù)
def aAnimal = getExtensions().create(Animal, "animal", Pig, 5, "pege")
//創(chuàng)建的Extension是 Pig 類型
def aPig = getExtensions().create(Pig, "pig", Pig, 3, "joge")
animal { //注:自定義擴(kuò)展和屬性沒(méi)有提示
    legs = 4 //擴(kuò)展屬性配置對(duì)象值
}
pig {
    setLegs(2)
}
task animalExt {
    println aAnimal
    println aPig
}
嵌套Extension : NamedDomainObjectContainer

什么是NamedDomainObjectContainer?

顧名思義就是命名領(lǐng)域?qū)ο笕萜?,它的主要功能有?/p>

  • 通過(guò)DSL創(chuàng)建指定type的對(duì)象實(shí)例
  • 指定的type必須有一個(gè)public構(gòu)造函數(shù),且必須帶有一個(gè)String name的參數(shù)
  • 它是一個(gè)實(shí)現(xiàn)了SortedSet接口的容器,所以所有領(lǐng)域?qū)ο蟮膎ame屬性都必須是唯一的,在容器內(nèi)部會(huì)用name屬性來(lái)排序

NamedDomainObjectContainer 需要通過(guò) Project.container(...) API 來(lái)創(chuàng)建,其定義為:

<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

需要完成此種嵌套擴(kuò)展屬性定義:

android {
    buildTypes {
        release {
            // 是否開(kāi)啟混淆
            minifyEnabled true
            // 開(kāi)啟ZipAlign優(yōu)化
            zipAlignEnabled true
            //去掉不用資源
            shrinkResources true
            // 混淆文件位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 使用release簽名
            signingConfig signingConfigs.hmiou
        }
        debug {
            signingConfig signingConfigs.hmiou
        }
    }
}
代碼示例:
//  NamedDomainObjectContainer
//這是領(lǐng)域?qū)ο箢愋投x
class TestDomainObj {
    //必須定義一個(gè) name 屬性,并且這個(gè)屬性值初始化以后不要修改
    String name
    String msg

    //構(gòu)造函數(shù)必須有一個(gè) name 參數(shù)
    public TestDomainObj(String name) {
        this.name = name
    }

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

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

//創(chuàng)建一個(gè)擴(kuò)展
class TestExtension {
    //定義一個(gè) NamedDomainObjectContainer 屬性
    NamedDomainObjectContainer<TestDomainObj> testDomains

    public TestExtension(org.gradle.api.Project project) {
        //在構(gòu)造函數(shù)中通過(guò) project.container(...) 方法創(chuàng)建 NamedDomainObjectContainer
        testDomains = project.container(TestDomainObj)
    }

    //讓其支持 Gradle DSL 語(yǔ)法,注:該方法名要與Extension第二層的name一致
    void buildTypes(Action<NamedDomainObjectContainer<TestDomainObj>> action) {
        action.execute(testDomains)
    }

    void test() {
        //遍歷命名領(lǐng)域?qū)ο笕萜?,打印出所有的領(lǐng)域?qū)ο笾?        testDomains.all {
            println(it)
        }
    }
}

//創(chuàng)建一個(gè)名為 test 的 Extension
def testExt = getExtensions().create("myandroid", TestExtension, project)
//該第三個(gè)參數(shù)project就傳到TestExtention對(duì)象的構(gòu)造參數(shù)中

//給 TextExtention對(duì)象配置 NamedDomainObjectContainer 屬性
myandroid {
    buildTypes {
        release {
            msg "This is release config"
        }
        debug {
            msg "This is debug config"
        }
    }
}

task nameDomainTask {
    testExt.test() //執(zhí)行TextExtention對(duì)象的test方法,打印配置的各個(gè)屬性
    //domainx配置就成為了默認(rèn)、必須的name屬性 內(nèi)部配置了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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容