深刻理解Android之Gradle: http://blog.csdn.net/innost/article/details/48228651javascript
Gradle完整指南(Android):http://www.jianshu.com/p/9df3c3b6067aphp
Gradle學習系列:http://www.kancloud.cn/digest/itfootball-gradle/html
Gradle官方網站:https://gradle.org/java
Groovy的API文檔:http://www.groovy-lang.org/api.htmlpython
Gradle 各版本下載
:http://services.gradle.org/distributions/Gradle_Recipes_for_Android.pdf
,Android構建的實用文檔: http://pan.baidu.com/s/1kVnq4WBBuilding_and_Testing_with_Gradle.pdf
,通用的構建與測試文檔: http://pan.baidu.com/s/1jIM4wgIGradle User Guide.pdf
,官方給出的使用手冊: http://pan.baidu.com/s/1qYIozFmGroovy
語言,可是其其實是基於Java語言的,因此在編寫腳本的時候能夠直接使用Java語言。Groovy
語言基礎雖然在編寫腳本的時候能夠直接使用java代碼,可是使用腳本化語言更加的清晰。android
Groovy
開發環境配置參看:http://www.jianshu.com/p/777cc61a6202git
Groovy註釋標記和Java同樣,支持//或者/**/ github
Groovy語句能夠不用分號結尾web
Groovy中支持動態類型,即定義變量的時候能夠不指定其類型,Groovy中,變量定義可使用關鍵字def,注意,雖然def不是必須的,可是爲了代碼清晰,建議仍是使用def關鍵字api
Groovy中每個對象的成員變量會自動爲它生成getter
和setter
函數,因此咱們能夠直接調用其成員變量或者對應方法。
var0 = "no def no type"
def var1 = 1 //能夠不使用分號結尾
def var2 = "I ama person"
def int x = 1 //變量定義時,也能夠直接指定類型
String testFunction(arg1,arg2){//無需指定參數類型
...
}
//無類型的函數定義,必須使用def關鍵字
def nonReturnTypeFunc(){
last_line //最後一行代碼的執行結果就是本函數的返回值
}
//若是指定了函數返回類型,則可沒必要加def關鍵字來定義函數
String getString(){
return"I am a string"
}
println("123") -> println "123"
def var = 123
println "i am a $var" // 最後打印 i am a 123
str = ''' 1223 122 556 '''
?.
運算符,至關於不爲空,則執行某個操做list?.size()
//等同於
if(list != null){
list.size()
}
*.
運算符,用於對集合類型的對象的每一個元素執行相同的方法,返回值爲大小和該集合元素相同的List。def smaple = ['123','1','12345']
println smaple*.size()
.&
方法做爲一個閉包參數傳遞def list = {1, 2, 3}
list.each{
println it
}
int printNumber(int number){
println number
}
//做爲方法做爲一個閉包傳遞
list.each(this.&printNumber)
.@
直接調用字段,在groovy中直接使用.
調用的是對應的getter方法class Todo {
String name
def getName() {
println "Getting Name"
name
}
}
def todo = new Todo(name: "Jim")
println todo.name
println todo.@name
========
result:
Getting Name
Jim
Jim
?:
替代Java
的三目運算符String name= person.name ? person.name : 'unknown'// java的寫法
def name2= person.name ?: "unknown" // Groovy 的寫法
主要介紹一下三種數據類型:
Groovy做爲動態語言,其中一切事物都是對象,因此即便是基本數據類型,其也是被轉化爲相應的對象的。
def int var = 123
println var.getClass().getName() //打印的結果爲 java.lang.Integer
Groovy中的容器類就三種:
//定義list變量,使用[]方式來定,其元素能夠是任何的對象
def testList = [123, "string", true]
//元素的存儲,注意咱們不須要擔憂越界的問題,當越界了,groovy會自動增長list的容量
assert testList[1] == "string"
assert testList[3] == null //此時第4個元素是不存在的,能夠自動增長
//直接設置越界索引的元素的值
testList[999] = 999
//打印testList的大小
println testList.size //結果爲 1000
//變量的定義,使用[key:value,......]的方式定義,value能夠是任何類型的對象,key可使用''或者""包裹起來,若是不作處理則表示默認爲字符串
def map = [key1: "value1", "321": true, 123:"value2"] //key1被默認爲'key1'
//若是key要表示特定的類型或外部定義的變量的值,則使用"()"包裹起來。
def test = "999"
def map1 = [(test):"1000"]
//元素的存取,兩種方式, map.keyName map[keyName]
println map."key1" + " " + map."123" //結果爲 value1 null, 注意使用map."123" 方式獲取到的值爲null
println map1[test] + " " + map[123] //1000 value2,使用map[123]才能正確的獲取到key值
//新增/修改元素 map.keyName = value
map."321" = false
println map."321"
map1["test2"] = "I an test 2"
println map1["test2"]
Range
繼承自List,一種更方便的有序集合類型。
//def
def range = 10..1000 //表示從10到1000之間的元素
def range2 = 10..<1000 //使用'<'表示包含最後一個元素值
//打印
println range.from
println range.get(2)
println range.to
閉包其表示一段能夠執行的代碼塊,看起來是函數與對象的結合體,閉包的最後一行是閉包的返回值,關於閉包能夠參考:
def closure = {
parm1, parm2 -> // ->前是閉包的入參,若是沒有參數,則能夠直接省略這一行代碼
code
...
code //最後一行代碼,無論有沒有return關鍵詞,都表示閉包的返回值
}
//example
def testClosure = {
x, y ->
x = x + y
x
}
//使用closure.call
def val = testClosure.call(3, 4)
println val
//使用closure(參數)
def val2 = testClosure(5, 6)
println val2
it
,它的做用和this
類似。def itClosure = {"hello kitty $it"}
//其等同於:
// def itClosure = {it -> "hello kitty $it "}
println itClosure('funny')
//可是若是在定義閉包時,顯式的使用 ->,並且前面沒有任何的參數,則表示正真沒有任何參數,若是調用時傳入參數會報錯
def noParamClosure = { -> "no param"}
println noParamClosure('it')//該行代碼會報錯
def simpleFunction(int x, String str, Closure c){
c.call(x, str) //在函數中調用閉包,並使用它做爲返回值
}
def val = simpleFunction 4, " is a four", {x, str -> x + str}
println val
//仍是上面的例子,使用閉包作爲參數
def simpleFunction(int x, String str, Closure c){
c.call(x, str) //注意此處調用閉包時傳遞了兩個參數,分別爲x, str
}
//咱們在調用該方法時,傳入閉包參數時,注意參數的個數,類型要與函數調用時保持一致
def val = simpleFunction 4, " is a four", {x, str -> x + str} //此爲正常調用
//如下都會報錯,groovy.lang.MissingMethodException: No signature of method: ConsoleScript3$_run_closure2.call() is applicable for argument types:(java.lang.Integer, java.lang.String) values: [5, tsttt]
Possible solutions: any(), any(), doCall(調用時傳入的參數類型)......
def val1 = simpleFunction 5, "tsttt", {x-> x}
def val2 = simpleFunction 5, "tsttt", {->'hahahh'}
def val3 = simpleFunction 5, "tsttt", {String str, String str2 -> str1 + str2}
xxx.groovy
文件編譯成class文件//在命令行執行以下命令,編譯成class文件
groovyc-d classes xxx.groovy
編譯成class以後可使用jd-gui工具反編譯成java類進行查看。
//獲取文件對象
def file = new File('e:/source/groovy/test.groovy')
//讀取每一行並打印
file.eachLine{
String strLine -> println strLine
}
//一次性獲取全部的文件內容
byte[] bytes = file.getBytes() //注意此處能夠直接使用file.bytes
println bytes.length
//使用閉包的方式用inputstream流來讀取,注意它的好處不用手動去關閉輸入流
file.withInputStream{
is -> println(is.getText())
}
//
def writeFile = new File('e:/source/groovy/test2.groovy')
//寫入數據,從新開始寫,原來的數據會被清除,若文件不存在,則自動建立
writeFile.write("this is the first line")
//添加數據到最末尾
writeFile.append("this is add by append")
//使用流從一個文件讀入寫入到這個文件,原文件中的數據會別清除
def readFile = new File('e:/source/groovy/test.groovy')
writeFile.withOutputStream{
os ->
readFile.witInputStream{
is ->
os << is //重載了<< 符號,將輸入流的數據傳遞給輸出流
}
}
未完待續。
Gradle
概述Gradle
是一種DSL(特定領域)腳本構建框架,編寫腳本使用的是Groovy語言(也能夠直接使用Java語言)。Gradle
、Groovy
、Java
的API方法。//咱們構建Android APP項目使用的插件是:
apply plugin: 'com.android.application'
//若是是構建一個library項目讓其餘的項目引用
apply plugin: 'com.android.library'
因此咱們在腳本中可以使用的特定的方法、屬性都是各類腳本決定的。
Gradle
和Android Gradle Plugin
的官方幫助文檔Gradle releaseNote
(Gradle最新版本發佈說明):https://docs.gradle.org/current/release-notesGradle User Guide
(最新版本用戶指導手冊):https://docs.gradle.org/current/userguide/userguide.htmlGradle DSL Reference
(最新領域語言說明):https://docs.gradle.org/current/dsl/Gradle Api JavaDoc
(JavaDoc說明):https://docs.gradle.org/current/javadoc/Goolge Gradle Plugin GitHub
(Google gradle 插件GitHub地址):https://github.com/google/android-gradle-dslGradle Android Plugin DSL Reference
(最新版本插件領域語言說明):http://google.github.io/android-gradle-dsl/current/Gradle Android Plugin Api JavaDoc
(最新版本插件API文檔):http://google.github.io/android-gradle-dsl/javadoc/current/build.gradle
文件與之對應,查看project命令:gradle projects
gradle tasks
//多項目查看某個項目下的tasks,或者直接cd 到想查看的項目目錄下面去,執行上面的命名。
gradle project_path:tasks
//拷貝complie 這個configuration的文件到指定目錄中
task copyAllDependencies(type: Sync) {
//referring to the 'compile' configuration
//拷貝全部編譯時依賴的文件如jar,aar等等
from configurations.compile
into 'build/output'
exclude 'recyclerview-v7-24.0.0-alpha1.aar' //過濾掉這個包
}
添加自定義的artifacts到指定的Configuration中:
//Configuration的申明:
configurations {
testConfig
//也能夠繼承
//testConfig.extendsFrom(compile)
}
//壓縮so任務
task testZip(type:Zip){
baseName = 'armeabi'
println 'ready to copy!!!!'
println(rootProject.projectDir.absolutePath + '\\app\\libs\\armeabi\\')
from rootProject.projectDir.absolutePath + '\\app\\libs\\armeabi\\'
}
//關聯一個自定義的文件Map
def map = [file:new File(rootProject.projectDir.absolutePath + '/app/debug.jks')]
artifacts{
testConfig map
//這裏也能夠直接傳入AbstractArchiveTask類型的task(如Jar,Zip),也能夠直接傳入File對象
//testConfig new File(rootProject.projectDir.absolutePath + '/app/debug.jks')
//testConfig testZip
}
//使用配置項,用於Copy task的from參數
//copying all dependencies attached to 'compile' into a specific folder
task copyAllDependencies(type: Sync) {
//referring to the 'compile' configuration
//注意不能直接傳遞allArtifacts對象,要調用其getFiles()方法
from configurations.testConfig.allArtifacts.getFiles()
into 'build/output'
}
先看一個簡單的執行流程圖:
建立Gradle對象,在執行任何一條gradle命令時,都會先建立一個全局惟一的Gradle對象,該對象能夠保存一些全局的基本的值。
建立Setting對象,Gradle每次構建都會建立一個Setting對象,若是存在settings.gradle文件則會去解析該文件配置Setting對象。一個setting.gradle文件對應一個Setting對象,當項目依賴編譯多個項目時,就須要在settings.gradle中include須要編譯的與依賴的項目。後面看DSL文檔會Setting對象持有一個rootProject對象,注意該對象的類型爲ProjectDescriptor
,而不是Project。
建立Project對象,在配置完Setinng對象後,開始建立Project對象,默認的建立的順序:先建立rootProject 對象(注意這裏的類型爲Project),子模塊的對象的建立依照settings.gradle文件中include的順序進行。
解析上一步建立對象對應的build.gradle文件,按序添加task執行順序,在解析完全部的Project對象後,最終會生成一個有向無環圖表示全部須要執行task的執行順序,注意解析文件是在其對應的Project對象後進行,而不是全部的Project對象建立後再進行。
依據上一步生成的有向無環圖,執行腳本。
DSL中對Project生命週期的描述:
Lifecycle
- There is a one-to-one relationship between a Project and a build.gradle file. During build initialisation, Gradle assembles a Project object for each project which is to participate in the build, as follows:
- Create a Settings instance for the build.
- Evaluate the settings.gradle script, if present, against the Settings object to configure it.
- Use the configured Settings object to create the hierarchy of Project instances.
- Finally, evaluate each Project by executing its build.gradle file, if present, against the project. The projects are evaluated in breadth-wise order, such that a project is evaluated before its child projects. This order can be overridden by calling Project.evaluationDependsOnChildren() or by adding an explicit evaluation dependency using Project.evaluationDependsOn(java.lang.String).
在上面步驟中的3-4之間,Gradle給咱們提供了一個鉤子函數gradle.beforeProject
,能夠作一些額外的自定義操做:
//若是該鉤子在setting.gradle中申明,每個對象建立都會執行一次
gradle.beforeProject{rootProject ->
println 'in xxx build.gradle beforeProject called!!!'
println rootProjct.rootDir
}
一樣在4-5之間也可使用鉤子函數gradle.taskGraph.whenReady
,該函數在創建完有向圖後執行腳本以前調用:
gradle.taskGraph.whenReady {
println 'in xxx build.gradle whenReady called!!!'
if(rootProject == project){ //若在rootProject的build.gradle中調用該方法,則會打印
println 'xxx project = rootProject'
}
}
在執行完腳本以後,gradle給咱們提供了一個gradle.buildFinished
鉤子函數供咱們作一些自定義操做:
gradle.buildFinished {
println 'in xxx build.gradle buildFinished called!!!'
}
注意上面的所列舉的三個鉤子函數傳遞的參數都是閉包,是能夠在多個.gradle
文件中調用的,能夠各自實現不一樣的閉包邏輯,可是決定其什麼時候生效取決於調用該方法的.gradle
文件是否已經被解析,文件中調用的鉤子函數是否被添加到監聽器列表中,好比在rootProject
的build.gradle
中是沒法監聽到它本身的beforeProject
鉤子的,由於調用該鉤子函數時,build.gradle
都尚未被解析,因此咱們須要在setting.gradle
中聲明鉤子。
Gradle
對象Gradle
對象每次執行腳本時,建立的一個惟一的對象,它表示一次腳本的執行,它一直存在於腳本執行的各個階段。如下是它屬性的截圖,前面說到的不少鉤子函數都屬於這個類。
Settings
對象肯定本次build須要配置Project以及執行順序和依賴關係,多個項目關聯編譯時須要用到這個對象,全局惟一,在Android Studio項目一般根目錄下存在一個settings.gradle
文件,咱們能夠經過它來配置Settings
對象。
參考文檔: Gradle命令行用戶指導:https://docs.gradle.org/current/userguide/gradle_command_line.html
- 查看Gradle
版本號
gradle -v
gradle task1
//執行多個task
gradle task1 task2
//靜默執行task,還有其餘三種模式
gradle -q task
//過濾task2不執行,加-x參數
gradle task1 -x task2
gradle projects
gradle tasks
//顯示全部
gradle --gui
gradle --help