掌控 Android Gradle

2021-02-15 Android群英傳
寫在前面

目前國內對Android領域的探索已經越來越深,不少技術領域如插件化、熱修復、構建系統等都對Gradle有迫切的需求,不懂Gradle將無法完成上述事情。所以Gradle必須要學習。

對本文有任何問題,可加我的個人微信:kymjs123

Gradle 裡的幾乎任何東西都是基於這兩個基礎概念:

掌握了這兩個,你就掌握了一大半的 Gradle 知識了。

首先講 Task

字面理解為任務,Gradle 中所有執行的事件都是藉由 Task 執行的。
例如我們新建一個 Android 工程,在其根目錄中輸入:

gradle tasks -q

可以看到如下輸出(你可能需要事先配置gradle的環境變量,或也可使用./gradlew替代):

根據上圖可以看到當前工程中的每條task都已羅列出,並且有黃色的輸出表示當前task的描述。
其中-q表示忽略gradle本身的log信息,加上這個參數可以屏蔽很多無關的輸出,不加也不會影響執行。

Task聲明格式

聲明一個 task 只需要在任務名前面加上task就可以了,例如下面聲明了一個hello的Task。

task hello

通常我們會給task附帶一些執行動作,稱之為Action,例如

hello.doFirst{ println "hello first"}hello.doLast{ println "hello last"}

也可以附帶一個閉包配置,稱之為Configuration,閉包中不僅可用做賦值操作,也可以執行一些自動執行的配置。

hello { println "hello"}

Task依賴

單獨聲明一個task在實際開發中幾乎不會有任何的意義,更多的時候是讓多個task組合起來,一個依賴另一個,形成一連串的任務集。

task hellohello.doFirst{ println "hello "}task world(dependsOn: "hello") << { println "world"}

上面這段代碼定義了兩個task,當我們執行hello任務的時候,會輸出 hello,而執行world任務的時候,由於聲明了dependsOn: "hello",表示world依賴hello,會先執行hello,再執行world。

task xxx << {}

這樣的語法等價於

task xxxxxx.dolast {}

你可以在任意位置新建一個名為build.gradle的文本,來練習上面講述的task定義與依賴。

接著講 Project

Android   │   ├──app   │   └──build.gradle   │   ├──library   │   └──build.gradle   │   ├──*.properties   │   ├──build.gradle   │   └──setting.gradle

一個 Android 工程,通常是由上述結構構成,其中有著許多不為人知的巧妙用法。

setting.gradle文件

關於setting.gradle中也可以寫代碼,是很多人不知道的。如下代碼是我在上一篇文章【企業級 Android 模塊化平臺設計建議】中講到的一個例子,在setting.gradle文件中,可以指定一個project位置,這裡就可以將一個外部工程中的模塊導入到APP工程中了。

getLocalProperties().entrySet().each { entry ->    def moduleName = entry.key    if (Boolean.valueOf(entry.value)) {        def file = new File(rootProject.projectDir.parent, "/${moduleName.replace("\\W", "")}/${moduleName.toLowerCase()}")        if (file.exists()) {            include ":${moduleName.toLowerCase()}"            project(":${moduleName.toLowerCase()}").projectDir = file        }    }}

build.gradle

一個項目的根gradle文件,用於描述這個項目的統一資源,其中包括各子資源的使用方式、插件的依賴環境等等。

subprojects{    apply plugin: 'com.android.library'    dependencies {      compile 'com.xxx.xxx:xxx:1.0.0'   }}

通常我們在每個模塊都會引用的 aar 的時候,都會在每個模塊裡面都去手動的compile一遍,例如support包。 但實際上有一個非常簡單的辦法,寫一遍就可以了,就是在項目的根gradle文件中的subprojects閉包中聲明這個dependencies。

通常在寫compile依賴的時候,我們都會寫成這樣:

compile 'com.android.support:appcompat-v7:25.0.0'

其實在gradle中,這是一個方法調用,它的本質是compile()方法傳入了一個map參數,因此完整的寫法實際上是這樣的:

compile group: 'com.android.support' name:'appcompat-v7' version:'25.0.0'

同時,map 的可使用 key 不只是有常用的group、name、version,還包括不常用的configuration、classifier等等。

再看Task

