Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 從編程的角度理解gradle腳本??Android Studio腳本構建和編程

從編程的角度理解gradle腳本??Android Studio腳本構建和編程

編輯:關於android開發

從編程的角度理解gradle腳本??Android Studio腳本構建和編程


隨著Android 開發環境從Eclipse轉向Android Studio,我們每個人都開始或多或少要接觸gradle腳本,大多數人將gradle看做構建工具,出現問題不知如何著手分析,只能寄希望百度能找到解決方案,其實大可不必。

如果我們把gradle看做編程框架,並理清gradle腳本與gradle對象的關系,通過查閱文檔,不但能清晰理解gradle腳本,而且出現問題再也不用百度,通過查閱文檔就能輕松解決問題。

本文就通過一個最普通的gradle工程,告訴大家如何通過查閱api文檔來看懂Android裡面的gradle 腳本。

一、gradle介紹

gradle基於的語言是groovy,而groovy語言是基於java語言的一個擴展,它完全兼容java語言的類庫,所以在gralde腳本中你完全可以使用你熟悉的java語言來編程。在本文最後我們會給出一個直接在gradle腳本中使用java編程的例子。

由於本文僅僅是讓大家能看懂腳本,而不是自己去編寫,所以groovy和gradle的細節不是本文的重點,有需要的同學自行百度。這裡要提的一點是groovy語言的函數調用是雖然和java類似,但是它是可以省略括號的,特別是當它的最後一個參數是閉包的時候。

println(“aaa” )//這個是可以的,

println“aaa” //這個也沒有問題。

\

是不是發現了一個秘密:我們在gradle腳本裡全是各種函數調用!!

Gradle api文檔路徑:https://docs.gradle.org/current/dsl/

由於我們也用到了Android 插件,所以我們也需要插件的文檔,這個文檔比較特殊,它是一個git工程,在線浏覽老是顯示html的源碼而非頁面,所以我建議大家將它clone回本地,然後用浏覽器打開,工程地址:https://github.com/google/android-gradle-dsl.git

 

二、gradle腳本和gradle 類對應關系

稍稍浏覽下gradle的文檔,我們會發現工程裡面的gradle腳本,其實和gradle的對象是對應的:

1.Gradle:全局對象,一次gradle構建對應一個Gradle對象;

2.Project:每個工程都是一個Project對象,它對應一個build.gradle文件;

3.Settings:對應一個Setting.gradle文件;

4.Task:代表要執行的工作,一個Project會有一個或多個Task用於完成構建的工作,Project會通過合理設置Task之間的依賴來組織構建流程,完成最終的構建任務。

 

三、腳本執行流程與對象生成

1.每次調用gradle 執行時,會先生成一個Gradle對象,裡面保存一些全局的信息;

2.然後會解析setting.gradle,生成Settings對象,一般在setting.gradle中主要是調用include方法,導入工程下的各個子模塊;

3.接下來會執行導入的各個子工程的build.gradle,生成並配置Project對象;

一般在build.gradle中,會調用Project的apply方法,引入插件,在插件中完成定義各種屬性以及創建所需的Task。

 

四、實例解析

我們以一個Android studio 默認app樣例工程結構為例,工程包含的gradle腳本目錄結構:

\

1. setting.gradle

setting.gradle只有一行語句:

include ':app'

這裡的include其實是Setting的一個函數,‘:app' 是函數調用的參數。

那我們在setting.gradle裡面還能寫什麼呢?因為setting.gradle對應的是gradle中的Settings對象,那查下Settings的文檔(https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html),看下它都有哪些方法,哪些屬性,就知道在setting.gradle能寫什麼了:

比如:

include ':Common'

project(':Common').projectDir = new File(settingsDir,'../../SDK/Common/')//include 調用後,生成了一個名為:CommonProject對象,project(':Common')取出這個對象,設置ProjectprojectDir屬性。

那projectDir哪裡來的?請看Project類的文檔。

 

2. build.gradle

接下來我們來看build.gradle,build.gradle對應一個Project對象,而Project本身是一個Build script:

\

而BuildScript可以包含哪些東西呢?

\

是不是看到了很多老朋友?buildscript , dependencies 。。

