Gradle Extension學(xué)習(xí)

在Gralde中包含許多的Task 和 Project ,但是里面還有一個很重要的概念 Extension,下面我們就來介紹一下Extension。

什么是Extension.

下面看一段非常常見的代碼

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "com.ljc.doubleclickplugin"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

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

如何定義Extension

ExtensionContainer

一般我們通過 ExtensionContainer 來創(chuàng)建 Extension,這個類與 TaskContainer 命名有點類似,TaskContainer 是用來創(chuàng)建并管理 Task 的,而 ExtensionContainer 則是用來創(chuàng)建并管理 Extension 的。通過 Project 的以下 API 可以獲取到 ExtensionContainer 對象

ExtensionContainer getExtensions?()
如何實現(xiàn)一個簡單的Extension
//創(chuàng)建User
class User {
    int age
    String username

    String toString() {
        return "name = ${username}, age = ${age}"
    }
}
//創(chuàng)建一個Extension 并定義名字
getExtensions().create("user", User)

//配置Extension
user {
    age = 30
    username = "xyy"
}
task testExt  {
    doLast{
        //能直接通過 project 獲取到自定義的 Extension
        println project.user
    }
}

運行結(jié)果


image.png

在上面的例子中 user就是我們自定義的Extension,我們需要配置的字段是和User的字段對應(yīng)的,
我們可以通過project.user直接訪問,每個 Extension 實際上與某個類是相關(guān)聯(lián)的,在 build.gradle 中通過 DSL 來定義,Gradle 會識別解析并生成一個對象實例,通過該類可以獲取我們所配置的信息。

ExtensionContainer主要API

1.創(chuàng)建

    <T> T create(Class<T> publicType, String name, Class<? extends T> instanceType, Object... constructionArguments);

參數(shù)函數(shù)含義
publicType:創(chuàng)建的 Extension 實例暴露出來的類類型;
name:要創(chuàng)建的Extension的名字,可以是任意符合命名規(guī)則的字符串,不能與已有的重復(fù),否則會拋異常;
instanceType:該Extension的類類型;
constructionArguments:類的構(gòu)造函數(shù)參數(shù)值
示例

//父類
class Person {

    String username
    int age

    Person(String name) {
        username = name
    }

    void setAge(int age) {
        this.age = age
    }

    String toString() {
        return "Person name is $username, age is  ${age} "
    }
}

//子類
class User extends Person {

    String  sex
    String owner

    User(String  sex, String owner) {
        super("User")
        this.sex = sex
        this.owner = owner
    }

    String toString() {
        return super.toString() + " sex is $age,  owner is $owner."
    }

}

//創(chuàng)建的Extension是 Animal 類型
Person mPerson = getExtensions().create(Person, "person", User, "man", "ljc")
//創(chuàng)建的Extension是 Pig 類型
User mUser = getExtensions().create("user", User, "women", "zdd")

person {
    age = 4    //配置屬性
}

user {
    setAge 2   //這個是方法調(diào)用,也就是 setAge(2)
}

task testExt  {
    doLast {
        println mPerson
        println mUser
        //驗證 aPig 對象是 ExtensionAware 類型的
        println "aPig is a instance of ExtensionAware : ${mUser instanceof ExtensionAware}"
    }

}

運行結(jié)果


image.png
增加Extension

除了創(chuàng)建以外還有一個add方法可以增加Extension,與創(chuàng)建的區(qū)別就是他不會返回一個Extension對象。
下面一個簡單示例看一下 添加方法

//添加一個User對象 添加名字為addUser 構(gòu)造方法

getExtensions().add(User, "addUser", new User("man", "zmj"))
addUser {
    username = "zms"
    age = 25
    sex = "man"
}
task addExt {
    doLast {
        def user = project.getExtensions().getByName("addUser")
        println user
    }
}

運行結(jié)果


查找Extension
Object findByName(String name)
<T> T findByType(Class<T> type)
Object getByName(String name)       //找不到會拋異常
<T> T getByType(Class<T> type)  //找不到會拋異常