Groovy 是基於 Java 的,只不過在這基礎上加了一大堆的閉包,來幫助更方便的開發構建腳本。如果你不會 Groovy,沒關係,當成 Java 寫就行了,其實當成 Kotlin 寫是最恰當的。如果你還不會 Kotlin,我強烈推薦你查看我的 【 Kotlin Primer 】系列文章

每個Task都可以配置其輸入與輸出,如果一個Task的輸出與上一次的輸出一致,則不會重複執行。此刻,會在命令行中輸出UP-TO-DATE表示已經是最新的結果。
例如如下Task:

task transform {    ext.srcFile = file('hello.txt')    ext.destDir = new File(buildDir, 'generated')    inputs.file srcFile    outputs.dir destDir    doLast {        destDir.mkdirs()        def ins = new BufferedReader(new FileReader(srcFile))        def stringBuilder = new StringBuilder()        def temp        while ((temp = ins.readLine()) != null) {            stringBuilder.append(temp)        }        def destFile = new File(destDir, "world.txt")        destFile.text = stringBuilder.toString()    }}

重複執行後會輸出UP-TO-DATE

騷操作的背後

學習任何一門技術,最快的途徑就是看源碼,gradle的源碼位於src目錄中,例如在我本機的路徑為: 
/Users/zhangtao/.gradle/wrapper/dists/gradle-3.3-all/55gk2rcmfc6p2dg9u9ohc3hw9/gradle-3.3/src
本地新建一個普通Java工程,導入源碼查看代碼與注釋,這是最好的學習資料。

task hello

在 Groovy 中,方法括號可以省略,如果字符串的類型是可以被推斷的,那麼引號也可以省略

public interface org.gradle.api.Project{ Task task(String name); Task task(String name, Closure configureClosure);}public TaskInternal createTask(Map<String, ?> args) {}

閉包的存在,目的是為了更好的為對象初始化。同 Kotlin 一樣,當閉包做為最後一個參數的時候,可以省略括號。

Copy a = task(myCopy, type: Copy)a.from 'resources'a.into 'target'a.include('**/*.txt', '**/*.xml', '**/*.properties')

等價於

task myCopy(type: Copy)myCopy {   from 'resources'   into 'target'   include('**/*.txt', '**/*.xml', '**/*.properties')}

本章就講到這裡,下一篇講如何創建一個Gradle插件,完成編譯時向指定類或新生成類中動態添加代碼(包括jar包中)。

