1. 程式人生 > >Android Studio Gradle的一些總結

Android Studio Gradle的一些總結

簡介

Android Studio預設使用Gradle作為構建工具,不像Ant那樣基於XML,取而代之的是採用基於Groovy的DSL(Domain Specific Language)。

Gradle構建工具是任務驅動型的構建工具,並且可以通過各種Plugin擴充套件功能以適應各種構建任務。

採用約定優於配置的原則,最簡單方式是使用一個預設的目錄結構。當然目錄結構是可以自己修改的。

Gradle Build Files

新建一個Android Studio專案時,會預設生成以下Gradle相關檔案。

Project級別的build.gradle檔案

buildscript {

//編譯Gradle指令碼過程中需要的依賴關係.//
repositories { jcenter() } //選擇JCenter repository.// dependencies { classpath 'com.android.tools.build:gradle:1.2.3' //指令碼依賴Android plugin for Gradle 1.2.3// } } allprojects { //你應用的依賴關係.// repositories { jcenter() } } //應用依賴jCenter repository.//

Module級別的build.gradle檔案

apply plugin: 'com.android.application'

//引入Android App外掛.//

android {

//下面的部分配置Android App相關的資訊.//

    compileSdkVersion 21

//編譯的SDK版本.// 

    buildToolsVersion "21.1.1"

//Build Tools版本,最好選擇版本號大於或等於compileSdkVersion的.//

    defaultConfig {

        applicationId "com.example.jessica.myapplication"

//application’s ID. 舊版本是 ‘packageName’.//
minSdkVersion 16 //需要的最小API版本.// targetSdkVersion 21 //應用執行的API版本.// versionCode 1 versionName "1.0" } buildTypes { release { //‘BuildTypes’ 控制你App如何編譯打包. 如果你想建立你自己的 build variants, 新增到這裡.// minifyEnabled true //是否進行混淆.// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //混淆配置.// } } } dependencies { //當然Module需要的依賴關係.// compile fileTree(dir: 'libs', include: ['*.jar']) //依賴編譯app/libs.// compile 'com.android.support:appcompat-v7:21.0.3' //依賴編譯遠端庫.// }

Other Gradle Files

gradle-wrapper.properties (Gradle Version)

wrapper相關配置檔案:當其他人編譯你的專案時,即使他們沒有安裝gradle,使用./gradlew相關命令時,這個檔案會檢查正確版本的gradle是否被安裝,如有必要會幫你下載正確的版本。下面會詳細講wrapper。

distributionBase=GRADLE_USER_HOME

//決定解壓後的Gradle包是儲存到工程目錄下, 還是儲存到Gradle user home directory. 
//(對於Unix machines, Gradle user home directory預設在 ~/.gradle/wrapper.)
//如果是PROJECT則zip會解壓到該工程目錄下

distributionPath=wrapper/dists

//解壓後的Gradle包存放的具體路徑.//

zipStoreBase=GRADLE_USER_HOME

zipStorePath=wrapper/dists

//下載的Gradle zip包所放置的目錄//

distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip

//Gradle的下載地址.//

settings.gradle

該檔案組合你所有想構建的module。

include ':app', ':ActionBar-PullToRefresh'

gradle.properties (Project Properties)

這個檔案包含整個project的配置資訊。預設是空檔案,你可以新增各種屬性值到這個檔案,build.gradle中可以引用之。

local.properties (SDK Location)

這個檔案告訴Android Gradle plugin你的Android SDK安裝在哪:

sdk.dir=/Users/jessica/Library/Android/sdk

由於這是你本地的SDK路徑,所以這個檔案不應該加入版本控制中。

The Gradle Wrapper

Android Studio新建專案時都建議使用Gradle Wrapper來構建,這不是必須的,直接指定你本地的安裝的Gradle也行。

用wrapper的好處是當別人參與到該專案時,無須事先本地安裝Gradle或者Android Studio,當執行./gradlew相關的命令時,wrapper會檢查本地相應目錄下是否已經有對應版本的Gradle,如果沒有會幫你下載正確的版本。還有對於一些持續整合的測試伺服器,不一定是安裝了Gradle的,這時候使用wrapper就能避免重新配置伺服器。

如果你想將Gradle專案轉換成基於Gradle Wrapper的,只需要簡單的跑一下gradle wrapper即可,也可以加上–gradle-version 2.4選項來指定一個gradle的版本,–gradle-distribution-url選項指定了從哪兒下載gradle,如果沒有任何選項,則會從Gradle repository下載你執行wrappertask的gradle版本。你也可以將wrapper這個task寫入你的build.gradle檔案:

task wrapper(type: Wrapper) {
    gradleVersion = '2.4'
}

wrappertask會在你的專案根目錄下生成如下檔案:

sample/
  gradlew
  gradlew.bat
  gradle/wrapper/
    gradle-wrapper.jar
    gradle-wrapper.properties

這些檔案是都應該加入到版本控制中的。

如果你想更改Gradle版本,可以直接修改gradle-wrapper.properties檔案:

distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip

或者再跑一下wrappertask重新生成這些檔案,因為wrapper指令碼可能會有更新。

使用wrapper的話會忽略你本機已經安裝的gradle。

關於Build variants

Build variants是product flavors和build types的組合。

buildTypes {
    debug {
        debuggable true
    }
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
productFlavors {
    demo {
        applicationId "me.zircon.test.demo"
        versionName "1.0-demo"
    }
    full {
        applicationId "me.zircon.test.full"
        versionName "1.0-full"
    }
}

上面的片段會組合成4種variants:demoDebug,demoRelease,fullDebug,fullRelease。

Android Studio正常左下角有一個Build Variants的面板,裡面可以選擇你最終想編譯的版本,當選擇run一個模組時,就是編譯的這裡選擇的版本。也可以通過命令列./gradlew assemble來編譯,編譯出的apk可以在app/build/outputs/apk裡找到,格式是app--.apk。 也有利用productFlavors來打渠道包的例子。可見這篇文章。

Source Sets

我們可以在src下建立多個source set:

這裡寫圖片描述

每一個set代表一個flavor或者build type,main set所有variants都會用到。在編譯某個variants時會選擇相應set中的src和res。比如assembleDemoDebug,會組合main,demo和debug set。對於res和manifest檔案,內容會合並,如果有重名欄位的,其合併優先順序從低到高是:libraries/dependencies -> main src -> productFlavor -> buildType。對於src,組合成variants的set中不能存在重名檔案,即demo和Debug中不能同時存在一個A.java,但是Debug和Release中可以同時有。 當然我們也可以通過指令碼中的sourceSets{ }配置目錄結構。 特別對於非約定目錄結構的工程(比如Eclipse工程),通過sourceSets{ }加以配置以便Gradle識別:

sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
        demo {
                 ...
        }
        instrumentTest.setRoot('tests')
}

關於dependencies

dependencies一般有三種形式:

  • Module Dependencies
compile project(":lib")
  • Local Dependencies
compile fileTree(dir: 'libs', include: ['*.jar'])
  • Remote Dependencies
compile 'com.android.support:appcompat-v7:19.0.1'

對於Remote Dependencies,書寫的格式一般是group:name:version,這個網址可以幫你在Maven Central搜尋lib並生成dependencies。

jcenter 和 Maven Central

Gradle會自動從repositories{…}幫你下載編譯Remote Dependencies。

舊版本的Android Studio預設生成的repositories{ }是Maven Central,而新版本已經變成jcenter。這兩者都是相互獨立的lib倉庫,由不同的廠商託管,相較之下,jcenter有以下優勢:

  • jcenter對開發者是友好的,上傳自己的lib到jcenter很方便
  • jcenter利用CDN加速,所以下載lib更快
  • jcenter類庫更全,可以認為是Maven Central的超類

並不是所有類庫都host在jcenter或者Maven Central上,有些是host在自己的Maven倉庫中,比如我們專案中所使用的twitter的crashlytics庫,它host在twitter自己的倉庫中:

repositories {
    maven { url 'https://maven.fabric.io/public' }
}

關於如何將自己的類庫上傳到jcenter可以參考 這篇文章

Gradle的一些概念

我們回過頭來看看Gradle的一些概念。

Gradle指令碼基於Groovy。每一個Gradle指令碼執行時都會配置一種型別的物件。比如執行build.gradle會建立並配置一個Project型別的物件,而settings.gradle則配置Settings物件。相應的這個型別中的屬性和方法可以直接用在指令碼中,如:file(…)返回路徑的File物件;println name則列印該project的name。

腳本里可以使用任何Groovy/Java的語法。比如解析AndroidManifest檔案取得VersionName:

def manifestVersionName() {
    def manifestFile = file(project.projectDir.absolutePath + '/src/main/AndroidManifest.xml')
    def ns = new groovy.xml.Namespace("http://schemas.android.com/apk/res/android", "android")
    def xml = new XmlParser().parse(manifestFile)
    return xml.attributes()[ns.versionName].toString()
}

Project

Gradle裡面的Project的概念可以理解成Android Studio中的Module的概念,Project是指我們的構建產物(比如Jar包)或實施產物(將應用程式部署到生產環境)。一個專案可以包含一個或多個任務。

Task

Project由一個或多個Task組成,每一個Task代表了一連串原子性的操作。在Android Studio右邊的Gradle面板或者輸入命令./gradlew tasks都能檢視當前專案所有的Task。 我們也可以用多種方式來新建一個task:

task myTask
task myTask { configure closure }
task myType << { task action }
task myTask(type: SomeType)
task myTask(type: SomeType) { configure closure }

Plugin

在Gradle中,所有有用的特性都是由Plugin來提供的。新增Plugin到Gradle中其實就是添加了一些新的task,域物件(如SourceSet),約定(如Java source預設放在src/main/java下),同時也會擴充套件一些已經存在的型別。 Plugin分兩種:指令碼外掛apply from: ‘other.gradle’和二進位制外掛apply plugin: ‘java’。

Refs