【android 應用】關於gradle的一份學習總結報告,請查收。

一、瞭解gradle

1.概述

1.1 gradle是什麼

gradle是一款基於JVM的專注於靈活性和性能的開源構建工具。
gradle用的是一種基於 Groovy 的領域特定語言(DSL,Demain Specific Language)來聲明項目設置,摒棄了 XML(如 ANT 和 Maven)的各種繁瑣配置。

1.2 作用

1.3 爲什麼用gradle?

附上:Gradle官網:https://gradle.org

2.Android gradle plugin

Android gradle plugin是Gradle插件,也就是AndroidStudio用於開發Android項目的gradle插件。
gradle是構建工具,可以構建java應用,web應用。而gradle plugin只是google用來構建android應用的一個android studio插件。

3.gradle wrapper

每個基於gradle構建的工程都有一個gradle本地代理,叫做 gradle wrappe。在 /gradle/wrapper/gralde-wrapper.properties 目錄中聲明瞭指向目錄和版本。

每一個Wrapper都會綁定到一個特定版本的Gradle,當用戶第一次執行如下的命令時,Wrapper會自動地下載並安裝對應版本的Gradle,方便用戶構建項目。

 

二、Groovy基本語法

1、基礎語法

1、語句可以不以分號結尾

2、函數調用可以不需要參數括號

println 'hello world'

3、動態類型

Groovy 定義變量的方式和 Java 是類似的,區別在於 Groovy 提供了def關鍵字供使用,它可以省略變量類型的定義,根據變量的值進行類型推導。

如:
def a = 123
def b = 'b'
def c = true
boolean d = false
int e = 123

4、函數寫法

Groovy 方法的默認訪問修飾符是public,方法的返回類型可以不需要聲明,但需添加def關鍵字。有返回值的方法return可以被省略,默認返回最後一行代碼的運行結果,如果使用了return關鍵字則返回指定的返回值。

例:
String method1() {
   return 'hello'
}
assert method1() == 'hello';
def method2() {
   return 'hello'
}
assert method2() == 'hello';
def method3() {
   'hello'
}
assert method3() == 'hello';
Groovy 方法的參數類型可以被省略,默認爲Object類型。
例:
def add(int a, int b) {
   return a + b
}
//與上面的等價
def add(a, b) {
   a + b
}

Groovy 方法的其他特性與Java一樣,比如支持重載、不定長參數(…)等。

5、不需要main函數

在Java中要輸出“hello world”需要像下面這樣,創建一個類,然後創建一個main方法。

public class Hello {
   public static void main(String[] args) {
       System.out.println("hello world");
   }
}

在Groovy中,這些都可以省略,實例如下:

例:在文本中寫如下groovy語句

println 'Groovy world!'

上面我們寫的groovy文件編譯後的class其實是Java類,該類從Script類派生而來(查閱API);可以發現,每個腳本都會生成一個static main方法,我們執行groovy腳本的實質其實是執行的這個Java類的main方法,腳本源碼裏所有代碼都被放到了run方法中,腳本中定義的方法(該例暫無)都會被定義在Main類中。如下:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
   def run() {
       println 'Groovy world!'
   }
   static void main(String[] args) {          
       InvokerHelper.runScript(Main, args)    
   }
}

6、Groovy快速入門博客

https://www.jianshu.com/p/e8dec95c4326

2、閉包

閉包其實就是一段代碼塊。在gradle中,我們主要是把閉包當參數來使用

例如1:
//定義一個閉包
def b1 = {
   println “hello b1”
}
//定義一個方法,方法裏面需要閉包類型參數
def method1 (Closure closure) {
   closure()
}
//調用方法
method1(b1)
結果:輸出hello b1

例如2:
//定義一個閉包,帶參數
def b2 = {
   v->
       println "hello ${v}"
}
//定義一個方法,方法裏面需要閉包類型參數
def method2 (Closure closure) {
   closure("xiaoma")
}
//調用方法
method2(b2)
結果:輸出hello xiaoma

例如3:
//多個參數以逗號分隔,參數類型和方法一樣可以顯式聲明也可省略。
def closure = { String x, int y ->                                
   println "hey {y}"
}

3、元編程

groovy運行時類方法調用流程:

在java中,如果對象調用了一個類中沒有定義過的方法時,連編譯都編譯不過,但是在groovy中,情況則不同(可以編譯通過),根據圖中流程可以知道,運行期間,當對象調用了一個類中沒有的方法時,會依次調用metaClass中的同名方法,類中的methodMissing(String name, Object args)方法,類中的invokeMethod(String name, Object args)方法,執行到其中一個便停止後續方法查找調用。

三、Gradle項目編譯

1.Android Gradle項目結構

含有兩個子模塊(app和remoteDiagnosisLibrary)的項目結構如下:

1.1gradle.properties

可以在 gradle.properties 文件中配置一些變量,這些變量在這個工程下的所有module的build.gradle文件裏都可以使用。這樣就可以把一些共用的變量放到這裏,這樣後面修改的時候就可以只修改這個變量,不用各個模塊都要修改了。
上圖項目結構中的gradle.properties如下:

1.2settings.gradle

Gradle試圖找到一個設置(settings.gradle)。爲此,運行時將目錄樹的層次結構遍歷到根目錄。一旦找到設置文件,算法就停止搜索。
總是添加一個設置到構建的根目錄,以避免初始性能影響。
上圖項目結構中的settings.gradle如下:

1.3build.gradle

配置腳本文件名默認是不變的build.gradle,每一個project(模塊)對應一個build.gradle。

2.編譯執行流程

一次Gradle的工作流分爲3大部分:

第一:初始化。
Gradle支持單個和多個項目的構建。在初始化階段,Gradle確定哪些項目將參與構建,併爲每個項目創建一個項目實例。
第二:配置。
在此階段,將配置項目對象。作爲構建的一部分的所有項目的構建腳本都被執行。
第三:執行。
Gradle確定在配置階段創建和配置的要執行的任務的子集。子集由傳遞給gradle命令和當前目錄的任務名參數決定。然後Gradle執行每一個選擇的任務。

實例1:創建task

task haha{
    println("hahaha")
    doLast{
        println("ccccc")
    }
    doFirst{
        println("aaaaa")
    }
    doLast{
        println("bbbbbb")
    }
    println("endendend")
}

注:
doFirst:將給定添加Action到此任務的操作列表的開頭。
doLast:將給定添加Action到此任務的操作列表的最後。

執行haha task,結果如下

Configure project:打印表明是第二階段:配置階段
Task:haha打印表明是第三階段:執行階段

這個地方特別理解一下:

1、dolast方法創建的任務,在配置階段只是創建執行的任務,真正執行是在執行階段。所以hahaha打印在configure階段,cccccc打印在task階段

2、執行階段task的順序

沒有順序之前是按照字母順序排列,可以通過依賴方法(dependsOn)、doFirst、doLast調整順序

 

3.模塊Project

1、每個項目都會有自己的gradle領域,配置腳本文件名默認是不變的build.gradle
2、Project之間如果出現父子關係,只有根Project纔會有setting.gradle配置文件,該配置文件的作用是聲明其包含的子項目。
3、Project代表一個項目,在jvm中的一個實例。Build.gradle中無主的方法都可以在project中找到

4.任務Task介紹

1.概述

task,如其名:任務,gradle就是由一個一個任務來完成的。他其實也是一個類,有自己的屬性,也可以"繼承",甚至他還有自己的生命週期。Task是構建中的最小執行單元。
task的基類是DefaultTask ,我們也可以自定義一個task,必須繼承DefaultTask,如下:

class MyTask extends DefaultTask {
   String message = 'This is MyTask'
   // @TaskAction 表示該Task要執行的動作,即在調用該Task時,hello()方法將被執行
   @TaskAction
   def hello(){
       println "Hello gradle. $message"
   }
}

2.默認Task

Gradle 允許在腳本中定義一個或多個默認任務.

2.1 添加默認任務的方法

在build.gradle中調用defaultTasks方法,將要設置成默認的task方法傳入進去。

2.2 實例
build.gradle

defaultTasks 'clean', 'run'
task clean << {
   println 'Default Cleaning!'
}
task run << {
   println 'Default Running!'
}
task other << {
   println "I'm not a default task!"
}

gradle -q 命令的輸出:

gradle -q
Default Cleaning!
Default Running!

結果等價於執行編譯命令gradle clean run。

在一個多項目構建中, 每一個子項目都可以有它特別的默認任務. 如果一個子項目沒有特別的默認任務, 父項目的默認任務將會被執行.

3.自定義Task

如下:vpsclient項目的gradle.build中創建了一個clean任務。

4.Gradle、Settings、Project、Task之間關係

Gradle

表示對Gradle的調用。

Settings

聲明實例化和配置Project要參與構建的實例的層次結構所需的配置。
對應的文件是setting.gradle。

Project

Project代表一個項目,在jvm中的一個實例。該接口是用於與構建文件中的Gradle交互的主要API。從中Project,您可以通過編程方式訪問Gradle的所有功能。
Project和build.gradle 文件之間存在一對一的關係。

Task

Task代表構建的一項基本工作,例如編譯類或生成javadoc。

四者之間的聯繫:
1、執行gradle命令時,會創建一個gradle對象。
2、在構建初始化過程中,Gradle爲每個要參與構建的項目裝配一個項目對象,具體如下:

爲構建創建Settings實例。
Settings。gradle腳本,如果存在,針對設置對象來配置它。
使用已配置的Settings對象創建Project實例的層次結構。
最後,Project通過build.gradle針對項目執行其文件(如果存在)來評估每個文件。這些項目以廣度順序進行評估,因此在其子項目之前先對其進行評估。可以通過調用Project.evaluationDependsOnChildren()或添加使用的顯式評估依賴項來覆蓋此順序Project.evaluationDependsOn(java.lang.String)。

3、Project本質上是Task對象的集合。每個Task都屬於一個Project。

四、Gradle配置

1、Build.gradle配置文件Demo

重要的屬性:

android屬性

設置編譯android項目的參數,構建android項目的所有配置都寫在這裏。
實例說明:

android {
   // 編譯SDK的版本
   compileSdkVersion 22
   // build tools的版本
   buildToolsVersion "23.0.1"
   //aapt配置
   aaptOptions {
       //不用壓縮的文件
       noCompress 'pak', 'dat', 'bin', 'notice'
       //打包時候要忽略的文件
       ignoreAssetsPattern "!.svn:!.git"
       //分包
       multiDexEnabled true
       //--extra-packages是爲資源文件設置別名:意思是通過該應用包名+R,com.android.test1.R和com.android.test2.R都可以訪問到資源
       additionalParameters '--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'
   }
   //默認配置
   defaultConfig {
       //應用的包名
       applicationId "com.example.heqiang.androiddemo"
       minSdkVersion 21
       targetSdkVersion 22
       versionCode 1
       versionName "1.0"
   }
   //編譯配置
   compileOptions {
       // java版本
       sourceCompatibility JavaVersion.VERSION_1_7
       targetCompatibility JavaVersion.VERSION_1_7
   }
   //源文件目錄設置
   sourceSets {
       main {
            //jni lib的位置
            jniLibs.srcDirs = jniLibs.srcDirs << 'src/jniLibs'
            //定義多個資源文件夾,這種情況下,兩個資源文件夾具有相同優先級,即如果一個資源在兩個文件夾都聲明瞭,合併會報錯。
            res.srcDirs = ['src/main/res', 'src/main/res2']
            //指定多個源文件目錄
            java.srcDirs = ['src/main/java', 'src/main/aidl']
       }
   }
   //簽名配置
   signingConfigs {
       debug {
           keyAlias 'androiddebugkey'
           keyPassword 'android'
           storeFile file('keystore/debug.keystore')
           storePassword 'android'
       }
   }
   buildTypes {
       //release版本配置
       release {
           debuggable false
           // 是否進行混淆
           minifyEnabled true
           //去除沒有用到的資源文件,要求minifyEnabled爲true才生效
           shrinkResources true
           // 混淆文件的位置
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
           signingConfig signingConfigs.debug
           //ndk的一些相關配置,也可以放到defaultConfig裏面。
           //指定要ndk需要兼容的架構(這樣其他依賴包裏mips,x86,arm-v8之類的so會被過濾掉)
           ndk {
               abiFilter "armeabi"
           }
       }
       //debug版本配置
       debug {
           debuggable true
           // 是否進行混淆
           minifyEnabled false
           //去除沒有用到的資源文件,要求minifyEnabled爲true才生效
           shrinkResources true
           // 混淆文件的位置
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
           signingConfig signingConfigs.debug
           //ndk的一些相關配置,也可以放到defaultConfig裏面。
           //指定要ndk需要兼容的架構(這樣其他依賴包裏mips,x86,arm-v8之類的so會被過濾掉)
           ndk {
               abiFilter "armeabi"
           }
       }
   }
   // lint配置
   lintOptions {
     //移除lint檢查的error
     abortOnError false
     //禁止掉某些lint檢查
     disable 'NewApi'
   }
}