相關焦點

  • 寫給Android開發的Gradle知識體系
    這篇文章主要介紹項目build.gradle和模塊build.gradle。4.模塊build.gradle新建一個Android項目,它的模塊build.gradle的內容如下:apply plugin: 'com.android.application'android {    compileSdkVersion 28    defaultConfig {        applicationId
  • Gradle 與 Android 構建入門
    比如需要 Android Gradle Plugin 插件為我們打包 apk 包,就需要添加1. classpath 'com.android.tools.build:gradle:3.4.0'最後是 allprojects 和 repositories:在 allprojects 中的配置會對所有工程生效而裡面的 repositories 則表示工程聲明的 dependencies
  • 擁抱Android Studio(二):Android Studio與Gradle深入
    ├── build.gradle //項目 build.gradle,通常配置項目全局配置,如 repositories 和 dependencies├── gradle.properties //項目屬性文件,通常可以放置一些常量├── gradlew //Gradle 包裝器可執行文件├── gradlew.bat //Gradle 包裝器可執行文件(Windows)├──
  • 給 Android 開發者的 Gradle 入門指南
    #掃描二維碼報名源創會#原文:Beginner’s Guide to Gradle for Android Developers連結:https://journals.apptivitylab.com/beginners-guide-to-gradle-for-android-developers
  • 【實戰】Android工程gradle詳解
    這時我們就需要對所有的版本進行統一的管理,管理的方式有兩種:rootProject我們可以把一些需要用的欄位都放在project的build.gradle(注意是project的不是module的)中:這樣,在module的build.gradle中可以進行讀取:
  • 原創 | 看完此文,你對Gradle的理解又升級了!
    作者:劉望舒http://liuwangshu.cn/application/android-gradle/2-gradle-dependency.htmlGradle知識體系為什麼現在要用Gradle?
  • 這一次,徹底了解 Gradle 吧!
    紅框裡的是 Gradle 自帶的內置插件,apply plugin: 'com.android.library'、apply plugin: 'com.android.application' 這些都是 gradle 自帶的內置插件
  • 這一次,徹底了解 Gradle 吧!
    紅框裡的是 Gradle 自帶的內置插件,apply plugin: 'com.android.library'、apply plugin: 'com.android.application' 這些都是 gradle 自帶的內置插件
  • Flutter Running Gradle task 'assembleDebug'解決方法
    前言最近用flutter做個app,當運行flutter run的時候,一直卡在這個地方動不了,如下圖:運行時會卡在Running 'gradle assembleDebug, 因為Gradle的Maven倉庫在國外, 可以使用阿里雲的鏡像地址。
  • 谷歌Android Studio 和 Gradle 插件使用全新版本編號
    安裝預覽版 Android Studio:https://developer.android.google.cn/studio/preview/install-preview如果沿用以前的編號系統,則此版本將為 Android Studio 4.3。
  • 谷歌:Android Studio 和 Gradle 插件使用全新版本編號
    安裝預覽版 Android Studio:https://developer.android.google.cn/studio/preview/install-preview如果沿用以前的編號系統,則此版本將為 Android Studio 4.3。
  • Android Gradle 使用大全
    項目結構中的每個build.gradle文件代表一個project,在這編譯腳本文件中可以定義一系列的task;task 本質上又是由一組被順序執行的Action`對象構成,Action其實是一段代碼塊,類似於Java中的方法Android Gradle 構建生命周期每次構建的執行本質上執行一系列的Task。
  • 一次Android權限刪除經歷
    2.初步定位首先使用android studio查看了打包出來的apk中的Androidmanifest文件,發現其中確實存在RECEIVE_SMS權限,也就是說打包到apk中的Androidmanifest文件並不是app下的該文件,從android開發者官網中合併多個manifest文件的文檔來看,實際上打包到apk中的manifest文件是由多個menifest文件合併而來的,其合併順序如下
  • Android studio導入第三方類庫的方法
    2、然後我們重啟我們的android studio就會發現我們的項目下面有了我們的類庫然後我們需要修改的是我們根目錄的下的settings.gradle這個文件,一定要注意是根目錄下的。在裡面添加如圖所示的代碼
  • 跟隨IntelliJ IDEA,谷歌 Android Studio 和 Gradle 插件使用全新...
    安裝預覽版 Android Studio:https://developer.android.google.cn/studio/preview/install-preview如果沿用以前的編號系統,則此版本將為 Android Studio 4.3。
  • 為你的Android實現測試覆蓋率
    備註:我的項目環境為gradle 6.5,低於gradle 6.0的項目請自行查詢另外的jacoco實現方式(gradle 6以上對文件權限進行了更改)。classpath 'com.dicedmelon.gradle:jacoco-android:0.1.5-SNAPSHOT‍在全局的build.gradle添加一個jacoco的classpathapply plugin
  • Android架構之App組件化方案詳細實踐與總結
    gradle.properties 中配置的欄位都可以在build.gradle文件中直接讀取出來,不用任何多餘的代碼。()) {            apply plugin: 'com.android.application'}          else {                 apply plugin: 'com.android.library'}因為gradle.properties中的數據類型都是String類型,而這裡我們需要的是boolean
  • Gradle依賴管理解析
    如果在項目中創建了一個模塊作為依賴項目,那麼你需要在settings.gradle 中添加該模塊,在應用模塊中將它作為依賴:Include ':app', ':library'在這種情況下,依賴模塊被稱之為依賴庫,並且文件夾的名稱與此相同。
  • 經驗丨Android開發最佳實踐
    gradle.properties文件。使用它時先安裝JDK8,在Android Studio工程結構對話框中把它設置成為SDK路徑,同時設置JAVA8_HOME和JAVA7_HOME環境變量, 然後在工程根目錄下配置 build.gradle:dependencies {classpath 'me.tatarka:gradle-retrolambda:2.4.
  • Android Studio打包apk,aar,jar包
    一片楓葉_劉超的博客地址:http://blog.csdn.net/qq_23547831作者編寫了github項目解析、android源碼分析以及產品研發多個專題,有興趣的可以關注下學習學習~文本我們將講解android studio打包apk,aar,jar包的相關知識。