Android Gradle Plugin指南(二)——基本項目

來源:互聯網
上載者:User

標籤:android gradle   項目結構   build task   build type   簽名配置   

原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Basic-Project


3、Basic Project(基本項目)


一個Gradle項目的構建流程定義在build.gradle檔案中,位於項目的根目錄下。

3.1 Simple build files(簡單的構建檔案)


一個最簡單的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 build file的3個主要部分:

buildscrip{...}這裡配置了驅動構建過程的代碼。
在這個部分,它聲明了使用Maven倉庫,並且聲明了一個maven檔案的依賴路徑。這個檔案就是包含了0.11.1版本android gradle外掛程式的庫。
注意:這裡的配置隻影響控制構建過程的代碼,不影響項目原始碼。項目本身需要聲明自己的倉庫和依賴關係,稍後將會提到這部分。

接下來,跟前面提到的Java Plugin一樣添加了android plugin。

最後,andorid{...}配置了所有android構建過程需要的參數。這裡也是Android DSL的進入點。
預設情況下,只需要配置目標編譯SDK版本和編譯工具版本,即compileSdkVersion和buildToolsVersion屬性。
這個complieSdkVersion屬性相當於舊構建系統中project.properites檔案中的target屬性。這個新的屬性可以跟舊的target屬性一樣指定一個int或者String類型的值。

重要:你只能添加android plugin。同時添加java plugin會導致構建錯誤。

注意:你同樣需要在相同路徑下添加一個local.properties檔案,並使用sdk.dir屬性來設定SDK路徑。
另外,你也可以通過設定ANDROID_HOME環境變數,這兩種方式沒有什麼不同,根據你自己的喜好選擇其中一種設定。
                

3.2 Project Structure(項目結構)


上面提到的基本的構建檔案需要一個預設的檔案夾結構。Gradle遵循約定優先於配置的概念,在可能的情況儘可能提供合理的預設配置參數。

基本的項目開始於兩個名為“source sets”的組件,即main source code和test code。它們分別位於:
    * src/main/
    * src/androidTest/

裡面每一個存在的檔案夾對應相應的源組件。
對於Java plugin和Android plugin來說,它們的Java原始碼和資源檔路徑如下:
    * java/
    * resources/

但對於Android plugin來說,它還擁有以下特有的檔案和檔案夾結構:
    * AndroidManifest.xml
    * res/
    * assets/
    * aidl/
    * rs/
    * jni/

注意:src/androidTest/AndroidManifest.xml是不需要的,它會自動被建立。

3.2.1 Configuring the Structure(設定項目結構)

當預設的項目結構不適用的時候,你可能需要去配置它。根據Gradle文檔,重新為Java項目配置sourceSets可以使用以下方法:

    sourceSets {        main {            java {                srcDir 'src/java'            }            resources {                srcDir 'src/resources'            }        }    }
注意:srcDir將會被添加到指定的已存在的源檔案夾中(這在Gradle文檔中沒有提到,但是實際上確實會這樣執行)。
    
替換預設的原始碼檔案夾,你可能想要使用能夠傳入一個路徑數組的srcDirs來替換單一的srcDir。以下是使用調用對象的另一種不同方法:
    sourceSets {        main.java.srcDirs = ['src/java']        main.resources.srcDirs = ['src/resources']    }

想要擷取更多資訊,可以參考Gradle文檔中關於Java Pluign的部分。