比較簡單跳過

嵌套Extension

就像最開始的例子就是一個嵌套的Extension,下面我們看一看嵌套的Extension如何實現(xiàn)

//首先定義和外部的Extension
class OutExt {

    String outName
    //這是內(nèi)部的 Extension
    InnerExt innerExt = new InnerExt()

    void setOutName(String name) {
        outName = name
    }



    void inner(Action<InnerExt> action) {
        //創(chuàng)建內(nèi)部Extension,并為其命名方法名 inner
        action.execute(inner)
    }

    //創(chuàng)建一個方法名為inner大的內(nèi)部Extension
    void inner(Closure c) {
        org.gradle.util.ConfigureUtil.configure(c, innerExt)
    }

    String toString() {
        return "OuterExt[ name = ${outName}] " + innerExt
    }

}


class InnerExt {

    String innerName

    void innerName(String name) {
        innerName = name
    }


    String toString() {
        return "InnerExt[ name = ${innerName}]"
    }

}

def outExt = getExtensions().create("outer", OutExt)

outer {

    outName "outer"

    inner {
        innerName "inner"
    }

}

task outAndInExt  {
    doLast {
        println outExt
    }

}

運行結(jié)果


image.png

其中的關(guān)鍵方法在于
void inner(Action<InnerExt> action)
void inner(Closure c)

定義在 outer 內(nèi)部的 inner ,Gradle 解析時實質(zhì)上會進行方法調(diào)用,也就是會執(zhí)行 outer.inner(...) 方法,而該方法的參數(shù)是一個閉包(俗稱 Script Block),所以在類 OuterExt 中必須定義 inner(...) 方法。

Android的Extension

下面是一個android項目的經(jīng)典配置

android {
    compileSdkVersion 30

    defaultConfig {

    }

    buildTypes {
    
    productFlavors{

    }
    signingConfigs{
        
    }
}

這就是一個很經(jīng)典的擴展 我們進入源碼去看一下
他們都是在 BaseExtension 的類里面

  private final DefaultConfig defaultConfig;
    private final NamedDomainObjectContainer<ProductFlavor> productFlavors;
    private final NamedDomainObjectContainer<BuildType> buildTypes;
    private final NamedDomainObjectContainer<SigningConfig> signingConfigs;

    public void defaultConfig(Action<DefaultConfig> action) {
        this.checkWritability();
        action.execute(this.defaultConfig);
    }
    
     public void buildTypes(Action<? super NamedDomainObjectContainer<BuildType>> action) {
        this.checkWritability();
        action.execute(this.buildTypes);
    }

    public void productFlavors(Action<? super NamedDomainObjectContainer<ProductFlavor>> action) {
        this.checkWritability();
        action.execute(this.productFlavors);
    }

    public void signingConfigs(Action<? super NamedDomainObjectContainer<SigningConfig>> action) {
        this.checkWritability();
        action.execute(this.signingConfigs);
    }

并且他們都是通過AppPlugin進行初始化的
初始化代碼如下

    protected AppExtension createExtension(
            @NonNull DslScope dslScope,
            @NonNull ProjectOptions projectOptions,
            @NonNull GlobalScope globalScope,
            @NonNull NamedDomainObjectContainer<BuildType> buildTypeContainer,
            @NonNull DefaultConfig defaultConfig,
            @NonNull NamedDomainObjectContainer<ProductFlavor> productFlavorContainer,
            @NonNull NamedDomainObjectContainer<SigningConfig> signingConfigContainer,
            @NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,
            @NonNull SourceSetManager sourceSetManager,
            @NonNull ExtraModelInfo extraModelInfo) {
        return project.getExtensions()
                .create(
                        "android",
                        getExtensionClass(),
                        dslScope,
                        projectOptions,
                        globalScope,
                        buildOutputs,
                        sourceSetManager,
                        extraModelInfo,
                        new ApplicationExtensionImpl(
                                globalScope.getDslScope(),
                                buildTypeContainer,
                                defaultConfig,
                                productFlavorContainer,
                                signingConfigContainer));
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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