android之Gradle構建專案流程
對於android開發,java語言那肯定都是很熟悉了,但對於android專案的構建應該就不是那麼的瞭解了,android專案的構建是通過gradle,而gradle所使用的語言確實groovy,這對於很多人來說可能就不是那麼的瞭解,groovy是基於java語言,並且也是支援java語言的,所以我們在gradle中使用java語言也是可以編譯通過的。
對於剛接觸java語言的人來說,程式的入口那就是main()函數了,這也是大家都懂的,但對於gradle而言,我們卻不知道他是從何開始執行的,因為我們沒有發現他的main()函式在哪裡,這裡有一點需要明白,groovy是指令碼語言,我們在groovy中編寫一段程式碼,不需要寫類,他就可以直接執行起來,其實,groovy在編譯的時候也是會先將我們所寫的程式碼塊編譯成java的類,然後在執行起來的,實際上gradle是會將我們的程式碼編譯成class檔案然後在main()函式中執行起來,只不過這個過程全部封裝到了gradle外掛中,我們沒看到而已。
gradle是一個外掛,是用來組織android各個module的,要想對gradle有一個比較清晰的瞭解,得先熟悉gradle中的幾個物件:
1、Gradle物件;
2、Settings物件;
3、Project物件;
一個工程只有一個gradle物件,一個Settings物件,多個Project物件,每次修改了.gradle檔案時,都會有這樣的字樣要求我們同步工程,點選後其實gradle外掛就會先創建出一個Gradle物件,這個物件會先去讀取settings.gradle檔案,構建Settings物件,在有了Settings物件後,根據裡面的內容就可以構建出Project物件,Project物件的構建個數與Settings中配置個數有關。
說了這麼多之後,可能會有有些迷糊,下面我們就在實際的工程中來看下它的執行流程,畢竟程式碼才能讓我們更直觀的瞭解,首先來看下工程的一個目錄結構:
這裡主要看的就是這些.gradle檔案,首先來看settings.gradle這個檔案,在這個檔案裡添加了一些程式碼,主要是用來監聽gradle執行到哪了:
include ':app', ':netlib' gradle.addBuildListener(new BuildListener() { //Called when the build is started //看文件註釋說這裡一開始構建就會執行,但就是沒看見的列印的log @Override void buildStarted(Gradle gradle) { println "gradle start ======================================== " } //Called when the build settings have been loaded and evaluated. The settings object // is fully configured and is ready to use to load the build projects //Settings物件載入和評估完成後執行這裡,執行完這裡即將開始構建Project物件 @Override void settingsEvaluated(Settings settings) { println "setting evaluated = "+settings.rootProject.children } //Called when the projects for the build have been created from the settings. // None of the projects have been evaluated //當所有的Project物件構建完後會執行到這裡,執行到這裡時,Project還沒有評估 @Override void projectsLoaded(Gradle gradle) { gradle.allprojects { project -> println "project name = "+project.name } println "projects load" } //Called when all projects for the build have been evaluated. The project objects // are fully configured and are ready to use to populate the task graph //在所有的Project物件構建完並且已經評估後會執行到這裡,之後就開始執行Project中的任務了 @Override void projectsEvaluated(Gradle gradle) { println "projects valuated" } //Called when the build is completed. All selected tasks have been executed. //所有的Project(包括任務)構建完後執行這裡 @Override void buildFinished(BuildResult result) { println "build result = "+result } }) gradle.addProjectEvaluationListener(new ProjectEvaluationListener() { //This method is called immediately before a project is evaluated. //Project開始評估執行這裡 @Override void beforeEvaluate(Project project) { println "before evaluated = "+project.name } // This method is called when a project has been evaluated, and before // the evaluated project is made available to other projects. // Project評估完執行這裡,評估成功後就開始評估下一個Project @Override void afterEvaluate(Project project, ProjectState state) { println "after valuated = "+project.name } })
上面每個方法都有註釋,英文註釋是從文件中拷過來的,中文就是我自己的理解了,接下來就來看下它的輸出:
Executing tasks: [:netlib:generateDebugSources, :app:generateDebugSources]
setting evaluated = [:app, :netlib]
projects load
project name = NetRequest
project name = app
project name = netlib
Configuration on demand is an incubating feature.
before evaluated = NetRequest
after valuated = NetRequest
before evaluated = netlib
after valuated = netlib
before evaluated = app
after valuated = app
projects valuated
:netlib:preBuild UP-TO-DATE
... ...
:app:generateDebugSources UP-TO-DATE
BUILD SUCCESSFUL in 3s
23 actionable tasks: 23 up-to-date
build result = [email protected]
這裡可能對這段log在哪輸出不太明白,剛開始切換到android studio 3.0的時候我也是找了好半天才找到,在3.0之前和之後是有一點變化的,現在用的是3.1的,那這裡說的是3.0之後版本的輸出位置:
點選這兩個地方就可以檢視工程build時的日誌。
繼續回到上面的輸出日誌,我們發現,在settings.gradle中我們只配置兩個Project,但是從答應的日誌看是有三個Project的,那多出來的一個是哪裡的呢?這個其實是rootProject,意思就是說settings.gradle配置的Project都有一個共同的根Project,也就是在我們專案的根目錄,通過輸出的日誌我們大致可以推斷出gradle的一個執行流程,這個可以自己在android studio上敲一敲,加深下印象,好好理解理解。
看了settings.gradle後,接下來就來看下rootProject的build.gradle的配置,就是和settings.gradle在同一目錄下的那個:
apply from: 'config.gradle'
buildscript {
//這裡的配置主要是為了構建gradle
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
//這裡是為每一個project提供相同的配置
println "common config project name = "+project.name
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
這裡在allproject列印了一個project.name,再來看下build時的輸出:
common config project name = NetRequest
common config project name = app
common config project name = netlib
說明每個peoject都執行到了這裡,也就是說每個project都用到了這裡的配置,這裡的配置有什麼用呢?一個專案都會有許多的庫依賴,對於一個庫依賴,一般都是新增一個引用就可以載入進來,那這個庫是從哪裡載入進來的呢?這裡的配置就是提供庫載入的倉庫,當識別到一個引用時,就會到倉庫中去將這個庫載入處理,如果倉庫中沒有找到,那麼就會報異常了。
這裡在總結下gradle的大體流程:
1、開始build的時,會建立一個Gradle物件,這個物件是唯一的,全域性共享;
2、Gradle物件建立完後,接下來就是去怎麼組合整個工程了,為了知道需要組合那些project,這時就需要去讀取settings.gradle檔案了,這時就會建立一個Settings物件,這個物件中就會包含組合工程所需的各個project,以及各個project的地址(其實就是在那個資料夾下),這個地址我們是可以修改的,具體怎麼修改,下一遍再說;
3、在讀取settings.gradle檔案的同時,也是會建立相應的project,只不過這個project沒有被評估(我的理解就是沒被初始化),剩下的就是對每個project進行評估,最後在對整個工程進行評估,在這些都做完之後,接下來就是執行每個project的task了,等到所有任務都執行完了,整個工程也就build完了,也就可以執行起來了。