看了這裡我們應該就能明白在build.gradle裡面可以寫哪些東西了。

\

這裡要說明的一個重要的點是buildscript,任何一個build.gradle執行的時候,會優先處理buildscript,它是來給腳本建立運行環境的,什麼是運行環境?

一般而言就是下載所需要的插件,舉個例子,android工程都需要android插件,它們都是通過下面的方式引入的:

buildscript {

repositories {//告訴如果本地沒有緩存,去哪個遠程倉庫下載插件

mavenCentral()

}

dependencies {

//這就是我們在applyplugin:com.android.application時的插件jar

classpath 'com.android.tools.build:gradle:1.3.0'

// NOTE: Do not place your application dependencies here; theybelong

//in the individual module build.gradle files

}

}

repositories {//告訴如果本地沒有緩存,去哪個遠程倉庫下載編譯時依賴的庫

mavenCentral()

}

上面的repositories, dependencies都是函數調用哦~~

看到上面的兩個一模一樣的repositories 了嗎?他們的作用是不一樣的,在buildscript裡面的那個是插件初始化環境用的,用於設定插件的下載倉庫,而外面的這個是設定工程依賴的一些遠程library的下載倉庫的。

在build.gradle中引入插件,是我們常見的動作:

apply plugin: 'com.android.application'

查閱Project的文檔(https://docs.gradle.org/current/dsl/org.gradle.api.Project.html).apply是Project的一個方法,

3. android相關部分

查閱android插件的文檔:(file:///home/test/android-gradle-dsl/1.5/index.html)

\

上面就是我們在android{}裡面能寫的所有block的信息,然後在每個block裡面能寫什麼繼續點擊進去察看有哪些屬性和方法就可以了,

比如signingConfigs:

\

signingConfigs{

release {

storeFile file('../sign/release.jks')

storePassword "[email protected]!d"

keyAlias "small"

keyPassword"[email protected]!d"

}

}

本文至此可以告一段落,相信大家結合文檔應該能弄明白gradle腳本裡面的每個代碼塊的意義了。

五、Android工程間的父子關系

需要補充的是:上面例子工程的結構中,工程之間是存在父子關系的,比如RxJava-Android-Samples/build.gradle對應的Project是RxJava-Android-Samples/app/build.gradle對應的Project的父親,而在父Project中做的操作是會被子Project繼承的,比如如果在 父Project引入過了android 插件,則在子Project中可直接引用,不需要重寫一個buildscript塊。

1.RxJava-Android-Samples/build.gradle

buildscript {

repositories {

mavenCentral()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.3.0'

// NOTE: Do not place your application dependencies here; theybelong

//in the individual module build.gradle files

}

}

allprojects {

repositories {

mavenCentral()

}

}

 

2.RxJava-Android-Samples/app/build.gradle

//直接引用android插件,沒有buildscript准備插件;

apply plugin:'com.android.application'

dependencies {

compile 'com.android.support:support-v13:23.0.1'

compile 'io.reactivex:rxandroid:1.0.1'

// BecauseRxAndroid releases are few and far between, it is recommended you also

// explicitly depend on RxJava'slatest version for bug fixes and new features.

compile 'io.reactivex:rxjava:1.0.14'

compile 'io.reactivex:rxjava-math:1.0.0'

compile 'com.jakewharton.rxbinding:rxbinding:0.2.0'

compile 'com.jakewharton:butterknife:5.1.1'

compile 'com.jakewharton.timber:timber:2.4.2'

compile 'com.squareup.retrofit:retrofit:1.6.1'

compile 'com.squareup.okhttp:okhttp:2.0.0'

compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'

compile 'com.alibaba:fastjson:1.2.4'

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'

releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'

}

android {

compileSdkVersion 23

buildToolsVersion '23.0.1'

defaultConfig {

applicationId "com.morihacky.android.rxjava"

minSdkVersion14

targetSdkVersion22

versionCode1

versionName"1.0"

}

buildTypes {

release {

minifyEnabled true

proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'

}

}

}

六、在gradle中使用java語言編程的例子

直接上代碼,想學習的就勞心理解啦,編輯器對代碼不太友好啊。

1. build.gradle

buildscript {

repositories{

maven {

url 'http://artifactory.rnd.meizu.com/artifactory/all'

}

}

dependencies {

classpath 'org.aspectj:aspectjtools:1.8.6'

}

}

importorg.aspectj.bridge.IMessage

import org.aspectj.bridge.MessageHandler

importorg.aspectj.tools.ajc.Main

dependencies{

compile'org.aspectj:aspectjrt:1.8.6'

}

android.applicationVariants.all{ variant ->

JavaCompile javaCompile = variant.javaCompile

//println javaCompile.properties

javaCompile.doLast {

String[] args = [

"-showWeaveInfo",

"-1.5",

"-inpath", javaCompile.destinationDir.toString(),

"-aspectpath",javaCompile.classpath.asPath,

"-d", javaCompile.destinationDir.toString(),

"-classpath",javaCompile.classpath.asPath,

"-bootclasspath",android.bootClasspath.join(File.pathSeparator)

]

MessageHandler handler = newMessageHandler(true);

new Main().run(args, handler)

def log = project.logger

for (IMessage message : handler.getMessages(null,true)) {

switch (message.getKind()) {

case IMessage.ABORT:

case IMessage.ERROR:

case IMessage.FAIL:

log.error message.message,message.thrown

break;

case IMessage.WARNING:

case IMessage.INFO:

log.info message.message,message.thrown

break;

case IMessage.DEBUG:

log.debug message.message,message.thrown

break;

}

}

println "aspect args : " +args.toString()

}

}

2. groovy

下面這段代碼展示了groovy中變量定義,函數定義,List,Map,Range,閉包。

1)變量定義

defvariable1 = 1 //可以不使用分號結尾

2)函數定義;

