AndroidStudio——Gradle 插件用戶指南(1-3)

不知道是什麼網絡問題,上午一直髮不了博客,其他頁面基本正常,就是在寫博客這裏,每次打開都是響應超時。剛纔用了VPN,順便試了一下,居然可以編輯。想是CDN之類的問題吧。

這次翻譯的是Gradle 插件用戶指南,也就是Gradle上的Android插件的官方文檔。文檔很長,加上最近激情不夠,翻譯得有些慢。到昨天爲止,才譯到第四章。今天先發前三章。

本文譯自Android官方技術文檔《Gradle Plugin User Guide》,原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide。

翻譯不易,轉載請註明CSDN博客上的出處:

http://blog.csdn.net/maosidiaoxian/article/details/41944325

翻譯工作耗時費神,如果你覺得本文翻譯得還OK,請點一下“頂”,我在精神上會倍受鼓勵的,謝謝。翻譯如有錯訛,敬請指正。


Gradle 插件用戶指南

簡介

本文檔是 Gradle 插件 0.9 版本的文檔。在 1.0 之前,我們所介紹的早期版本可能由於不兼容問題會有所不同。

新構建系統的目標

新的構建系統的目標是:
  • 可以很容易地重用代碼和資源
  • 可以很容易地創建應用程序的幾個變種,無論是多APK分發還是不同定製版的應用程序
  • 可以很容易地配置、 擴展和自定義構建過程
  • 好的 IDE 集成

爲什麼是 Gradle ?

Gradle 是一個先進的構建系統和構建工具,它允許通過插件創建自定義的構建邏輯。

基於Gradle的以下特點,我們選擇了它: 
  • 域特定語言 (DSL) 來描述和處理構建邏輯
  • 構建文件基於 Groovy ,並允許通過 DSL來混合聲明性元素,以及使用代碼來處理 DSL 元素以提供自定義邏輯。
  • 基於 Maven 和 Ivy 的內置依賴管理。
  • 非常靈活。允許使用最佳實現,但並不強制自己的實現方式。
  • 插件可以提供自己的 DSL 和API供構建文件使用。
  • 良好的Tooling API 供 IDE 集成

要求

  • Gradle 版本需要 1.10,1.11或 1.12。插件版本需要 0.11.1
  • SDK Build Tools版本要求爲 19.0.0。某些功能可能需要更高版本。

基本項目

Gradle 項目在項目的根文件夾裏的build.gradle文件中描述它的構建邏輯。

簡單的構建文件

最簡單的 純Java項目的build.gradle如下所示:

apply plugin: 'java'

這裏配置使用了Gradle內置的 Java 插件。該插件提供用於構建並測試 Java 應用程序所需要的東西。

最簡單的 Android 項目的 build.gradle 則是以下內容:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.11.1'
    }
}

apply plugin: 'android'

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"
}

在這個 Android 構建文件中,有3個主要部分: 

buildscript { ... }配置了驅動構建的代碼。 
在上面的這種情況中,它聲明瞭使用 Maven 中央庫,並且對一個Maven 文件有一個類路徑依賴。這個文件是包含 Gradle Android 插件的 0.11.1版本的庫 
注: 這隻會影響運行構建的代碼,不會影響項目的源代碼。項目本身需要定義它自己的倉庫和依賴關係。稍後會提及這部分。

然後,和先前的提到的 Java 插件一樣,這裏配置使用了 android插件。 

最後, android { ... }配置了用於 android 構建的所有參數。這是Android DSL的入口。
默認情況下,只需要配置編譯目標,以及build-tools的版本。它通過compileSdkVersionbuildtoolsVersion屬性來完成。
編譯目標相當於舊的構建系統中project.properties 文件內的target屬性。這個新的屬性可以設置爲一個 int 值 (表示api 級別),或者是和以前的target的值一樣,設置爲字符串。

重要提示:你應該只配置使用這個android插件。如果同時配置使用了java插件也會導致構建錯誤。

注:您還需要一個local.properties文件,通過sdk.dir屬性來設置 SDK 的位置,並且所設置的這個SDK要求存在。 
或者,您也可以設置一個ANDROID_HOME環境變量。這兩種方法之間沒什麼差別,你喜歡,你選擇。

項目結構

上述的基本構建文件要求有一個默認的文件夾結構。Gradle 遵循約定大於配置的概念,在可能的情況下提供了合理的默認選項值。

基本項目開始於兩個名爲“source sets”的組件。即主源代碼和測試代碼。它們分別在:
  • src/main/
  • src/androidTest/
裏面的每個文件夾中都存在對應的源代碼組件的文件夾。
對於 Java 和 Android 插件,Java 源代碼和 Java 資源的位置如下: 
  • java/
  • resources/