Android Plugin使用的是類似的文法。但是由於它使用的是自己的sourceSets,這些配置將會被添加在android對象中。
以下是一個樣本,它使用了舊項目結構中的main源碼,並且將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,renderscripthe和java資源檔)都放在同一個目錄裡面,所以我們需要將這些sourceSet組件重新對應到src目錄下。
注意:setRoot()方法將移動整個組件(包括它的子檔案夾)到一個新的檔案夾。樣本中將會移動scr/androidTest/*到tests/*下。
以上這些是Android特有的,如果配置在Java的sourceSets裡面將不會有作用。

以上也是將舊構建系統項目遷移到新構建系統需要做的遷移工作。


3.3 Build Tasks(構建任務)


3.3.1 General Tasks(通用任務)


添加一個外掛程式到構建檔案中將會自動建立一系列構建任務(build tasks)去執行(註:gradle屬於任務驅動型構建工具,它的構建過程是基於Task的)。Java plugin和Android plugin都會建立以下task:
    * assemble:這個task將會組合項目的所有輸出。
    * check:這個task將會執行所有檢查。
    * build:這個task將會執行assemble和check兩個task的所有工作
    * clean:這個task將會清空項目的輸出。
實際上assemble,check,build這三個task不做任何事情。它們只是一個Task標誌,用來告訴android plugin添加實際需要執行的task去完成這些工作。

這就允許你去調用相同的task,而不需要考慮當前是什麼類型的項目,或者當前項目添加了什麼plugin。
例如,添加了findbugs plugin將會建立一個新的task並且讓check task依賴於這個新的task。當check task被調用的時候,這個新的task將會先被調用。

在命令列環境中,你可以執行以下命令來擷取更多進階別的task:

    gradle tasks

查看所有task列表和它們之間的依賴關係可以執行以下命令:
    gradle tasks --all

注意:Gradle會自動監視一個task聲明的所有輸入和輸出。
兩次執行build task並且期間項目沒有任何改動,gradle將會使用UP-TO-DATE通知所有task。這意味著第二次build執行的時候不會請求任何task執行。這允許task之間互相依賴,而不會導致不需要的構建請求被執行。

3.3.2 Java project tasks(Java項目的Task)


Java plugin主要建立了兩個task,依賴於main task(一個標識性的task):
    * assemble
        * jar:
這個task建立所有輸出
    * check
        * test:
這個task執行所有的測試。
jar task自身直接或者間接依賴於其他task:classes task將會被調用於編譯java源碼。
testClasses task用於編譯測試,但是它很少被調用,因為test task依賴於它(類似於classes task)。

通常情況下,你只需要調用到assemble和check,不需要其他task。

你可以在Gradle文檔中查看java plugin的全部task。

3.3.3 Android tasks


Android plugin使用相同的約定以相容其他外掛程式,並且附加了自己的標識性task,包括:
    * assemble:這個task用於組合項目中的所有輸出。
    * check:這個task用於執行所有檢查。
    * connectedCheck:這個task將會在一個指定的裝置或者模擬器上執行檢查,它們可以同時在所有串連的裝置上執行。
    * deviceCheck:通過APIs串連遠程裝置來執行檢查,這是在CL伺服器上使用的。
    * build:這個task執行assemble和check的所有工作。
    * clean:這個task清空項目的所有輸出。
這些新的標識性task是必須的,以保證能夠在沒有裝置串連的情況下執行定期檢查。
注意build task不依賴於deviceCheck或者connectedCheck。

一個Android項目至少擁有兩個輸出:debug APK(調試版APK)和release APK(發布版APK)。每一個輸出都擁有自己的標識性task以便能夠單獨構建它們。
    * assemble:
        * assembleDebug
        * assembleRelease

它們都依賴於其它一些tasks以完成構建一個APK需要多個步驟。其中assemble task依賴於這兩個task,所以執行assemble將會同時構建出兩個APK。

小提示:gradle在命令列終端上支援駱駝命名法的task簡稱,例如,執行gradle aR命令等同於執行gradle assembleRelease。

check task也擁有自己的依賴:
    * check:
        * lint
    * connectedCheck:
        * connectedAndroidTest
        * connectedUiAutomatorTest(目前還沒有應用到)
    * deviceCheck:
這個test依賴於test建立時,其它實現測試擴充點的外掛程式。

最後,只要task能夠被安裝(那些要求籤名的task),android plugin就會為所有構建類型(debug,release,test)安裝或者卸載。

3.4 Basic Build Customization(基本的構建定製)


Android plugin提供了大量DSL用於直接從構建系統定製大部分事情。

3.4.1 Manifest entries (Manifest屬性)


通過SDL可以配置一下manifest選項:
    * minSdkVersion
    * targetSdkVersion
    * versionName
    * packageName
    * package Name for the test application
    * Instrumentation test runner

例如:

    android {        compileSdkVersion 19        buildToolsVersion "19.0.0"        defaultConfig {            versionCode 12            versionName "2.0"            minSdkVersion 16            targetSdkVersion 16        }    }

在android元素中的defaultConfig元素中定義所有配置。

之前的Android Plugin版本使用packageName來配置manifest檔案中的packageName屬性。從0.11.0版本開始,你需要在build.gradle檔案中使用applicationId來配置manifest檔案中的packageName屬性。
這是為了消除應用程式的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()方法,你自訂的getVersionName()方法就被取代掉了。

如果一個屬性沒有使用DSL進行設定,一些預設的屬性值將會被使用。以下表格是可能使用到的值:

Property Name Default value in DSL object Default value
versionCode     -1 value from manifest if present
versionName     null     value from manifest if present
minSdkVersion   -1 value from manifest if present
targetSdkVersion   -1 value from manifest if present
packageName     packageName     value from manifest if present
testPackageName null     app package name + “.test”
testInstrumentationRunner null     android.test.InstrumentationTestRunner
signingConfig     null     null    
proguardFile     N/A (set only) N/A (set only)
proguardFiles     N/A (set only) N/A (set only)

如果你在構建指令碼中使用自訂代碼邏輯請求這些屬性,那麼第二列的值將非常重要。例如,你可能會寫:
    if (android.defaultConfig.testInstrumentationRunner == null) {        // assign a better default...    }
如果這個值一直保持null,那麼在構建執行期間將會實際替換成第三列的預設值。但是在DSL元素中並沒有包含這個預設值,所以,你無法查詢到這個值。
除非是真的需要,這是為了預防解析應用的manifest檔案。
    
3.4.2 Build Types(構建類型)
預設情況下,Android Plugin會自動給項目設定同時構建應用程式的debug和release版本。
兩個版本之間的不同主要圍繞著能否在一個安全裝置上調試,以及APK如何簽名。

Debug版本採用使用通用的name/password鍵值對自動建立的數位憑證進行簽名,以防止構建過程中出現請求資訊。Release版本在構建過程中沒有簽名,需要稍後再簽名。

這些配置通過一個BuildType對象來配置。預設情況下,這兩個執行個體都會被建立,分別是一個debug版本和一個release版本。

Android plugin允許像建立其他構建類型一樣定製debug和release執行個體。這需要在buildTypes的DSL容器中配置:
    android {        buildTypes {            debug {                applicationIdSuffix ".debug"            }            jnidebug.initWith(buildTypes.debug)            jnidebug {                packageNameSuffix ".jnidebug"                jnidebugBuild true            }        }    }
   
以上程式碼片段實現了以下功能:
    * 配置預設的debug構建類型:將debug版本的包名設定為<app package>.debug以便能夠同時在一台裝置上安裝debug和release版本的apk。
    * 建立了一個名為“jnidebug”的新構建類型,並且這個構建類型是debug構建類型的一個副本。
    * 繼續配置jnidebug構建類型,允許使用JNI組件,並且也添加了不一樣的包名尾碼。
    
建立一個新的構建類型就是簡單的在buildType標籤下添加一個新的元素,並且可以使用initWith()或者直接使用閉包來配置它。

以下是一些可能使用到的屬性和預設值:

Property name Default values for debug Default values for release / other
debuggable     debuggable     false
jniDebugBuild     false false
renderscriptDebugBuild   false false
renderscriptOptimLevel   3 3
packageNameSuffix     null null
versionNameSuffix     null null
signingConfig     android.signingConfigs.debug null
zipAlign     false     true
runProguard     false false
proguardFile     N/A (set only) N/A (set only)
proguardFiles     N/A (set only) N/A (set only)


除了以上屬性之外,Build Type還會受項目源碼和資源影響:
對於每一個Build Type都會自動建立一個匹配的sourceSet。預設的路徑為:
    src/<buildtypename>/
這意味著BuildType名稱不能是main或者androidTest(因為這兩個是由plugin強制實現的),並且他們互相之間都必須是唯一的。

跟其他sourceSet設定一樣,Build Type的source set路徑可以重新被定向:
    android {        sourceSets.jnidebug.setRoot('foo/jnidebug')    }

另外,每一個Build Type都會建立一個新的assemble<BuildTypeName>任務。

assembleDebug和assembleRelease兩個Task在上面已經提到過,這裡要講這兩個Task從哪裡被建立。當debug和release構建類型被預建立的時候,它們的tasks就會自動建立對應的這個兩個Task。

上面提到的build.gradle程式碼片段中也會實現assembleJnidebug task,並且assemble會像依賴於assembleDebug和assembleRelease一樣依賴於assembleJnidebug。

提示:你可以在終端下輸入gradle aJ去運行assembleJnidebug task。

可能會使用到的情況:
    * release模式不需要,只有debug模式下才使用到的許可權
    * 自訂的debug實現
    * 為debug模式使用不同的資源(例如當資源的值由綁定的認證決定)

BuildType的代碼和資源通過以下方式被使用:
    * manifest將被混合進app的manifest
    * 程式碼為只是另一個資源檔夾
    * 資源將疊加到main的資源中,並替換已存在的資源。


3.4.3 signing configurations(簽名配置)
對一個應用程式簽名需要以下:
    * 一個Keystory
    * 一個keystory密碼
    * 一個key的別名
    * 一個key的密碼
    * 儲存類型

位置,鍵名,兩個密碼,還有儲存類型一起形成了簽名配置。
    
預設情況下,debug被配置成使用一個debug keystory。debug keystory使用了預設的密碼和預設key及預設的key密碼。
debug keystory的位置在$HOME/.android/debug.keystroe,如果對應位置不存在這個檔案將會自動建立一個。

debug構建類型會自動使用debug簽名配置。

可以建立其他配置或者自訂內建的預設配置。通過signingConfigs這個DSL容器來配置:
    android {        signingConfigs {            debug {                storeFile file("debug.keystore")            }            myConfig {                storeFile file("other.keystore")                storePassword "android"                keyAlias "androiddebugkey"                keyPassword "android"            }        }        buildTypes {            foo {                debuggable true                jniDebugBuild true                signingConfig signingConfigs.myConfig            }        }    }
以上程式碼片段修改debug keystory的路徑到項目的根目錄下。在這個例子中,這將自動影響其他使用到debug構建類型的構建類型。

這裡也建立了一個新的Single Config(簽名配置)和一個使用這個新簽名配置的新的Build Type(構建類型)。

注意:只有預設路徑下的debug keystory不存在時會被自動建立。更改debug keystory的路徑並不會自動在新路徑下建立debug keystory。如果建立一個新的不同名字的SignConfig,但是使用預設的debug keystore路徑來建立一個非預設的名字的SigningConing,那麼還是會在預設路徑下建立debug keystory。換句話說,會不會自動建立是根據keystory的路徑來判斷,而不是配置的名稱。

注意:雖然經常使用項目根目錄的相對路徑作為keystore的路徑,但是也可以使用絕對路徑,儘管這並不推薦(除了自動建立出來的debug keystore)。

注意:如果你將這些檔案添加到版本控制工具中,你可能不希望將密碼直接寫到這些檔案中。下面Stack Overflow連結提供從控制台或者環境變數中擷取密碼的方法:
http://stackoverflow.com/questions/18328730/how-to-create-a-release-signed-apk-file-using-gradle
我們以後還會在這個指南中添加更多的詳細資料。

3.4.4 Running Proguard(運行 Proguard)
從Gradle Plugin for ProGuard version 4.10之後就開始支援ProGuard。ProGuard外掛程式是自動添加進來的。如果Build Type的runProguard屬性被設定為true,對應的task將會自動建立。
android {    buildTypes {        release {            runProguard true            proguardFile getDefaultProguardFile('proguard-android.txt')        }    }    productFlavors {        flavor1 {        }        flavor2 {            proguardFile 'some-other-rules.txt'        }    }}

發布版本將會使用它的Build Type中聲明的規則檔案,product flavor(定製的產品版本)將會使用對應flavor中聲明的規則檔案。

這裡有兩個預設的規則檔案:
    * proguard-android.txt
    * proguard-android-optimize.txt

這兩個檔案都在SDK的路徑下。使用getDefaultProguardFile()可以擷取這些檔案的完整路徑。它們除了是否要進行最佳化之外,其它都是相同的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.