StringtestFunction(arg1,arg2){//無需指定參數類型

...

}

3)List變量由[]定義,比如

defaList = [5,'string',true] //List由[]定義,其元素可以是任何對象

4)List存取

aList[100]= 100 //設置第101個元素的值為10

assertaList[100] == 100

5)Map變量由[:]定義,比如

defaMap = ['key1':'value1','key2':true]

Map由[:]定義,注意其中的冒號。冒號左邊是key,右邊是Value。key必須是字符串,value可以是任何對象。另外,key可以用''或""包起來,也可以不用引號包起來。比如:

defaNewMap = [key1:"value",key2:true]//其中的key1和key2默認被處理成字符串"key1"和"key2"

不過Key要是不使用引號包起來的話,也會帶來一定混淆,比如

defkey1="wowo"

defaConfusedMap=[key1:"who am i?"]

//aConfuseMap中的key1到底是"key1"還是變量key1的值“wowo”?顯然,答案是字符串"key1"。如果要是"wowo"的話,則aConfusedMap的定義必須設置成:

defaConfusedMap=[(key1):"who am i?"]

6)Range類,Range類型的變量 由begin值+兩個點+end值表示

def aRange =1..5

//如果不想包含最後一個元素,則

defaRangeWithoutEnd = 1..<5

//包含1,2,3,4這4個元素

7)閉包

defxxx = {paramters -> code} //或者

defxxx = {無參數,純code}

比如:

defgreeting = { "Hello, $it!" }

assertgreeting('Patrick') == 'Hello, Patrick!'

當函數的最後一個參數是閉包的話,可以省略圓括號;

public static Listeach(List self, Closure closure)

上面這個函數表示針對List的每一個元素都會調用closure做一些處理。這裡的closure,就有點回調函數的感覺。但是,在使用這個each函數的時候,我們傳遞一個怎樣的Closure進去呢?比如:

def iamList =[1,2,3,4,5] //定義一個List

iamList.each{//調用它的each,這段代碼的格式看不懂了吧?each是個函數,圓括號去哪了?

println it

}

上面代碼有以下知識點:

each函數調用的圓括號不見了!原來,Groovy中,當函數的最後一個參數是閉包的話,可以省略圓括號。比如

deftestClosure(int a1,String b1, Closure closure){

//dosomething

closure() //調用閉包

}

那麼調用的時候,就可以免括號!

testClosure4, "test", {

println"i am in closure"

}

開始你的Gradle構建和編程之旅吧~~

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved