Android Gradle(1) 概念及基礎

2022-01-27 享學課堂online

前言

手把手講解系列文章,是我寫給各位看官,也是寫給我自己的。文章可能過分詳細,但是這是為了幫助到儘量多的人,畢竟工作5,6年,不能老吸血,也到了回饋開源的時候.這個系列的文章:

1、用通俗易懂的講解方式,講解一門技術的實用價值2、詳細書寫源碼的追蹤,源碼截圖,繪製類的結構圖,儘量詳細地解釋原理的探索過程3、提供Github 的 可運行的Demo工程,但是我所提供代碼,更多是提供思路,拋磚引玉,請酌情cv4、集合整理原理探索過程中的一些坑,或者demo的運行過程中的注意事項5、用gif圖,最直觀地展示demo運行效果

如果覺得細節太細,直接跳過看結論即可。本人能力有限,如若發現描述不當之處,歡迎留言批評指正。

學到老活到老,路漫漫其修遠兮。與眾君共勉 !

正文大綱

1. gradle是什麼

2. groovy語言的特性以及它和java的關係

3. 為什麼你的apk打包這麼慢

4. 如何利用gradle編程解決工作中的實際問題

5. gradle的高級用法(gradle多渠道快速打包插件)

正文1.gradle 是什麼?

先看看來自百度百科的解釋:Gradle是一個基於 ApacheAnt和 ApacheMaven概念的項目自動化構建開源工具。它使用一種基於 Groovy的特定領域語言 (DSL)來聲明項目設置,目前也增加了基於Kotlin語言的 kotlin-based DSL,拋棄了基於XML的各種繁瑣配置。面向Java應用為主。當前其支持的語言限於 Java、Groovy、Kotlin和Scala,計劃未來將支持更多的語言.

Gradle是一個基於 JVM的構建工具,是一款通用靈活的構建工具,支持 maven,Ivy倉庫,支持傳遞性依賴管理,而不需要遠程倉庫或者是 pom.xml和ivy.xml配置文件,基於 Groovy,build腳本使用 Groovy編寫。

大家懂的,百度百科就是把簡單的一個東西解釋得一般人看不懂。那麼來看看上面一段話中的重點。Gradle 是基於Jvm的項目自動化構建工具 ,可以使用java groovy kotlin 和 scala語言進行編程。它是DSL 特定領域語言,它是專門用來構建項目的.

再解讀並且擴展一下:

Gradle是一個工具,用於構建項目,在 androidStudio的工程目錄中的體現,就是 幫我們把 Android工程中的java源碼文件,資源文件,依賴包,普通配置文件等,經過一系列步驟, 最終生成一個 或者多個apk文件,有了apk文件,才能到 應用市場去發布。

Gradle是一個編程框架, Groovy是該框架常用的程式語言,既然它是語言,那麼就可以進行程序邏輯的編寫,編寫之後,會被編譯成字節碼,交給JVM運行。

項目構建工具,除了 gradle之外,還有 ant, maven,只不過很少使用,已經漸漸轉 gradle.

Gradle在 androidStudio項目中存在的痕跡如下圖(這是一個新建的 project):

上面圖中,上圖中,我標記了1-6,現在來一一解釋:

1.Gradle- Wrapper

gradle的包裝盒,裡面有gradle的jar包,還有properties屬性. Jar包包含的是.class文件,這也就解釋了為什麼gradle的代碼是基於JVM的,可以預見,這個jar包內肯定包含了gradle編譯之後生成的java類,各種api. 然而,事實也證明我的猜想沒有錯。Jar包之外,還有一個.properties.這裡是gradle的一些配置信息,比較重要的是最後一條, distributionUrl 它代表了 gradle工具包的下載路徑.

2.外部的build.gradle

它是全局範圍的構建配置.

3.setting.gradle

但是這裡不僅僅可以定義要編譯的module,還可以進行插件化編程。

4.gradle.properties

gradle的全局配置

5.gradlew 和 gradlew.bat

這兩個,是不同平臺下的可執行文件,前者是 .sh格式,希爾文件,linux下的可執行文件。後者是 window下的批處理命令。

6.module內部的build.gradle綜上所述

Gradle是貫穿了整個android工程的構建工具,幾乎隨處可見gradle的身影,作為高級開發者,如果只知道android的java代碼,寫寫xml,而不懂得gradle編程的話,開發中遇到某些問題( 特別是架構方面的問題),很可能不知所措。

2.groovy語言的特性以及它和java的關係

Gradle的常用程式語言有 java,groovy,kotlin,scala等,但是最常見的,谷歌默認的構建語言,還是 groovy.那麼, 了解 groovy語言的特性是繞過不去的。但是精(熟)通(練)Java的開發者, groovy和java都是基於 jvm,都是編譯成字節碼來運行在 jvm中,我們在有 java老底的基礎上,不需要逐字逐句去學習語法,而只需要總結出 groovy和java語法上比較相異的部分,則可以輕鬆掌握它。

先給出 Groovy語法的官網:https://www.w3cschool.cn/groovy/groovybasicsyntax.html大部分語法,我們作為java開發者都能看懂,但是以下這些,則需要動一下腦子。

1.語句結束的逗號可以省略

但是你要加上也不會報錯,建議能省就省吧

2.導包

Groovy的導包方式和java一樣: importjava.lang.*,但是.gradle內會有默認導包。每一個xxx.gradle文件,都能不用導包而直接使用以下包的類。

import java.lang.*

import java.util.*

import java.io.*

import java.net.*

import groovy.lang.*

import groovy.util.*

import java.math.BigInteger

import java.math.BigDecimal

3.定義變量

除了java所支持的 Stringa="aaa" ,之外,它還可以 defa="aaaa"

String s = "aaaaa"

def s2 = "ssssss"

4.循環

for(int i in1..10) {//用for in 遍歷 1到10(包含頭尾)

println i

}

def dd= [1,2,3,4,5]//for in 遍歷數組

for(d in dd){

println d

}

def map = ["ken":21,"ju":12,"aaaaa":223] // for in 遍歷 map

for(d in map){

println d

}

另外,如果是簡單的多次執行同一段代碼,還可以這麼寫(這個涉及到閉包,後面解釋):

10.times{

variable -> println variable

}

5.文件IO

除了可以使用 java的標準io流去進行文件讀寫之外,還使用 Groovy可以進行文件的 IO讀寫操作,後者更加簡單.比如

newFile("test.txt").eachLine { line -> println "line $line"} //讀取每一行

//讀取文件全部內容

File f = newFile("test.txt")

println "文件全部內容 \n$f.text"

//把helloWorld字符串寫入到test.txt文件

newFile("test.txt").withWriter('utf-8', {

writer -> writer.writeLine("hello world")

})

總之一句話, Groovy提供的 File類,可以進行簡單的文件操作,足夠滿足我們平時的gradle編程IO流操作,其他更多api可以翻閱 https://www.w3cschool.cn/groovy/groovyfileio.html

6.閉包

導致有些人看不懂.gradle文件的原因就是 閉包, 這個是java中不存在的概念( 拉姆達表達式類似閉包,但是不是閉包).可以大致理解 為:閉包==匿名代碼塊

//閉包測試

def clo = { println("無參閉包") }//無參閉包

clo()

def clo1 = { a -> println("1個參數的閉包:"+ a) }

clo1("參數")

def clo2 = { a, b, c -> println("多個參數的閉包 $a $b $c") }

clo2(1,2,3)

閉包也可以作為參數傳遞給一個方法:

task test() {

//閉包測試

def clo = { println("無參閉包") }//無參閉包

def clo1 = { a -> println("1個參數的閉包:"+ a) }

def clo2 = { a, b,c -> println("多個參數的閉包 $a $b $c") }

//閉包作為參數

testClo(clo)

testClo1(clo1)

testClo2(clo2)

}

void testClo(Closure clo) {

println("=======開始測試閉包0咯=======")

clo()

}

void testClo1(Closure clo) {

println("=======開始測試閉包1咯=======")

clo("哈哈哈")

}

void testClo2(Closure clo) {

println("=======開始測試閉包2咯=======")

clo("啊1", 2, 3)

}

集合/映射+閉包

task test() {

def list = [1, 2, 3, 4, 5]

list.each { a -> println(a) }//指明形參名

list.each { println(it) } //使用默認的形參名it

def map = ["zhou": 22, "li": 30, "han": 40]

map.each { a -> println(a) }//指明形參名

map.each { a -> println(a.key + "- "+ a.value) }//指明形參名

map.each { println(it.key + "- "+ it.value) } //使用默認的形參名it

}

7.省略小括號

除了閉包之外,groovy對於小括號的省略寫法也是阻礙我們看懂gradle文件的原因。那麼groovy在什麼情況下可以省略小括號呢?

1. 所有的頂級表達式的括號可以省略2. 當閉包作為頂級表達式的最後一個參數的時候,小括號可以省略

但是,當函數嵌套調用的時候,如果函數是無參的,這個時候小括號不可省略.

什麼意思?小括號的省略往往和閉包 / 方法調用有關,我們拿實際案例來說:

buildscript {

repositories {

google()

jcenter()

}

dependencies {

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

// NOTE: Do not place your application dependencies here; they belong

// in the individual module build.gradle files

}

}

上面這段,如果按照java的語言習慣,根本讀不通,但是,如果我們把括號補全以下,變成這樣:

buildscript({

repositories({

google()

jcenter()

})

dependencies({

classpath ('com.android.tools.build:gradle:3.4.1')

// NOTE: Do not place your application dependencies here; they belong

// in the individual module build.gradle files

})

})

解讀以上補全過程,通過代碼閱讀,我發現,buildscript / repositories /google/jcenter/dependencies / classpath 其實都是 一個一個的"方法名",方法自然是會帶上小括號,小括號裡面就會裝著參數,而參數類型恰恰就是 閉包Closure,最後一個 classpath比較特殊,他的參數類型是Object[] :比如

void buildscript(Closure configureClosure);

void repositories(Closure configureClosure);

補全了小括號,我們就能以java的閱讀習慣去閱讀 gradle文件。再舉一個例子(如果上面的能讀懂,那麼下面的這一段代碼應該能讀懂了):

android {

compileSdkVersion 29

buildToolsVersion "29.0.2"

defaultConfig {

applicationId "com.example.myapplication"

minSdkVersion 15

targetSdkVersion 29

versionCode 1

versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildTypes {

release {

minifyEnabled false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

}

}

}

補全括號之後,

android({

compileSdkVersion(29)

buildToolsVersion("29.0.2")

defaultConfig({

applicationId("com.example.myapplication")

minSdkVersion(15)

targetSdkVersion(29)

versionCode(1)

versionName("1.0")

testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner")

})

buildTypes({

release({

minifyEnabled(false)

proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')

})

})

})

那麼什麼時候不可以省略小括號呢?也舉個例子:

無參函數調用的時候,括號不可省略。有參數的函數,可以省略。

總結

從一個java老司機的眼光去看 groovy,其實java和groovy差別就是以上這些(其他一些 groovy 語法並不是不重要,而是java開發者一眼就能看明白,沒必要拿出來佔字數),掌握起來並不難,就一句話:gradle/groovy 編程,在函數調用時往往會 省略小括號,如果 省略了小括號再添上 閉包參數,看上去就比較 詭異了。但是, 補全了小括號,理解了 閉包之後,讀寫 gradle/groovy將不會再有障礙。

3.為什麼你的apk打包這麼慢

你們有沒有經歷過 用as新建一個project,然後半天不能構建成功的窘境?如果有,那麼恭喜你,你的電腦網路被牆了,gradle插件包伺服器並不在國內,如果網絡被牆,那麼下載不動,你的項目構建就很慢。

解決方案1

還記不記得這裡的wrapper / gradle-wrapper.properties 這裡有一個關鍵配置,

`https\://services.gradle.org`是協議和主機

`/distributions/`是路徑

`gradle-5.1.1-all.zip`則是插件包的名字

這裡的gradle-5.1.1-all.zip插件包,包含了源文件和可執行文件,其實我們構建項目,並不需要源文件,所以,我們可以試著把這裡的-all 改成 -bin,變成下面這樣:

distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip```也許可以加快下載速度,有利於你的項目編譯。

解決方案2

承接方案1, distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 這個插件包,最後下載到了我們的本地,window系統下,一般都在:MAC系統應該也在對應的用戶目錄,我沒有mac電腦,就不截圖了.

我們可以手動通過別的下載軟體把這個包,下載到上圖的目錄下 ( C:\Users\adminstrator\.gradle\wrapper\dists),然後在 gradle-wrapper.properties中設置對應的版本即可,這樣也能免除你在編譯的時候去浪費時間了。 而且這些包應該也能復用,以後拷貝出去,給其他項目來用,也能節約時間。

解決方案3

除了gradle插件包下載慢之外,很多第三方依賴庫都是來自北美大陸,我們去下載,依然可能被牆。一定有人經歷過jcenter下的包下半天沒動靜的情況了。這個如何解決?使用國內鏡像去替換舉個例子,如下圖,jcenter下了半天沒動靜。那麼,你改成這樣:在 jcenter()的後面加上 {url'https://maven.aliyun.com/repository/jcenter'}aliyun的鏡像地址為:https://maven.aliyun.com/mvn/view如果發現其他的依賴庫下的依賴包下載不動,同理。除了阿里雲之外,還有其他公司發布國內鏡像,使用方法同理。

那麼如果你想玩點騷操作,你想先去國內倉庫去找,然後再去國外倉庫去找。也可以實現,方法為:當給同一個倉庫設置多個地址的時候,系統按照從上到下的書寫順序去查找,找到為止,查到最後還找不到,那就GG了,沒法編譯。

解決方案4

存在一種情況,即使你按照前面3步去做了,編譯依然很慢,這是為何?很可能是因為:這裡的加號,意思是:你這次所下載的依賴包,自動去查找網絡上的最新版如果每一次編譯,都要去請求網絡,然後下載最新版,勢必會拖慢編譯速度。加號,谷歌設計出來應該是為了提供使用最新包的簡易寫法,但是這個並不是一個好習慣。試想,你引用的第三方依賴包 發生了api變化,很可能讓你的引用代碼出現bug。

解決方案5

如果上面的方案都不能解決你編譯慢的問題,比如你的項目引用了大量的依賴包,down下來一個新的項目,首次編譯都要花費大量的時間。這個時候,可以:使用本地私庫 常用的私庫有 artifact 等。至於私庫搭建,相信網上有很多攻略,我就不在這裡浪費篇幅了。

未完待續...結語

全文太長,點個在看吧。下一篇(2) 將會 繼續第4節往後講解。

萬水千山總是情,點個在看行不行

相關焦點

  • Gradle for Android入門
    Project和tasks在grade中的兩大重要的概念,分別是project和tasks。每一次構建都是有至少一個project來完成,所以Android studio中的project和Gradle中的project不是一個概念。每個project有至少一個tasks。每一個build.grade文件代表著一個project。
  • 掌控 Android Gradle
    對本文有任何問題,可加我的個人微信:kymjs123Gradle 裡的幾乎任何東西都是基於這兩個基礎概念:掌握了這兩個,你就掌握了一大半的 Gradle 知識了。首先講 Task字面理解為任務,Gradle 中所有執行的事件都是藉由 Task 執行的。
  • 擁抱Android Studio(二):Android Studio與Gradle深入
    一開始不知道為什麼而學,學不進去,荒廢了基礎,等到金工實習的時候,又發現基礎不牢,後悔不已。 考慮到傳統教育方式的不足之處,筆者在組織本系列文章的時候是先講入門實例,進而學習 Gradle 和 Groovy 基礎原理,最後學習進階實例。上篇文章介紹了 從 ADT 遷移到 Android Studio,相信經過很短時間的使用之後,已經開始熟悉和愛上 Android Studio 了。
  • 寫給Android開發的Gradle知識體系
    1.png所有構建文件在 Gradle Scripts 層級下顯示,大概介紹下這些文件的用處。項目build.gradle:配置項目的整體屬性,比如指定使用的代碼倉庫、依賴的Gradle插件版本等等。模塊build.gradle:配置當前Module的編譯參數。
  • Gradle 實現 Android 多渠道定製化打包
    build.gradle 中部分配置代碼如下:android {    compileSdkVersion 24    buildToolsVersion "24.0.1"    //默認配置,所有 productFlavors 都會繼承 defaultConfig 中配置的屬性    defaultConfig {
  • Gradle 與 Android 構建入門
    比如需要 Android Gradle Plugin 插件為我們打包 apk 包,就需要添加1. classpath 'com.android.tools.build:gradle:3.4.0'最後是 allprojects 和 repositories:在 allprojects 中的配置會對所有工程生效而裡面的 repositories 則表示工程聲明的 dependencies
  • 給 Android 開發者的 Gradle 入門指南
    #掃描二維碼報名源創會#原文:Beginner’s Guide to Gradle for Android Developers連結:https://journals.apptivitylab.com/beginners-guide-to-gradle-for-android-developers
  • AOP編程_Android優雅權限框架(1)概念基礎
    正文大綱1、Demo地址2、本文所涉技術盤點3、關於Android權限的梗4、初級/中級/高級android開發的權限請求寫法5、AOP優雅權限框架詳解     gradle配置     Java代碼6、AOP思想以及常用AOP框架
  • 【實戰】Android工程gradle詳解
    這時我們就需要對所有的版本進行統一的管理,管理的方式有兩種:rootProject我們可以把一些需要用的欄位都放在project的build.gradle(注意是project的不是module的)中:這樣,在module的build.gradle中可以進行讀取:
  • 1.6萬字好文!這一次,徹底了解 Gradle 吧!
    Gradle 學習資料食用指南Gradle 很複雜、學習難度很大的,一遍基本是不夠的,請大家耐心反覆看幾遍 <( ̄ˇ ̄)/1. 首先還是希望大家能先閱讀下本文,先對 Gradle 有些基本理解再看後面,尤其是一點 Gradle 基礎都沒有的同學,我是真的建議大家先把我這篇文章看完,我寫文章從來都是從小白出發2.
  • 這一次,徹底了解 Gradle 吧!
    Gradle 學習資料食用指南Gradle 很複雜、學習難度很大的,一遍基本是不夠的,請大家耐心反覆看幾遍 <( ̄ˇ ̄)/1. 首先還是希望大家能先閱讀下本文,先對 Gradle 有些基本理解再看後面,尤其是一點 Gradle 基礎都沒有的同學,我是真的建議大家先把我這篇文章看完,我寫文章從來都是從小白出發2.
  • 原創 | 看完此文,你對Gradle的理解又升級了!
    作者:劉望舒http://liuwangshu.cn/application/android-gradle/2-gradle-dependency.htmlGradle知識體系為什麼現在要用Gradle?
  • 分享 7個 Gradle 實用小技巧
    前言Gradle在android開發中應用地十分廣泛,但相信有很多同學並不很了解gradle。本文主要介紹了使用gradle的一些實用技巧,幫助讀者增進對這個熟悉的陌生人的了解。主要包括以下內容:1.Gradle依賴樹查詢。2.使用循環優化Gradle依賴管理。
  • Android Gradle 使用大全
    Android Gradle 的 Project 和 Tasks這個Gradle中最重要的兩個概念。每次構建(build)至少由一個project構成,一個project 由一到多個task構成。項目結構中的每個build.gradle文件代表一個project,在這編譯腳本文件中可以定義一系列的task;task 本質上又是由一組被順序執行的Action`對象構成,Action其實是一段代碼塊,類似於Java中的方法Android Gradle 構建生命周期每次構建的執行本質上執行一系列的Task。
  • 7 個你應該知道的Gradle 實用技巧
    Gradle在android開發中應用地十分廣泛,但相信有很多同學並不很了解gradle本文主要介紹了使用gradle的一些實用技巧,幫助讀者增進對這個熟悉的陌生人的了解主要包括以下內容1.Gradle依賴樹查詢有時我們在分析依賴衝突時,需要查看依賴樹,我們常用的查看依賴樹的命令為
  • 谷歌Android Studio 和 Gradle 插件使用全新版本編號
    Android Studio 的新版本編號方案IT之家獲悉,從 Arctic Fox (2020.3.1) 開始,Android Studio 的版本號系統將以年份為基礎,從而更加符合 IntelliJ IDEA 的版本模式——Android Studio 正是基於這個 IDE 構建的。
  • 谷歌:Android Studio 和 Gradle 插件使用全新版本編號
    Android Studio 的新版本編號方案IT之家獲悉,從 Arctic Fox (2020.3.1) 開始,Android Studio 的版本號系統將以年份為基礎,從而更加符合 IntelliJ IDEA 的版本模式——Android Studio 正是基於這個 IDE 構建的。
  • Gradle基礎知識點總結
    Groovy基礎語法 2.1 開發環境配置Groovy:是一種基於JVM的敏捷開發語言  ,可以與Java完美結合。在進行Groovy基礎語法學習之前,我們首先要配置好開發環境。開發環境配置如下:1、JDK下載安裝與環境變量配置    2、Groovy SDK下載安裝與環境變量配置    3、IntelliJ IDEA開發工具下載安裝。
  • 安卓基礎知識【1】——神秘的【android-SDK】
    前言:        我們學習AIDE,不光要學會怎麼使用AIDE,更應該追本溯源的搞清楚裡面的一些原理,我這幾天花了點時間來整理了一下安卓SDK的一些基礎知識,從源頭來看看AIDE中各個文件的作用。由於時間倉促,可能會有一些理解不到位的,有錯誤之處還請指出以便改正。
  • 跟隨IntelliJ IDEA,谷歌 Android Studio 和 Gradle 插件使用全新...
    Android Studio 的新版本編號方案  從 Arctic Fox (2020.3.1) 開始,Android Studio 的版本號系統將以年份為基礎  安裝預覽版 Android Studio:https://developer.android.google.cn/studio/preview/install-preview如果沿用以前的編號系統,則此版本將為 Android Studio 4.3。