除了上面寫的,在android{}塊中可以包含以下直接配置項:
productFlavors{ } 產品風格配置,ProductFlavor類型
testOptions{ } 測試配置,TestOptions類型
dexOptions{ } dex配置,DexOptions類型
packagingOptions{ } PackagingOptions類型
jacoco{ } JacocoExtension類型。用於設定 jacoco版本
splits{ } Splits類型。

dependencies屬性

gradle中所有的jar包的座標都放在這個屬性內,每個jar包都包含三個基本元素(group,name,version)。

2、Gradle構建語言幫助文檔地址

Gradle配置Build.gradle腳本語言幫助文檔地址:

https://docs.gradle.org/current/dsl/

3、修改成國內源(阿里源)

在 project 的 build.gradle中修改如下:

allprojects {
   repositories {
       //jcenter()
       maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
   }
}

然後點擊 gradle rync 即可。

4、自定義gradle插件

4.1 二進制插件

apply plugin: 'xxx'   //聲明引用插件的類型

如騰訊shadow中buildScripts/gradle/maven.gradle:

4.2 應用腳本插件

apply from:'xxx'   //表示引用其他的配置文件

如騰訊shadow中gradle.build:

就是引用了buildScripts/gradle/下面的兩個配置文件

五、Gradle自定義構建

1、構建的變體

1.1 概述

構建變體是構建版本和生產版本的結合體。當你創建了一個構建版本或者生產版本,同樣的,新的變體也會被創建。

像下圖便有這麼多的變體:

1.2 創建構建變體

flavorDimensions "channel","money"
android {
   productFlavors {
      vivo {
           dimension "channel"
           applicationId "vivo"
           versionCode 1
           minSdkVersion 15
       }
       oppo {
           dimension "channel"
           applicationId "oppo"
           versionCode 2
           minSdkVersion 15
       }
       free {
           dimension "money"
           resValue "color", "colorfree", "#ff8888"
       }
       vip {
           dimension "money"
           resValue "color", "colorfree", "#ff0000"
       }
   }
}

2、自定義構建流程

2.1在某任務之前執行

Task diyTask = project.task('diyTask') {
   doLast {
       Utils.println("diy task run")
   }
}
project.tasks.whenTaskAdded { Task theTask ->
   if (theTask.name == 'assembleDebug') {
       theTask.dependsOn(diyTask)
       theTask.mustRunAfter(diyTask)            // diyTask在assembleRelease之前執行
   }
}

2.1在某任務之後執行

Task diyTask = project.task('diyTask') {
   doLast {
       Utils.println("diy task run")
   }
}
project.tasks.whenTaskAdded { Task theTask ->
   if (theTask.name == 'assembleRelease') {
       theTask.dependsOn(diyTask)            // diyTask在assembleRelease之後執行
   }
}

 

六、Gradle命令

1、任務查詢和運行命令

查看任務

./gradlew tasks

查看所有任務 包括緩存任務等

./gradlew tasks --all

對某個module [moduleName] 的某個任務[TaskName] 運行

./gradlew :moduleName:taskName

2、快速構建命令

查看構建版本

./gradlew -v

清除build文件夾

./gradlew clean

檢查依賴並編譯打包

./gradlew build

編譯並安裝debug包

./gradlew installDebug

編譯並打印日誌

./gradlew build --info

譯並輸出性能報告,性能報告一般在 構建工程根目錄 build/reports/profile

./gradlew build --profile

調試模式構建並打印堆棧日誌

./gradlew build --info --debug --stacktrace

強制更新最新依賴,清除構建並構建

./gradlew clean build --refresh-dependencies

3、指定構建目標命令

編譯並打Debug包

./gradlew assembleDebug

這個是簡寫 assembleDebug

./gradlew aD

編譯並打Release的包

./gradlew assembleRelease

這個是簡寫 assembleRelease

./gradlew aR

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章