對於Android 插件,Android所特有的額外的文件和文件夾是:
  • AndroidManifest.xml
  • res/
  • assets/
  • aidl/
  • rs/
  • jni/
注: src/androidTest/AndroidManifest.xml是不需要的,因爲它會被自動創建。

配置項目結構

When the default project structure isn’t adequate, it is possible to configure it. 根據 Gradle 文檔,爲一個Java 項目重新配置 sourceSets可以通過如下方法實現:

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}

注: srcDir實際上會將給定的文件夾添加到現有的源文件夾列表中 (這在Gradle 文檔中沒有提及,但這是實際的行爲)。

如果要替換默認的源文件夾,您就要使用傳入一個路徑數組的srcDirs來代替。以下是使用涉及的對象的另一種不同的方法:

sourceSets {
    main.java.srcDirs = ['src/java']
    main.resources.srcDirs = ['src/resources']
}

欲瞭解更多信息,請參閱 Gradle 文檔中關於 Java 插件的內容,見這裏

Android 插件使用類似的語法,但因爲它使用它自己的sourceSets,所以在android對象裏面來實現。 
這裏有一個例子,使用舊的項目結構的主源碼並重新映射androidTest sourceSet 到tests文件夾:

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        androidTest.setRoot('tests')
    }
}

注意: 因爲舊的結構把所有源文件 (java、 aidl、 renderscript和 java 資源) 都放在相同的文件夾中,我們需要重新映射sourceSet的所有這些新組件到相同的src文件夾中。
注意: setRoot()會將整個sourceSet (和它的子文件夾) 移到一個新的文件夾中。這將移動src/androidTest/*tests/*
下。這是 Android 專用的,不適用於 Java sourceSets。 

這也是一個“遷移”的例子。

構建任務

常規任務

在構建文件中配置使用一個插件,將自動創建一系列要運行的構建任務。Java 插件和 Android 插件都是。
約定的任務如下:
  • assemble
    組裝項目的輸出的任務
  • check
    運行所有檢查的任務。
  • build
    這個任務將執行assemblecheck
  • clean
    這個任務將清理項目的輸出
assemblecheckbuild這些任務,實際上不做任何事情。他們是錨記任務,用於讓插件添加實際的任務去做這些事情。這允許您能夠調用同樣的任務,無論項目的類型是什麼,或者是配置使用了什麼插件 


例如,配置使用findbugs插件將創建一個新的任務和使check任務依賴於它,使得每當調用check任務時都會調用到它。

您可以從命令行中運行下面的命令來獲取更高級別的任務: 
gradle tasks

下面的命令可以得到一個完整的任務列表,並且看到任務運行之間的依賴關係:
gradle tasks --all

注: Gradle 會自動監視一個任務所聲明的輸入和輸出。
在沒有變化的情況下,運行兩次build會使 Gradle 報告所有任務爲UP-TO-DATE狀態,這個狀態意味着沒有任何事情需要執行。這允許任務正確地相互依賴而無需不必要的構建操作。

Java 項目任務

Java 插件主要創建兩個任務,它們是主要錨記任務的依賴任務:
  • assemble
    • jar
      這個任務將創建輸出。
  • check
    • test
      這個任務將運行測試。
jar任務本身會直接或間接地依賴其他任務: 例如,classes任務用於編譯 Java 代碼。
testClasses任務用於編譯測試,但它很少會被調用,因爲test任務依賴於它 (以及classes任務)。

一般情況下,你將可能永遠只調用assemblecheck,而無視其他任務。 

在這裏,你可以看到Java 插件的所有任務和對它們的描述。

Android 任務

Android 的插件使用相同的約定配置以兼容其他插件,並添加了另外的錨記任務:
  • assemble
    組裝項目的輸出的任務
  • check
    運行所有檢查的任務。
  • connectedCheck
    運行需要一個已連接的設備或模擬器的檢查。它們將在所有已連接的設備上並行運行。
  • deviceCheck
    使用 API 連接到遠程設備運行檢查。這一個是在 CI 服務器上使用的。
  • build
    這項任務將執行assemble 和 check
  • clean
    這個任務將清理項目的輸出
新的錨記任務是有必要的,以便能夠運行定期的檢查而無需連接的設備。
注意到,build任務不依賴於deviceCheckconnectedCheck

Android 項目具有至少兩個輸出: debug版本的APK 和release版本的 APK。這裏的每一個輸出都有自己的錨記任務,以便單獨構建它們: 
  • assemble
    • assembleDebug
    • assembleRelease
它們兩個都依賴於執行構建一個 APK所需的多個步驟的其他任務。assemble任務取則依賴於這兩個任務,所以調用 assemble 將會構建出這兩個 APKs。

提示:在命令行上,Gradle 支持任務名稱的駝峯命名法的簡寫。例如: 
gradle aR
相當於輸入
gradle assembleRelease
只要沒有其他任務匹配 “aR” 

check錨記任務有它們自己的依賴項: 
  • check
    • lint
  • connectedCheck
    • connectedAndroidTest
    • connectedUiAutomatorTest (暫未實現)
  • deviceCheck
    • 這個任務依賴於當其他插件實現了測試擴展點時創建的任務。
最後,該插件爲所有構建類型 (debugreleasetest)創建了omstal/uninstall 任務,只要他們可以被安裝(需要簽名)。

基本的構建定製

Android 插件提供了大量的 DSL,以通過構建系統直接地自定義大部分事情。

清單條目

通過 DSL 可以配置以下清單條目:
  • minSdkVersion
  • targetSdkVersion
  • versionCode
  • versionName
  • applicationId (有效的包名 —— 更多的信息請參閱ApplicationId 與packageName
  • 用於測試應用程序的包名
  • Instrumentation test runner
示例:

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        versionCode 12
        versionName "2.0"
        minSdkVersion 16
        targetSdkVersion 16
    }
}

android元素的內部的defaultConfig元素是定義所有這些配置的地方。

以前版本的 Android 插件使用packageName來配置清單的“packageName”屬性。
從 0.11.0開始,你應該在 build.gradle 中使用 applicationId 來配置清單中的“packageName”條目。
它消除了應用程序的包名(指它的 ID)和java 包名之間的所引起的混亂。 


在構建文件中描述它的強大之處是它可以是動態的。 
例如,可以從文件中的某處或使用一些自定義的邏輯讀取版本信息: 

def computeVersionName() {
    ...
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        versionCode 12
        versionName computeVersionName()
        minSdkVersion 16
        targetSdkVersion 16
    }
}

注意: 不要使用在作用域內可能與已存在的getter函數有衝突的函數名稱。例如 defaultConfig { ...} 實例調用 getVersionName() 時將自動使用 defaultConfig.getVersionName() 的 getter 方法,而不是自定義的方法。

如果一個屬性未通過 DSL 來設置,它將使用默認值。下表描述了對於未設置的屬性的處理方式。
 屬性名稱  DSL 對象中的默認值  默認值
 versionCode  -1  如果在清單中存在,則使用清單中的值
 versionName  null  如果在清單中存在,則使用清單中的值
 minSdkVersion  -1  如果在清單中存在,則使用清單中的值
 targetSdkVersion  -1  如果在清單中存在,則使用清單中的值
 applicationId  null  如果在清單中存在,則使用清單中的值
 testApplicationId  null  applicationId + “.test”
 testInstrumentationRunner  null  android.test.InstrumentationTestRunner
 signingConfig  null  null
 proguardFile  N/A (只設置)  N/A (只設置)
 proguardFiles  N/A (只設置)  N/A (只設置) 


第二列的值是很重要的,如果您在構建腳本中使用自定義邏輯查詢這些屬性的話。例如,您可以編寫:
if (android.defaultConfig.testInstrumentationRunner == null) {
    // assign a better default...
}

如果值仍然爲null,那麼在構建的時候它將會被設爲第三列中的實際默認值,但是由於 DSL 元素不包含此默認值,因此您無法查詢它。
這是爲了防止解析應用程序的清單,除非真的很需要。

構建類型

默認情況下,Android 插件自動將項目設置爲生成應用程序的的debug和release版本。
這兩個版本的不同,大多是圍繞在調試一個安全的(非開發版的)設備的能力,以及 apk 怎麼簽名。

調試版本使用自動創建的密鑰/證書籤名,並且密鑰/證書的用戶名/密碼是已知的(以防止構建過程中需要相關的信息)的。release版本在構建的時候不會進行簽名,需要在之後進行簽名。

這個配置是通過一個叫BuildType的對象來完成的。默認情況下,2 個實例會被創建,分別是debug版和release版。

Android 插件允許自定義這兩個實例,以及創建其他的構建類型。它通過buildTypes DSL 容器來實現:

android {
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }

        jnidebug.initWith(buildTypes.debug)
        jnidebug {
            packageNameSuffix ".jnidebug"
            jniDebuggable true
        }
    }
}

上面的代碼段可實現以下操作:
  • 配置默認的Debug Build Type
    • 設置包名爲<app appliationId>.debug,以便能夠在相同的設備上安裝debugrelease兩個版本的apk
  • 創建一個叫jnidebug的新的BuildType對象 ,並將其配置爲debug生成類型的一個副本。
  • 通過啓用 JNI 組件的debug構建,並添加不同的包後綴,繼續配置jnidebug
創建新的 Build Types 就是簡單地在buildTypes下添加一個新的元素,然後調用 initWith()或者是使用一個閉包來配置。

以下是可能用到的屬性和它們的默認值: 

 屬性名稱  用於 debug的默認值  用於 release/其他 的默認值
 debuggable  true  false
 jniDebuggable  false  false
 renderscriptDebuggable  false  false
 renderscriptOptimLevel  3  3
 applicationIdSuffix  null  null
 versionNameSuffix  null  null
 signingConfig  android.signingConfigs.debug  null
 zipAlignEnabled  false  true
 minifyEnabled  false  false
 proguardFile  N/A (只設置)  N/A (只設置)
 proguardFiles  N/A (只設置)  N/A (只設置)


除了這些屬性,Build Types還會影響到構建的代碼和資源。
對每個Build Type都會創建一個自動匹配的sourceSet,默認位置爲 
src/<buildtypename>/
這意味着Build Type的名字不能爲main或者是androidTest (這是插件所強制的),並且它們之間必須是唯一的。

與任何其他source set一樣,生成類型的source set的位置也是可以重新設置的: 
android {
    sourceSets.jnidebug.setRoot('foo/jnidebug')
}
此外,對於每個Build Type,會創建一個新的assemble<BuildTypeName>任務。 

已經提到過的assembleDebugassembleRelease這兩個任務,這裏也會講一下它們是怎麼來的。當debugreleaseBuild Types被預創建的時候,他們的任務也會被自動創建。然後,

上面的build.gradle片段也會生成一個assembleJnidebug任務,並且assemble將會依賴於它,就像它依賴於assembleDebugassembleRelease任務一樣。 

提示: 請記住您可以輸入gradle aJ來運行assembleJnidebug任務。

可能會用到的情況: 
  • release模式下不需要,但debug模式下需要的權限
  • 自定義的debug實現
  • 爲調試模式使用不同的資源 (例如某個資源的值與簽名證書相綁定時)。
BuildType的代碼和資源通過以下方式被使用:
  • manifest將被合併到應用程序的manifest中
  • 代碼只是作爲另一個源文件夾來起作用
  • 資源將覆蓋main裏面的資源,並替換已經存在的值。

簽名配置

對應用程序進行簽名,要求如下:
  • 一個 keystore
  • 一個 keystore 的密碼
  • 一個 key 的別名
  • 一個 key 的密碼
  • 存儲類型
簽名文件的位置,key的名稱,以及這兩個密碼和存儲類型,一起構成了一個簽名配置 ( SigningConfig類型) 

默認情況下,有一個debug的配置,配置使用了一個debug keystore。這個keystore使用了一個已知的key和一個已知的密碼。 
這個debug keystore 位於$HOME/.android/debug.keystore,並且會在不存在時被創建。debug Build Type被設置爲自動使用此debug

SigningConfig

你也可以創建其他配置,或者自定義某個默認的內置配置。通過signingConfigs DSL 容器來實現:
android {
    signingConfigs {
        debug {
            storeFile file("debug.keystore")
        }

        myConfig {
            storeFile file("other.keystore")
            storePassword "android"
            keyAlias "androiddebugkey"
            keyPassword "android"
        }
    }

    buildTypes {
        foo {
            debuggable true
            jniDebuggable true
            signingConfig signingConfigs.myConfig
        }
    }
}
上面的代碼段把debug keystore的位置修改爲在項目的根位置下。這會自動影響到任何設置爲使用它的Build Types,在這裏,影響到的是debug Build Type

代碼的代碼還創建了一個新的Signing Config和使用新配置的新的Build Type 。

注:只有位於默認位置下的debug keystores纔會被自動創建。如果debug keystore的位置被更改了,它將不會在需要時自動創建。創建一個使用一個不同的名稱SigningConfig,但使用了默認的debug keystore的路徑,它也會被自動創建。換句話說,會不會被自動創建與keystore的路徑有關,而與配置名稱無關。

注: keystore的路徑通常使用項目根目錄的相對路徑,但也可以是使用絕對路徑,儘管這不推薦 (除了自動創建的debug keystore)。

注意: 如果您將這些文件加入版本控制,您可能不希望這些文件中有你的密碼。下面的 Stack Overflow 鏈接顯示瞭如何從控制檯或環境變量中讀取值的方法。
我們會在以後更新本指南補充更詳細的信息。

運行ProGuard

ProGuard 是通過 Gradle plugin for ProGuard version 4.10來進行支持的。ProGuard 插件會被自動配置使用,並且如果Build Type通過minifyEnabled屬性配置爲運行ProGuard,對應的任務將被自動創建。

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }

    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'some-other-rules.txt'
        }
    }
}

變種使用他們的構建類型中所聲明的規則文件,product flavors(定製版本)則使用flavor中聲明的規則文件。

這裏有 2 個默認的規則文件
  • proguard-android.txt
  • proguard-android-optimize.txt
它們位於 SDK 中。使用getDefaultProguardFile()將返回的文件的完整路徑。它們除了是否啓用優化之外,其它都是相同的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章