Android - Gradle 小課堂第2課 - SourceSet

Gradle 小課堂系列
Gradle 小課堂第1課 - 入門篇
Gradle 小課堂第2課 - SourceSet

什么是 SourceSet?

SourceSet 就是源碼的集合。用來告訴 gradle 我的 java 代碼在哪里,我的 resource 目錄在哪里等等。默認(rèn)情況下,只有一個 SourceSet : main,也不用做任何設(shè)置就能正常編譯項(xiàng)目,實(shí)際上是因?yàn)?SourceSet 規(guī)定了一些默認(rèn)值,如果按照默認(rèn)值配置項(xiàng)目(Android Studio 新建項(xiàng)目就按照默認(rèn)值創(chuàng)建)就不用額外去寫配置代碼了。

SourceSet 規(guī)定的那些默認(rèn)值是什么?

這個可以通過運(yùn)行一個 task 來查看,這個 task 就叫 sourceSets,可以在 Android Studio 的 gradle 面板上雙擊執(zhí)行,也可以用命令行執(zhí)行。見下圖:

gradle 面板

執(zhí)行結(jié)果片段:

main
----
Compile configuration: compile
build.gradle name: android.sourceSets.main
Java sources: [app\src\main\java]
Manifest file: app\src\main\AndroidManifest.xml
Android resources: [app\src\main\res]
Assets: [app\src\main\assets]
AIDL sources: [app\src\main\aidl]
RenderScript sources: [app\src\main\rs]
JNI sources: [app\src\main\jni]
JNI libraries: [app\src\main\jniLibs]
Java-style resources: [app\src\main\resources]

上面列出的是 main 的默認(rèn)值,默認(rèn)情況下還應(yīng)該打印出這幾個的默認(rèn)值: debug、release、test、testDebug、testRelease、androidTest、androidTestDebug。帶 test 字符串的是與測試相關(guān)的。debug 和 release 也是默認(rèn)就創(chuàng)建好的兩個 SourceSet。

多個 SourceSet 之間的關(guān)系是什么?

先說 main 這個 SourceSet,它是一個共用的 SourceSet,可以認(rèn)為是所有 SourceSet 的“基類”,任何一個其他的 SourceSet 編譯時都會將 main 中的代碼包括進(jìn)去,也就是說 main 中的代碼肯定是會參與編譯的。

再說 debug 和 release 這兩個 SourceSet,他倆是默認(rèn)的兩個 buildType 生成的 SourceSet。buildType 會影響 SourceSet,而且 buildType 與 SourceSet 是一一對應(yīng)的,只要有一個 buildType 就會有一個 SourceSet 默默地創(chuàng)建出來。可以將這種 SourceSet 記為 buildType 維度的 SourceSet。

如果定義了 productFlavor,如下面代碼所示:

android {
    productFlavors {
        huoguo {
        }
        malatang {
        }
    }
}

就會生成兩個名為 huoguo 和 malatang 的 SourceSet。productFlavor 也是與 SourceSet 一一對應(yīng)的??梢詫⑦@種 SourceSet 記為 productFlavor 維度的 SourceSet。

那么最終編譯的時候到底應(yīng)該使用哪個 SourceSet?這就要提到 Build Variant,在 Android Studio 中可以在 Build Variants 界面選擇,如下圖所示:


Build Variants

可以看到兩個不同維度的 SourceSet 自由組合了起來,生成了 2 x 2 = 4 個 Build Variant。每次編譯只能選擇其中一種,也就是說,最終編譯使用哪些 SourceSet 是由 buildType 和 productFlavor 共同決定的,而 SourceSet 就起到了區(qū)分這些變量的作用,通過 SourceSet 的配置,使得不同的 buildType 和不同的 productFlavor 有機(jī)會使用不同的代碼來編譯。

回到 SourceSet 之間的關(guān)系的問題,同一維度下的幾個 SourceSet 之間可見是互斥的關(guān)系,而不同維度之間的 SourceSet 就是(可能產(chǎn)生的)組合的關(guān)系。因此同一維度下的不同 SourceSet 可以使用路徑完全相同的類文件,而不用擔(dān)心類重復(fù)的沖突。而不同維度下的 SourceSet 必須考慮到?jīng)_突的問題,不能使用路徑相同的類文件。

SourceSet 自定義路徑

上文提到的 sourceSets task 會打印出所有的目錄默認(rèn)配置,列出的就是所有 SourceSet 可配置的目錄,對應(yīng)的代碼如下摘自 DSL 文檔的圖:

SourceSet 可配置屬性

下面舉幾個常用的例子:

例1:添加一個 java 源碼目錄的設(shè)置

android {
    sourceSets {
        main { // main source set
            java {
                def anotherDir = "......"
                srcDirs anotherDir        // 1 添加
                srcDir anotherDir         // 2 添加
                setSrcDirs([anotherDir])  // 3 重置
                srcDirs = [anotherDir]    // 4 重置
                srcDirs += [anotherDir]   // 5 添加
            }
        }
    }
}

注釋 1 與 2 位置的語句是調(diào)用了 srcDirs(dir)srcDir(dir) 這兩個方法,雖然方法名有單數(shù)和復(fù)數(shù)的區(qū)別,實(shí)際上這兩個方法效果是完全一樣的,都是添加一個源碼目錄。而注釋 3 和 4 的語句是等價(jià)的,是設(shè)置屬性 srcDirs,會覆蓋之前的值,也就是說設(shè)置完成后,只剩下新添加的 anotherDir 了。注釋 5 的語句相當(dāng)于調(diào)用 setSrcDirs(getSrcDirs() + [anotherDir]),使用了運(yùn)算符重載(operator overload),重載了 + 運(yùn)算,與 1 和 2 是效果相同的。

例2:將 SourceSet 的路徑修改為另一套

android {
    sourceSets {
        main {
            def dependSrc = 'juanbing'
            java.srcDirs = ["${dependSrc}/java"]
            assets.srcDirs = ["${dependSrc}/assets"]
            res.srcDirs = ["${dependSrc}/res"]
            manifest.srcFile "${dependSrc}/AndroidManifest.xml"
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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