1. 程式人生 > >android之Gradle構建專案流程

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完了,也就可以執行起來了。