Gradle構(gòu)建項(xiàng)目詳解

? ? ? ? 我們知道Android開發(fā)中浪讳,Android studio開發(fā)平臺是通過Gradle構(gòu)建項(xiàng)目的矮嫉,那Gradle到底是如何構(gòu)建生成我們想要的apk文件的呢,而對于一個Android開發(fā)人員贿条,關(guān)于Gradle相關(guān)的知識點(diǎn)粹懒,我們應(yīng)該需要了解那些方面的知識呢,今天我就帶大家來了解一下Android開發(fā)應(yīng)該知道的關(guān)于Gradle相關(guān)知識點(diǎn)吧勺像。


Gradle知識點(diǎn)匯總:

一:Android Studio apk生成的過程簡介

二:為什么使用Gradle障贸,Gradle有什么優(yōu)點(diǎn)

三:Andorid構(gòu)建項(xiàng)目時,Gradle有哪些相關(guān)的文件

四:Grovvy常見基本語法介紹

五:Gradle插件講解

六:Gradle的生命周期

七:Android中Gradle的常見配置關(guān)鍵字與常見問題匯總(不斷更新)

八:如何提高Gradle編譯效率

九:擴(kuò)展閱讀


一:Android Studio apk生成的過程簡介

Apk生成流程圖:

簡述:Andorid Studio開發(fā)平臺通過讀取Gradle相關(guān)文件吟宦,從而開始構(gòu)建并整合項(xiàng)目中的各種類型的文件篮洁,從而一步步的生成Apk文件蔑鹦,而我們可以根據(jù)項(xiàng)目的需要怜浅,通過配置Gradle文件的內(nèi)容,從而構(gòu)建出符合我們自己需求的apk文件爬迟。

例如:

1辰狡、生成多渠道的apk包(應(yīng)用包锋叨,各大手機(jī)應(yīng)用商店)

2、生成不同開發(fā)環(huán)境的apk包(dev宛篇,sit娃磺,uat,prod)


二:為什么使用Gradle叫倍,Gradle有什么優(yōu)點(diǎn)

? ? ? ? Gradle是一個構(gòu)建工具偷卧,那么為什么要用構(gòu)建工具豺瘤,這就需要先從項(xiàng)目自動化開始講起。

? ? ? ? 在我們開發(fā)軟件時听诸,會面臨相似的情況就是坐求,我們需要去用IDE來進(jìn)行編碼,當(dāng)完成一些功能時會進(jìn)行編譯晌梨、單元測試桥嗤、打包等工作,這些工作都需要開發(fā)人員手動來實(shí)現(xiàn)仔蝌。而一般的軟件都是迭代式開發(fā)的泛领,一個版本接著一個版本,每個版本又可能有很多的功能敛惊,如果開發(fā)每次實(shí)現(xiàn)功能時都需要手動的進(jìn)行編譯渊鞋、單元測試和打包等工作,那顯然會非常耗時而且也容易出現(xiàn)問題瞧挤,因此項(xiàng)目自動化應(yīng)運(yùn)而生锡宋。


它有以下優(yōu)點(diǎn):

一、它可以盡量防止開發(fā)手動介入從而節(jié)省了開發(fā)的時間并減少錯誤的發(fā)生特恬。

二执俩、自動化可以自定義有序的步驟來完成代碼的編譯、測試和打包等工作鸵鸥,讓重復(fù)的步驟變得簡單奠滑。

三、IDE可能受到不同操作系統(tǒng)的限制妒穴,而自動化構(gòu)建是不會依賴于特定的操作系統(tǒng)和IDE的,具有平臺無關(guān)性摊崭。

四:Gradle是一款基于JVM的專注于靈活性和性能的開源構(gòu)建工具讼油,Gradle的特性與優(yōu)點(diǎn)如下圖:

特性與優(yōu)點(diǎn)詳解:

1、輕松的可拓展性

? ? ? ? Gradle有非常良好的拓展性呢簸。如果你想要在多個構(gòu)建或者項(xiàng)目中分享可重用代碼矮台,Gradle的插件會幫助你實(shí)現(xiàn)。將Gradle插件應(yīng)用于你的項(xiàng)目中根时,它會在你的項(xiàng)目構(gòu)建過程中提供很多幫助:為你的添加項(xiàng)目的依賴的第三方庫瘦赫、為你的項(xiàng)目添加有用的默認(rèn)設(shè)置和約定(源代碼位置、單元測試代碼位置)蛤迎。

2确虱、采用了Groovy

? ? ? ? Ant和Maven的構(gòu)建腳本是由XML來編寫的,如果XML邏輯復(fù)雜內(nèi)容太多就不容易維護(hù)替裆。Gradle可以使用Groovy來實(shí)現(xiàn)構(gòu)建腳本校辩,Groovy是基于Jvm一種動態(tài)語言窘问,它的語法和Java非常相似并兼容Java,因此你無需擔(dān)心學(xué)習(xí)Groovy的成本宜咒。Groovy在Java的基礎(chǔ)上增加了很多動態(tài)類型和靈活的特性惠赫,比起XML,Gradle更具有表達(dá)性和可讀性故黑。

3儿咱、強(qiáng)大的依賴管理

? ? ? ?Gradle提供了可配置的可靠的依賴管理方案。一旦依賴的庫被下載并存儲到本地緩存中场晶,我們的項(xiàng)目就可以使用了混埠。依賴管理很好的實(shí)現(xiàn)了在不同的平臺和機(jī)器上產(chǎn)生相同的構(gòu)建結(jié)果。

4峰搪、靈活的約定

? ? ? ? Gradle可以為構(gòu)建你的項(xiàng)目提供引導(dǎo)和默認(rèn)值岔冀,如果你使用這種約定,你的Gradle構(gòu)建腳本不會有幾行概耻。比起Ant使套,Gradle不僅僅提供了約定,還可以讓你輕松的打破約定鞠柄。

5侦高、GradleWrapper

? ? ? ?GradleWrapper是對Gradle的包裝,它的作用是簡化Gradle本身的下載厌杜、安裝和構(gòu)建奉呛,比如它會在我們沒有安裝Gradle的情況下,去下載指定版本的Gradle并進(jìn)行構(gòu)建夯尽。Gradle的版本很多瞧壮,所以有可能出現(xiàn)版本兼容的問題,這時就需要GradleWrapper去統(tǒng)一Gradle的版本匙握,避免開發(fā)團(tuán)隊(duì)因?yàn)镚radle版本不一致而產(chǎn)生問題咆槽。

6、可以和其他構(gòu)建工具集成

? ? ? ? Gradle可以和Ant圈纺、Maven和Ivy進(jìn)行集成秦忿,比如我們可以把Ant的構(gòu)建腳本導(dǎo)入到Gradle的構(gòu)建中。

7蛾娶、底層API

? ? ? ? Gradle顯然無法滿足所有企業(yè)級構(gòu)建的所有要求灯谣,但是可以通過HookGradle的生命周期,來監(jiān)控和配置構(gòu)建腳本蛔琅。

8胎许、社區(qū)的支持和推動

? ? ? ? Gradle是一個開源的項(xiàng)目,它遵循了Apache License 2.0協(xié)議。Gradle的優(yōu)良特性吸引了很多開發(fā)者并形成了Gradle社區(qū)呐萨,很多開源軟件開發(fā)者為Gradle的核心代碼做出了共享杀饵。


三:Andorid構(gòu)建項(xiàng)目時,Gradle有哪些相關(guān)的文件

1谬擦、build.gradle(項(xiàng)目)

2切距、build.gradle(module)

3、gradle-wrapper.properties

4惨远、config.gradle

5谜悟、setting.gradle

6、gradle.properties


GradleWrapper文件:

? ? ? ?GradleWrapper稱為Gradle包裝器北秽,是對Gradle的一層包裝葡幸。為什么需要GradleWrapper呢?比如在一個開發(fā)團(tuán)隊(duì)中贺氓,如果每進(jìn)來一個成員蔚叨,都需要在計(jì)算機(jī)中安裝Gradle,這個時候運(yùn)行Gradle的環(huán)境和版本就會對構(gòu)建結(jié)果帶來不確定性辙培。針對這個問題蔑水,Gradle提供了一個解決方案,那就是GradleWrapper扬蕊,它是一個腳本搀别,可以在計(jì)算機(jī)沒有安裝Gradle的情況下運(yùn)行Gradle構(gòu)建,并且能夠指定Gradle的版本尾抑,開發(fā)人員可以快速啟動并運(yùn)行Gradle項(xiàng)目歇父,而不必手動安裝,這樣就標(biāo)準(zhǔn)化了項(xiàng)目再愈,從而提高了開發(fā)效率榜苫。AS在新建項(xiàng)目時會自帶GradleWrapper,這也是我們很少去單獨(dú)去下載安裝Gradle的原因翎冲。

???GradleWrapper的工作流程如下圖所示:

???gradle-wrapper.properties是GradleWrapper的屬性文件单刁,用來配置GradleWrapper,Gradle4.2.1版本對應(yīng)的gradle-wrapper.properties如下所示府适。

distributionBase=GRADLE_USER_HOME

distributionPath=wrapper/dists

distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-bin.zip

zipStoreBase=GRADLE_USER_HOME

zipStorePath=wrapper/dists

字段的含義解析:

distributionBase:Gradle解包后存儲的主目錄。

distributionPath:distributionBase指定目錄的子目錄肺樟。distributionBase+distributionPath就是Gradle解包后的存放位置檐春。

distributionUrl:Gradle發(fā)行版壓縮包的下載地址。

zipStoreBase:Gradle壓縮包存儲主目錄么伯。

zipStorePath:zipStoreBase指定目錄的子目錄疟暖。zipStoreBase+zipStorePath就是Gradle壓縮包的存放位置。

? ? ? ? 這里我們最需要關(guān)注的是distributionUrl這個字段,如果官方的地址下載不了或者緩慢俐巴,可以將這個地址換為其他的鏡像地址骨望,或者干脆把Gradle發(fā)行版壓縮包放在服務(wù)器上以供下載。


四:grovvy常見基本語法介紹

簡述:Groovy是Apache旗下的一種基于JVM的面向?qū)ο缶幊陶Z言欣舵,既可以用于面向?qū)ο缶幊糖骛部梢杂米骷兇獾哪_本語言,在語言的設(shè)計(jì)上它吸納了Python缘圈、Ruby和Smalltalk語言的優(yōu)秀特性劣光,比如動態(tài)類型轉(zhuǎn)換、閉包和元編程支持糟把。

? ? ? ? Groovy與Java可以很好的互相調(diào)用并結(jié)合編程 绢涡,比如在寫Groovy的時候忘記了語法可以直接按Java的語法繼續(xù)寫,也可以在Java中調(diào)用Groovy腳本遣疯。比起Java雄可,Groovy語法更加的靈活和簡潔,可以用更少的代碼來實(shí)現(xiàn)Java實(shí)現(xiàn)的同樣功能缠犀。

? ? ? ?項(xiàng)目構(gòu)建比較復(fù)雜数苫,為了使用各種開發(fā)語言的開發(fā)者都能夠快速的構(gòu)建項(xiàng)目,專家們開發(fā)出了Gradle這個基于Groovy的DSL夭坪,DSL(DomainSpecifcLanguage)意為領(lǐng)域特定語言文判,只用于某個特定的領(lǐng)域。

? ? ? ? 我們只要按照Groovy的DSL語法來寫室梅,就可以輕松構(gòu)建項(xiàng)目戏仓。

語法一:變量

???Groovy中用def關(guān)鍵字來定義變量,可以不指定變量的類型亡鼠,默認(rèn)訪問修飾符是public赏殃。

???def a = 1;

???def int b = 1;

???def c = "hello world";


語法二:方法

? ? ? ? 方法使用返回類型或def關(guān)鍵字定義,方法可以接收任意數(shù)量的參數(shù)间涵,這些參數(shù)可以不申明類型仁热,如果不提供可見性修飾符,則該方法為public勾哩。

???用def關(guān)鍵字定義方法抗蠢。

???task method <<{

???????add (1,2)

???????minus 1,2 //1

???}

???def add(int a,int b) {

???????println a+b? //3

???}

???def minus(a思劳,b) {? ?//2

???????println? a-b

???}

如果指定了方法返回類型迅矛,可以不需要def關(guān)鍵字來定義方法。

???task method <<{

???????def number=minus 1,2

???????println number

???}

???int? minus(a潜叛,b) {

???????return a-b

???}

???如果不使用return秽褒,方法的返回值為最后一行代碼的執(zhí)行結(jié)果壶硅。

???int minus(a,b) {

???????a-b? //4

???}

從上面兩段代碼中可以發(fā)現(xiàn)Groovy中有很多省略的地方:

1销斟、語句后面的分號可以省略庐椒。

2、方法的括號可以省略蚂踊,比如注釋1和注釋3處约谈。

3、參數(shù)類型可以省略悴势,比如注釋2處窗宇。

4、return可以省略掉特纤,比如注釋4處军俊。


語法三:類

???Groovy類非常類似于Java類。

???task method <<{

???????def p = new Person()

???????p.increaseAge 5

???????printlnp.age

???}

???class Person {

???????String name

???????Integer age =10

???????def increaseAge(Integer years) {

???????????this.age+= years

???????}

???}

???運(yùn)行g(shù)radlemethod打印結(jié)果為:15

Groovy類與Java類有以下的區(qū)別:

1捧存、默認(rèn)類的修飾符為public粪躬。

2、沒有可見性修飾符的字段會自動生成對應(yīng)的setter和getter方法昔穴。

3镰官、類不需要與它的源文件有相同的名稱,但還是建議采用相同的名稱吗货。


語法四:語句

4.1泳唠、斷言

? ? ?Groovy斷言和Java斷言不同,它一直處于開啟狀態(tài)宙搬,是進(jìn)行單元測試的首選方式笨腥。

???task method <<{

???????assert 1+2 == 6

???}

???輸出結(jié)果為:

???Execution failed for task ':method'.

???????????> assert 1+2 == 6

???????????|?|

???????????3?false

解析:當(dāng)斷言的條件為false時,程序會拋出異常勇垛,不再執(zhí)行下面的代碼脖母,從輸出可以很清晰的看到發(fā)生錯誤的地方。


4.2闲孤、for循環(huán)

? ? ? Groovy支持Java的for(int i=0谆级;i<N;i++)和for(int i:array)形式的循環(huán)語句讼积,另外還支持for in loop形式肥照,支持遍歷范圍、列表勤众、Map建峭、數(shù)組和字符串等多種類型。

//遍歷范圍

???def x = 0

for (iin 0..3 ) {

???????x += I }

assert x == 6

//遍歷列表

???def x = 0

for (iin [0, 1, 2, 3] ) {

???????x += I }

assert x == 6

//遍歷Map中的值

???def map = ['a':1, 'b':2, 'c':3]

???x = 0

???for ( v inmap.values() ) {

???????x += v }

assert x == 6


4.3决摧、switch語句

???Groovy中的Switch語句不僅兼容Java代碼,還可以處理更多類型的case表達(dá)式。

???task method <<{

???????def x = 16

???????def result = ""

???????switch ( x ) {

???????????case "ok":

???????????????result = "found ok"

???case [1, 2, 4, 'list']:

???????????????result = "list"

???????????????break

???????????case 10..19:

???????????????result = "range"

???????????????break

???????????case Integer:

???????????????result = "integer"

???????????????break

???????????default:

???????????????result = "default"

???????}

???????assert result == "range"

???}

解析:case表達(dá)式可以是字符串掌桩、列表边锁、范圍、Integer等等波岛,因?yàn)槠蛎┨常@里只列出了一小部分。


語法五:數(shù)據(jù)類型

Groovy中的數(shù)據(jù)類型主要有以下幾種:

1则拷、Java中的基本數(shù)據(jù)類型

2贡蓖、Groovy中的容器類

3、閉包


5.1煌茬、字符串

? ? ? Groovy中的基本數(shù)據(jù)類型和Java大同小異斥铺,這里主要介紹下字符串類型。

? ? ? 在Groovy中有兩種字符串類型坛善,普通字符串String(java.lang.String)和插值字符串GString(groovy.lang.GString)晾蜘。

5.1.1:單引號字符串

? ? ? ?在Groovy中單引號字符串和雙引號字符串都可以定義一個字符串常量,只不過單引號字符串不支持插值眠屎。( 'Android進(jìn)階解密‘)

5.1.2:雙引號字符串

?????要想插值可以使用雙引號字符串剔交,插值指的是替換字符串中的占位符,占位符表達(dá)式為${}或者以$為前綴改衩。

???def name = 'Android進(jìn)階之光'

???println "hello ${name}"

???println "hello $name"

5.1.3:三引號字符串

???三引號字符串可以保留文本的換行和縮進(jìn)格式岖常,不支持插值。

???task method <<{

???????def name = '''Android進(jìn)階之光

???????Android進(jìn)階解密

???????Android進(jìn)階葫督?'''

???????println name

???}

???打印結(jié)果為:

???Android進(jìn)階之光

???????????Android進(jìn)階解密

???Android進(jìn)階竭鞍?


5.1. 4:GString

? ? ? ? String是不可變的,GString卻是可變的候衍,GString和String即使有相同的字面量笼蛛,它們的hashCodes的值也可能不同,因此應(yīng)該避免使用GString作為Map的key蛉鹿。

???assert "one: ${1}".hashCode() != "one: 1".hashCode()

? ? ? ?當(dāng)雙引號字符串中包含插值表達(dá)式時滨砍,字符串類型為GString,因此上面的斷言為true妖异。


5.2惋戏、List

? ? ? ? Groovy沒有定義自己的集合類,它在Java集合類的基礎(chǔ)上進(jìn)行了增強(qiáng)和簡化他膳。Groovy的List對應(yīng)Java中的List接口响逢,默認(rèn)的實(shí)現(xiàn)類為Java中的ArrayList。

???def number = [1, 2, 3]

???assert number instance of List

???def linkedList= [1, 2, 3]? as LinkedList???

???assert linkedList instanceof java.util.LinkedList

???可以使用as操作符來顯式指定List的實(shí)現(xiàn)類為java.util.LinkedList棕孙。

???獲取元素同樣要比Java要簡潔些舔亭,使用[]來獲取List中具有正索引或負(fù)索引的元素些膨。

???task method <<{

???????def number?= [1, 2, 3, 4]

???????assert number [1] == 2

???????assert number [-1] == 4? //1?

???????number << 5????//2????????????

???????assert number [4] == 5

???????assert number [-1] == 5

???}

???注釋1處的索引-1是列表末尾的第一個元素。注釋2處使用<<運(yùn)算符在列表末尾追加一個元素钦铺。


5.3订雾、Map

? ? ? 創(chuàng)建Map同樣使用[],需要同時指定鍵和值矛洞,默認(rèn)的實(shí)現(xiàn)類為java.util.LinkedHashMap洼哎。

???def name = [one: '魏無羨', two: '楊影楓', three: '張無忌']

???????????assert name['one']?== '魏無羨'

???????????assertname.two?== '楊影楓‘

???Map還有一個鍵關(guān)聯(lián)的問題:

???def key = 'name'

???def person = [key: '魏無羨']???//1

???????????assert person.containsKey('key')

???person = [(key): '魏無羨']?????//2??????

???????????assertperson.containsKey('name')

???注釋1處魏無羨的鍵值是key這個字符串,而不是key變量的值name沼本。如果想要以key變量的值為鍵值噩峦,需要像注釋2處一樣使用(key),用來告訴解析器我們傳遞的是一個變量抽兆,而不是定義一個字符串鍵值识补。


5.4 閉包(Closure)

? ? ? ?Groovy中的閉包是一個開放的、匿名的郊丛、可以接受參數(shù)和返回值的代碼塊李请。


???閉包的定義遵循以下語法:

{ [closureParameters-> ] statements }

???閉包分為兩個部分,分別是參數(shù)列表部分[closureParameters-> ]和語句部分statements厉熟。

???參數(shù)列表部分是可選的导盅,如果閉包只有一個參數(shù),參數(shù)名是可選的揍瑟,Groovy會隱式指定it作為參數(shù)名白翻,如下所示。

{println it }????//使用隱式參數(shù)it的閉包

當(dāng)需要指定參數(shù)列表時绢片,需要->將參數(shù)列表和閉包體相分離滤馍。

{ it ->println it }? ?//it是一個顯示參數(shù)

{ String a, String b ->???????????????????????????????

???println "${a} is a $"

}

???閉包是groovy.lang.Cloush類的一個實(shí)例底循,這使得閉包可以賦值給變量或字段巢株,如下所示。

//將閉包賦值給一個變量

def println={ it ->println it }????

assert printlnin stanceofClosure

//將閉包賦值給Closure類型變量

Closure do= {println 'do!' }

調(diào)用閉包

閉包既可以當(dāng)做方法來調(diào)用熙涤,也可以顯示調(diào)用call方法阁苞。

def code = { 123 }

assert code() == 123 //閉包當(dāng)做方法調(diào)用

assert code.call() == 123 //顯示調(diào)用call方法

def isOddNumber= {inti-> i%2 != 0 }??????????????????????????

assert isOddNumber(3) == true?//調(diào)用帶參數(shù)的閉包


6、I/O操作

? ? ? Groovy的I/O操作要比Java的更為的簡潔祠挫。

6.1 文件讀取

???我們可以在PC上新建一個name.txt那槽,在里面輸入一些內(nèi)容,然后用Groovy來讀取該文件的內(nèi)容:

def filePath= "D:/Android/name.txt"

def file = new File(filePath) ;

file.eachLine{

???printlnit

}

可以看出Groovy的文件讀取是很簡潔的等舔,還可以更簡潔些:

def filePath= "D:/Android/name.txt"

def file = new File(filePath) ;

println file.text


6.2 文件寫入

文件寫入同樣十分簡潔:

def filePath= "D:/Android/name.txt"

def file = new File(filePath);

file.withPrintWriter{

???it.println("三井壽")

???it.println("仙道彰")

}


7. 其他

7.1 asType

asType可以用于數(shù)據(jù)類型轉(zhuǎn)換:

String a = '23'

int b = a as int

def c =a.asType(Integer)

assert c instanceof java.lang.Integer


7.2 判斷是否為真

if (name != null &&name.length> 0) {}

可以替換為

if (name) {}


7.3 安全取值

? ? ?在Java中骚灸,要安全獲取某個對象的值可能需要大量的if語句來判空:

if (school != null) {

???if (school.getStudent() != null) {

???????if (school.getStudent().getName() != null) {

???????????System.out.println(school.getStudent().getName());

???????}

???}

}

Groovy中可以使用?.來安全的取值:

println school?.student?.name


7.4? with操作符

???對同一個對象的屬性進(jìn)行賦值時慌植,可以這么做:

task method <<{

Person p = new Person()

p.name = "楊影楓"

p.age= 19

p.sex= "男"

println p.name

}

class Person {??????????????????????

???String name?????????????????????

???Integer age

???String sex

}

使用with來進(jìn)行簡化:

Person p = new Person()

p.with{

??name = "楊影楓"

??age= 19

??sex= "男"

?}??

println p.name

8. 總結(jié)

? ? ? 大概的介紹了Groovy的一些語法甚牲,包括:變量义郑、方法、數(shù)據(jù)類型等等鳖藕,比起Groovy官方文檔來說魔慷,介紹的并不多,但不要忘了本系列的目標(biāo)是學(xué)習(xí)與Android相關(guān)的Gradle著恩,Groovy并不是重點(diǎn),我們只需要了解本文所介紹的內(nèi)容就夠了蜻展,如果碰到哪里不會再去查找Groovy官方文檔和Groovy API文檔喉誊。

例子:

?task hello {

???????doLast{

???????????println 'Hello world!'

???????}

???}

簡潔版:

?task hello << {

???????println 'Hello world!'

???}

解析:

? ? ?task(任務(wù))和action(動作)是Gradle的重要元素。上面的代碼中纵顾,task代表一個獨(dú)立的原子性操作伍茄,比如復(fù)制一個文件,編譯一次Java代碼施逾,這里我們簡單的定義一個名為hello的任務(wù)敷矫。doLast 代表task執(zhí)行的最后一個action,通俗來講就是task執(zhí)行完畢后會回調(diào)doLast中的代碼汉额,在上面這個Gradle的任務(wù)曹仗,Gradle的任務(wù)包括創(chuàng)建任務(wù)、任務(wù)依賴蠕搜、動態(tài)定義任務(wù)和任務(wù)的分組和描述怎茫。


創(chuàng)建任務(wù)

方法一:直接用任務(wù)名稱創(chuàng)建

???def Task hello=task(hello)

???hello.doLast{

???????println"hello world"

???}

方法二:任務(wù)名稱+任務(wù)配置創(chuàng)建

???def Task hello=task(hello,group:BasePlugin.BUILD_GROUP)

???hello.doLast{

???????println"hello world"

???}

? ? 其中g(shù)roup為任務(wù)配置項(xiàng),它代表了分組妓灌,關(guān)于分組具體見3.4小節(jié)轨蛤。

方法三:TaskContainer的create方法創(chuàng)建

???tasks.create(name: 'hello') << {

???????println"hello world"

???}

? ? ?此前創(chuàng)建任務(wù)的方式最終都會調(diào)用tasks的create方法,其中tasks類型為TaskContainer虫埂。

任務(wù)依賴:任務(wù)依賴會決定任務(wù)運(yùn)行的先后順序祥山,被依賴的任務(wù)會在定義依賴的任務(wù)之前執(zhí)行。創(chuàng)建任務(wù)間的依賴關(guān)系如下所示掉伏。

???task hello << {

???????println'Hello world!'

???}

???task go(dependsOn: hello) << {

???????println"go for it"

???}

? ? ? 在hello任務(wù)的基礎(chǔ)上增加了一個名為go的任務(wù)缝呕,通過dependsOn來指定依賴的任務(wù)為hello,因此go任務(wù)運(yùn)行在hello之后岖免。

???運(yùn)行g(shù)radle -q go構(gòu)建腳本岳颇,打印結(jié)果如下:

???Hello world!

???go for it


動態(tài)定義任務(wù):動態(tài)定義任務(wù)指的是在運(yùn)行時來定義任務(wù)的名稱,如下所示颅湘。

? ? ? ? ? ?3.times {number ->

???????????task "task$number" << {

???????????println "task $number"

???}

???}

解析:這里用到了Groovy語法话侧,關(guān)于Groovy語法會在本系列后續(xù)的文章進(jìn)行介紹。times是Groovy在java.lang.Number中拓展的方法闯参,是一個定時器瞻鹏。3.times中循環(huán)創(chuàng)建了三個新任務(wù)悲立,隱式變量number的值為0,1新博,2薪夕,任務(wù)的名稱由task加上number的值組成,達(dá)到了動態(tài)定義任務(wù)的目的赫悄。

???運(yùn)行g(shù)radle -q task0構(gòu)建腳本原献,打印結(jié)果如下:

???task 0


任務(wù)的分組和描述

? ? ? Gradle有任務(wù)組的概念,可以為任務(wù)配置分組和描述埂淮,以便于更好的管理任務(wù)姑隅,擁有良好的可讀性。改造上面的例子倔撞,為hello任務(wù)添加分組和描述讲仰。

???task hello {

???????group = 'build'

???????description = 'hello world'

???????doLast{

???????????println"任務(wù)分組: ${group}"

???????????println"任務(wù)描述: ${description}"

???????}

???}

???task go(dependsOn: hello) << {

???????println"go for it"

???}

也可以采用3.1小節(jié)中其他的創(chuàng)建任務(wù)方式來為任務(wù)添加分組和描述鄙陡,如下所示躏啰。

???def Task hello=task(hello)

???hello.description='hello world'

???hello.group=BasePlugin.BUILD_GROUP

???hello.doLast{

???????println"任務(wù)分組: ${group}"

???????println"任務(wù)描述: ${description}"

???}

???task go(dependsOn: hello) << {

???????println"go for it"

???}


五:Gradle插件講解

5.1趁矾、應(yīng)用Gradle插件

? ? ? ? 要想應(yīng)用插件,主要有兩個步驟丙唧,一是解析插件愈魏,二是把插件應(yīng)用到項(xiàng)目中,應(yīng)用插件通過 Project.apply()方法來完成想际。

? ? ? ? 在Gradle中一般有兩種類型的插件培漏,分別叫做腳本插件和對象插件。腳本插件是額外的構(gòu)建腳本胡本,它會進(jìn)一步配置構(gòu)建牌柄,可以把它理解為一個普通的build.gradle。對象插件又叫做二進(jìn)制插件侧甫,是實(shí)現(xiàn)了Plugin接口的類珊佣。


2.1腳本插件

文件other.gradle:

ext{

verson='1.0'

url='http://liuwangshu.cn'

}

這實(shí)際上不算是一個真正的腳本插件,就是一個簡單的腳本披粟,主要是用于演示腳本插件是如何被應(yīng)用的咒锻。

? ? 我們在build.gradle中來應(yīng)用這個插件:

build.gradle

apply from: 'other.gradle'

task test {

???doLast{

???????println"版本為:${verson},地址為:${url}"

???}

}

? ? ? apply是Gradle project中提供的方法,用于配置項(xiàng)目中的插件守屉。執(zhí)行g(shù)radlew.bat test惑艇,會打印出想要的結(jié)果。

對象插件:我們知道對象插件就是實(shí)現(xiàn)了org.gradle.api.plugins<Project>接口的插件,對象插件可以分為內(nèi)部插件和第三方插件思灌。


2.2.1 內(nèi)部插件

? ? ? 如果我們想要應(yīng)用Java插件可以這么寫:

build.gradle文件:

apply plugin:org.gradle.api.plugins.JavaPlugin

Gradle默認(rèn)就導(dǎo)入了org.gradle.api.plugins包,因此我們也可以去掉包名:

apply plugin:JavaPlugin

? ? ? ?實(shí)現(xiàn)了org.gradle.api.plugins接口的插件會有pulginid,使用pulginid是最簡潔课兄、最常用的方式:apply plugin: 'java‘

? ? ? ?Gradle的發(fā)行包中有大量的插件搬俊,這些插件有很多類型餐屎,比如語言插件攀细、集成插件、軟件開發(fā)插件等等撮慨,如果我們想向項(xiàng)目添加c++源代碼編譯功能影涉,可以這么寫:

????????apply plugin: 'cpp'


第三方插件:

???第三方的對象插件通常是jar文件,要想讓構(gòu)建腳本知道第三方插件的存在喊式,需要使用buildscript來設(shè)置。

buildscript{

?repositories {

???maven {

?????url"https://plugins.gradle.org/m2/"

???}

?}

?dependencies {

???classpath"com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4"

?}

}

apply plugin: "com.jfrog.bintray"

? ? ? 在buildscript中來定義插件所在的原始倉庫和插件的依賴 竖配,再通過apply方法配置就可以了。Android Gradle插件也屬于第三方插件,如果我們想引入Android Gradle插件盯漂,可以這么寫:

buildscript{

???repositories {

???????jcenter()

???}

???dependencies {

???????classpath'com.android.tools.build:gradle:2.3.2'

???}

}

apply plugin: 'com.android.application'

? ? ? 這樣我們就可以使用Android Gradle插件,通過apply方法來使用App工程插件,這樣項(xiàng)目會編譯成為一個apk切揭。

自定義對象插件:

? ? ? ? 對象插件是實(shí)現(xiàn)了org.gradle.api.plugins<Project>接口的插件,這個接口中只定義個一個簡單的apply方法嗤谚,想要自定義插件就需要去實(shí)現(xiàn)org.gradle.api.plugins<Project>接口。

? ? ? ? 來實(shí)現(xiàn)一個簡單的自定義插件椅野,為了方便測試,不再采用文本編輯妖爷,而是使用IntelliJ來編輯(AS也可以)嗽上,用IntelliJ來打開2.1小節(jié)的例子彼念,改寫build.gradle文件:

build.gradle

applyplugin:CustomPlugin

classCustomPluginimplements Plugin<Project> {

???@Override

???void apply(Project project) {

???????project.task('CustomPluginTask') {

???????????doLast{

???????????????println"自定義插件"

???????????}

???????}

???}

}

? ? ? ?在build.gradle中自定義了一個插件CustomPlugin惯殊,在apply方法中創(chuàng)建一個名稱為CustomPluginTask的任務(wù)忆嗜。在IntelliJ的Terminal中輸入gradlew.bat CustomPluginTask來執(zhí)行CustomPluginTask任務(wù)闪湾。


Gradle插件的作用和好處:

Gradle插件可以做什么呢濒憋?主要有以下的幾點(diǎn)

1裆站、為項(xiàng)目配置依賴羽嫡。

2了牛、為項(xiàng)目配置約定,比如約定源代碼的存放位置。

3浇衬、為項(xiàng)目添加任務(wù),完成測試餐济、編譯耘擂、打包等任務(wù)。

4絮姆、為項(xiàng)目中的核心對象和其他插件的對象添加拓展類型醉冤。


使用Gradle插件主要有以下的好處:

1、重用和減少維護(hù)在多個項(xiàng)目類似的邏輯的開銷。

2诞外、更高程度的模塊化。

3莹妒、封裝必要的邏輯,并允許構(gòu)建腳本盡可能是聲明性产镐。


六:Gradle的生命周期

Gradle構(gòu)建生命周期分三個階段:

???初始化階段:負(fù)責(zé)判斷有多少個Projects參與構(gòu)建鳍征。

???配置階段:負(fù)責(zé)對初始化階段創(chuàng)建的Projects完成配置。

???執(zhí)行階段:根據(jù)配置階段的配置執(zhí)行任務(wù)。


初始化階段:

? ? ? ?構(gòu)建初始化階段首先尋找一個叫settings.gradle的文件,檢查是否當(dāng)前構(gòu)建是否是多項(xiàng)目構(gòu)建,并負(fù)責(zé)創(chuàng)建項(xiàng)目樹竣况。在多項(xiàng)目構(gòu)建中睁宰,settings.gradle是必需的雌桑,因?yàn)檫@個文件定義了參與構(gòu)建的項(xiàng)目膏斤,通過settings.gradle判斷有哪些項(xiàng)目需要初始化喻粹,加載所有需要初始化的項(xiàng)目的build.gradle文件并為每個項(xiàng)目創(chuàng)建project對象藻肄。

? ? ? ? 可以看出雄妥,settings.gradle中的代碼最先執(zhí)行最蕾,所以理論上還可以做其他事情。

??而在沒有settings.gradle文件的項(xiàng)目中老厌,如果執(zhí)行構(gòu)建瘟则,則Gradle按這個順序查找settings.gradle:

1、從當(dāng)前目錄的master文件夾內(nèi)尋找梅桩。

2壹粟、如果master目錄中也沒有,則搜索父目錄宿百。

3趁仙、如果父目錄也沒找到,則把構(gòu)建當(dāng)成單個項(xiàng)目構(gòu)建垦页。

4雀费、如果找到了,并且發(fā)現(xiàn)當(dāng)前項(xiàng)目是多項(xiàng)目構(gòu)建的一部分痊焊,則執(zhí)行多項(xiàng)目構(gòu)建盏袄。沒找到,則執(zhí)行單項(xiàng)目構(gòu)建薄啥。

? ? ? ? 從第二步中可以看出辕羽,Gradle支持從子項(xiàng)目中觸發(fā)構(gòu)建父項(xiàng)目。如果不想從子項(xiàng)目觸發(fā)父項(xiàng)目垄惧,而只是做單項(xiàng)目構(gòu)建刁愿,則應(yīng)該在gradle命令后加上-u命令行選項(xiàng)。


配置階段:

? ? ? ? 配置階段負(fù)責(zé)對初始化階段創(chuàng)建的projects做一些配置到逊,比如添加Task铣口,修改Task的行為等滤钱,執(zhí)行各項(xiàng)目下的build.gradle腳本,完成project的配置脑题,并且構(gòu)造Task任務(wù)依賴關(guān)系圖以便在執(zhí)行階段按照依賴關(guān)系執(zhí)行Task.執(zhí)行task中的配置代碼件缸。


執(zhí)行階段:

? ? ? ?通過配置階段的Task圖,按順序執(zhí)行需要執(zhí)行的任務(wù)中的動作代碼叔遂,就是執(zhí)行任務(wù)中寫在doFirst或doLast中的代碼他炊。

? ? ? ?以上就是Gradle構(gòu)建項(xiàng)目時的生命周期,由于Gradle的強(qiáng)大和易配性掏熬,如果想在構(gòu)建的過程中去做一些額外的操作的話佑稠,可以使用Gradle自帶的鉤子方法,Gradle提供了很多生命周期監(jiān)聽方法旗芬,可以在各個階段Hook指定的任務(wù)舌胶。

執(zhí)行流程圖:

備注:這里有幾個概念很關(guān)鍵,gradle, project, task疮丛。

1幔嫂、gradle全局可見,相當(dāng)于這個gradle工具本身誊薄。

2履恩、project是一個模塊,與android studio中的module是對應(yīng)的關(guān)系呢蔫,也對應(yīng)了一個build.gradle的文件切心。

3、task是最小的執(zhí)行塊片吊。為了方便绽昏,我們來有兩個project的工程來模擬,他們的具體執(zhí)行順序進(jìn)一步細(xì)分為下面的這個樣子俏脊。

圖解:

Project

???Project提供的生命周期回調(diào)方法有:

???//在Project進(jìn)行配置前調(diào)用

???void beforeEvaluate(Closure closure)

???//在Project配置結(jié)束后調(diào)用

???void afterEvaluate(Closure closure)

? ? ? beforeEvaluate必須在父模塊的build.gradle對子模塊進(jìn)行配置才能生效全谤,因?yàn)樵诋?dāng)前模塊的build.gradle中配置,它自己本身都沒配置好爷贫,所以不會監(jiān)聽到认然。


Gradle

???Gradle提供的生命周期回調(diào)方法很多,部分與Project里的功能雷同:

//在project進(jìn)行配置前調(diào)用漫萄,child project必須在root project中設(shè)置才會生效卷员,root project必須在settings.gradle中設(shè)置才會生效。

???void beforeProject(Closure closure)

//在project配置后調(diào)用

???afterProject(Closure closure)

//構(gòu)建開始前調(diào)用

???void buildStarted(Closure closure)

//構(gòu)建結(jié)束后調(diào)用

???void buildFinished(Closure closure)

//所有project配置完成后調(diào)用

???void projectsEvaluated(Closure closure)

//當(dāng)settings.gradle中引入的所有project都被創(chuàng)建好后調(diào)用腾务,只在該文件設(shè)置才會生效

???void projectsLoaded(Closure closure)

//settings.gradle配置完后調(diào)用毕骡,只對settings.gradle設(shè)置生效

???void settingsEvaluated(Closure closure)

我們修改setting.gradle的代碼如下:

???gradle.settingsEvaluated{

???????println "settings:執(zhí)行settingsEvaluated..."}

???gradle.projectsLoaded{

???????println"settings:執(zhí)行projectsLoaded..."}

???gradle.projectsEvaluated{

???????println"settings:執(zhí)行projectsEvaluated..."}

???gradle.beforeProject{proj->

???????????println"settings:執(zhí)行${proj.name}beforeProject"}

???gradle.afterProject{proj->

???????????println"settings:執(zhí)行${proj.name}afterProject"}

???gradle.buildStarted{

???????println"構(gòu)建開始..."}

???gradle.buildFinished{

???????println"構(gòu)建結(jié)束..."}

???include? ":app"

這個時候的執(zhí)行結(jié)果如下:

???settings:執(zhí)行settingsEvaluated...

???settings:執(zhí)行projectsLoaded...

???settings:執(zhí)行testbeforeProject

???根項(xiàng)目配置開始---

???根項(xiàng)目里任務(wù)配置---

???根項(xiàng)目配置結(jié)束---

???settings:執(zhí)行test afterProject

???settings:執(zhí)行app beforeProject

???子項(xiàng)目beforeEvaluate回調(diào)...

???APP子項(xiàng)目配置開始---

???APP子項(xiàng)目里任務(wù)配置---

???APP子項(xiàng)目配置結(jié)束---

???settings:執(zhí)行app afterProject

???APP子項(xiàng)目after Evaluate回調(diào)...

???settings:執(zhí)行projects Evaluated...

???構(gòu)建結(jié)束...

Gradle構(gòu)建周期中的Hook點(diǎn):

七:Android中Gradle的常見配置關(guān)鍵字與常見問題匯總(不斷更新)

一、Gradle是什么

1、Gradle是一個自動化構(gòu)建工具

2挺峡、兼容Maven等倉庫

3、基于Groovy的特定領(lǐng)域語言來聲明設(shè)置


二担钮、GradleWraper的作用是什么

1橱赠、GradleWrapper是一個腳本文件

2、它會在沒有安裝Gradle的情況下為我們下載Gradle箫津,之后我們就可以使用gradlew命令狭姨,像使用gradle一樣來使用Gradle了

3、GradleWraper簡化了gradle的安裝部署


三:Gradle命令

1苏遥、gradlew clean:清除app目錄下的build文件夾

2饼拍、gradlew check:執(zhí)行l(wèi)int檢查

3、gradlew assemble:打release和debug包

4田炭、gradlew build: 執(zhí)行check和assemble

5师抄、gradlew assembleRelease/gradlewassembleDebug:打全部渠道的Release或者debug包


四:設(shè)置編譯android項(xiàng)目的參數(shù)

???????android {

???????//編譯SDK的版本

???????compileSdkVersion22

???????// build tools的版本

???????buildToolsVersion"23.0.1"

???????//aapt配置

???????aaptOptions{

???????//不用壓縮的文件

???????noCompress'pak', 'dat', 'bin', 'notice'

???????//打包時候要忽略的文件

???????ignoreAssetsPattern"!.svn:!.git"

???????//分包

???????multiDexEnabled true

???????//--extra-packages是為資源文件設(shè)置別名:意思是通過該應(yīng)用包名+R,com.android.test1.R和com.android.test2.R都可以訪問到資源

???????additionalParameters'--extra-packages', 'com.android.test1','--extra-packages','com.android.test2'

???????}

???????//默認(rèn)配置

???????defaultConfig{

???????//應(yīng)用的包名

???????applicationId "com.example.heqiang.androiddemo"

???????minSdkVersion 21

???????targetSdkVersion 22

???????versionCode 1

???????versionName "1.0"

???????}

???????//編譯配置

???????compileOptions{

???????// java版本

???????sourceCompatibilityJavaVersion.VERSION_1_7

???????targetCompatibilityJavaVersion.VERSION_1_7

???????}

???????//源文件目錄設(shè)置

???????sourceSets{

???????main {

???????//jnilib的位置

???????jniLibs.srcDirs=jniLibs.srcDirs<< 'src/jniLibs'

???????//定義多個資源文件夾教硫,這種情況下叨吮,兩個資源文件夾具有相同優(yōu)先級,即如果一個資源在兩個文件夾都聲明了瞬矩,合并會報(bào)錯茶鉴。

???????res.srcDirs= ['src/main/res', 'src/main/res2']

???????//指定多個源文件目錄

???????java.srcDirs= ['src/main/java', 'src/main/aidl']

???????}

???????}

???????//簽名配置

???????signingConfigs{

???????debug {

???????keyAlias 'androiddebugkey'

???????keyPassword 'android'

???????storeFilefile('keystore/debug.keystore')

???????storePassword 'android'

???????}

???????}

buildTypes{

???????//release版本配置

???????release {

???????debuggable false

???????//是否進(jìn)行混淆

???????minifyEnabled true

???????//去除沒有用到的資源文件,要求minifyEnabled為true才生效

???????shrinkResources true

???????//混淆文件的位置

???????proguardFilesgetDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'

???????signingConfigsigningConfigs.debug

???????//ndk的一些相關(guān)配置景用,也可以放到defaultConfig里面涵叮。

???????//指定要ndk需要兼容的架構(gòu)(這樣其他依賴包里mips,x86,arm-v8之類的so會被過濾掉)

???????ndk{

???????abiFilter "armeabi"

???????}

???????}

//debug版本配置

???????debug {

???????debuggable true

???????//是否進(jìn)行混淆

???????minifyEnabled false

???????//去除沒有用到的資源文件,要求minifyEnabled為true才生效

???????shrinkResources true

???????//混淆文件的位置

???????proguardFilesgetDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'

???????signingConfig signingConfigs.debug

???????//ndk的一些相關(guān)配置伞插,也可以放到defaultConfig里面割粮。

???????//指定要ndk需要兼容的架構(gòu)(這樣其他依賴包里mips,x86,arm-v8之類的so會被過濾掉)

???????ndk{

???????abiFilter"armeabi"

???????}

???????}

???????}

???????// lint配置

???????lintOptions{

???????//移除lint檢查的error

???????abortOnErrorfalse

???????//禁止掉某些lint檢查

???????disable 'NewApi'

???????}

???????}

備注:android中還可以有以下配置:productFlavors{ }產(chǎn)品風(fēng)格配置,ProductFlavor類型蜂怎;testOptions{ }測試配置穆刻,TestOptions類型;dexOptions{ }dex配置杠步,DexOptions類型氢伟;packagingOptions{ }PackagingOptions類型;jacoco{ }JacocoExtension類型幽歼。 用于設(shè)定jacoco版本朵锣;splits{ } Splits類型。


五:幾種依賴的區(qū)別


六:排除依賴傳遞,解決依賴沖突

1甸私、exclude:設(shè)置不編譯指定的模塊诚些,排除指定模塊的依賴

2、transitive:用于自動處理子依賴項(xiàng),默認(rèn)為true诬烹,gradle自動添加子依賴項(xiàng)砸烦。設(shè)置為false排除所有的傳遞依賴

3、force:強(qiáng)制設(shè)置某個模塊的版本绞吁。

常見代碼實(shí)現(xiàn):

implementation ('io.reactivex.rxjava2:rxandroid:2.1.0')?{

???????exclude group: 'io.reactivex.rxjava2', module: 'rxjava'

???}


依賴替換規(guī)則

??依賴替換規(guī)則的適用場景分為以下幾種:

1.根據(jù)某些條件對依賴進(jìn)行替換幢痘;

2.將本地依賴替換為外部依賴;

3.將外部依賴替換為本地依賴家破;


外部依賴和本地依賴是什么颜说。

外部依賴:外部依賴,顧名思義汰聋,就是從遠(yuǎn)程倉庫拉取的依賴门粪,也被稱為常用的三方庫:

//從遠(yuǎn)程倉庫拉取的開源代碼庫

implementation 'com.facebook.stetho:stetho:1.5.1'

implementation 'io.reactivex.rxjava3:rxjava:3.0.0-RC0‘


本地依賴:也就是我們項(xiàng)目中常見的module,按照**《阿里Java開發(fā)手冊》**中來描述,也叫做一方庫:

implementation project(':library')

? ? ? ?根據(jù)某些條件對依賴進(jìn)行替換舉個例子烹困,很多UI三方庫都會依賴RecyclerView玄妈,但這么多的依賴庫,我們不可避免遇到版本不同導(dǎo)致依賴沖突的情況髓梅,一般情況下措近,我們是這么解決的:

???????????//將RecyclerView的依賴從這個三方庫中排除掉

???????????implementation "xxx.xxx:xxx:1.0.0",{

???????????exclude group: 'com.android.support', module: 'recyclerview-v7'

???????}

? ? ? ? ?將RecyclerView的依賴從這個三方庫中排除掉,令其使用項(xiàng)目本身的RecyclerView版本女淑,這樣項(xiàng)目就可以正常運(yùn)行了瞭郑,看起來并沒有什么問題。

試想鸭你,如果項(xiàng)目的依賴比較復(fù)雜屈张,也許我們要面對的將是這樣的依賴配置:

???????implementation "libraryA:xxx:1.0.0",{

???????exclude group: 'com.android.support', module: 'recyclerview-v7'

???????}

???????implementation "libraryB:xxx:2.2.0",{

???????exclude group: 'com.android.support', module: 'recyclerview-v7'

???????}

???????implementation "libraryC:xxx:0.0.8",{

???????exclude group: 'com.android.support', module: 'recyclerview-v7'

???????}

將外部依賴替換為本地依賴

???????該規(guī)則和2非常相似阁谆,只不過將依賴替換的雙方調(diào)換了而已场绿,下面是官方的示例代碼:

???????configurations.all{

???????resolutionStrategy.dependencySubstitution{

???????substitute module("org.utils:api") because "we work with the unreleased development version" with project(":api")

???????substitute module("org.utils:util:2.5") with project(":util")

???????}

???????}

???????1.因?yàn)間roup不同嫉入,所以需要先將2.x的rxjava全局exclude掉咒林;

???????2.將所有3.x的rxjava的依賴版本都統(tǒng)一(文中是3.0.0-RC0)


七:Gradle打包時的Proguard

1、通過在buildTypes中配置minifyEnable來開啟和關(guān)閉proguard

2澎粟、通過proguardFiles來配置混淆參數(shù)與keep的內(nèi)容


混淆的作用:

1活烙、壓縮(Shrink):檢測并移除代碼中無用的類、字段啸盏、方法和特性(Attribute)宫补。

2曾我、優(yōu)化(Optimize):對字節(jié)碼進(jìn)行優(yōu)化,移除無用的指令贫贝。

3蛉谜、混淆(Obfuscate):使用a型诚,b,c也搓,d這樣簡短而無意義的名稱涵紊,對類、字段和方法進(jìn)行重命名颤练。

4嗦玖、預(yù)檢(Preveirfy):在Java平臺上對處理后的代碼進(jìn)行預(yù)檢踏揣,確保加載的class文件是可執(zhí)行的匾乓。

哪些不做混淆:

1、Android系統(tǒng)組件

2彰亥、JNI

3任斋、反射

4、WebView的JS調(diào)用

5耻涛、內(nèi)部類

6、Annottation

7抹缕、enum

8卓研、范型

9奏赘、序列化

10、第三方


八:多渠道打包

原理:在AndroidManifest.xml配置mete-data

<meta-data

???????android:name="UMENG_CHANNEL"

???????android:value="Channel_ID" />

配置Flavors:

android {

productFlavors{

???????xiaomi{

???????manifestPlaceholders= [UMENG_CHANNEL_VALUE: "xiaomi"]}

???????_360 {

???????manifestPlaceholders= [UMENG_CHANNEL_VALUE: "_360"]}

???????baidu{

???????manifestPlaceholders= [UMENG_CHANNEL_VALUE: "baidu"]}

???????wandoujia{

???????manifestPlaceholders= [UMENG_CHANNEL_VALUE: "wandoujia"]}

???????}

}

批量修改:

android {

??productFlavors{

???????xiaomi{}

???????_360 {}

???????baidu{}

???????wandoujia{}

}

productFlavors.all{

???????flavor ->flavor.manifestPlaceholders= [UMENG_CHANNEL_VALUE: name]

???????}}

? ? ?在APP內(nèi)讀取mete-data配置確定渠道

? ? ? 然后用./gradlewassembleRelease這條命令會把Product Flavor下的所有渠道的Release版本都打出來。

? ? ? ?因?yàn)橐陨戏椒ㄐ枰啻尉幾g柜某,速度較慢喂击,當(dāng)渠道變多之后不適合多渠道打包

改進(jìn)的方法1:apk反編譯后重寫AndroidManifest文件翰绊,再重新編譯簽名

改進(jìn)的方法2:如果在META-INF目錄內(nèi)添加空文件旁壮,可以不用重新簽名應(yīng)用。因此,通過為不同渠道的應(yīng)用添加不同的空文件刽肠,可以唯一標(biāo)識一個渠道,因?yàn)関1簽名可以在不改變簽名情況下二次打包惫撰,我們可以在gradle中對dex文件進(jìn)行自己的簽名躺涝。

???在采用V2簽名后坚嗜,以上方法不再適用,考慮到V2簽名的特點(diǎn)(對APK Signing Block是不進(jìn)行驗(yàn)證的)诱建,我們向V2簽名后的APK簽名區(qū)塊寫入渠道號励翼,實(shí)現(xiàn)多渠道打包汽抚。


備注:在多渠道批量打包方面,可以參考使用:騰訊VasDolly否过,美團(tuán)Walle苗桂。

九:如何提高Gradle編譯效率

備注:上面是谷歌官方推薦的提升Gradle編譯速度的建議,具體詳情可以去擴(kuò)展閱讀中查看便锨。


十:擴(kuò)展閱讀

1、https://blog.csdn.net/itachi85/article/details/81906139(劉望舒系列)

2吱殉、http://www.reibang.com/p/2e19268bf387(AndroidGradle學(xué)習(xí)(七):Gradle構(gòu)建生命周期)

3贩虾、https://blog.csdn.net/woxueliuyun/article/details/54602701(Gradle生命周期)

4缎罢、https://blog.csdn.net/u011486491/article/details/79001186(AndroidGradle學(xué)習(xí)2——gradle生命周期和重要的gradle)

5考杉、https://blog.csdn.net/coloriy/article/details/52807393(AndroidGradle看這一篇就夠了)

6崇棠、http://www.reibang.com/p/c11862136abf(史上最全Androidbuild.gradle配置詳解)

7枕稀、http://www.reibang.com/p/1274c1f1b6a4(要點(diǎn)提煉|Gradle指南)

8、http://www.reibang.com/p/2bd920314012(AndroidGradle干貨)

9萎坷、http://www.reibang.com/p/dcf14b220a19(不一樣的Gradle多渠道配置總結(jié))

10凹联、http://www.reibang.com/p/d84032b46b56(如何開發(fā)一款高性能的gradletransform)

11、https://juejin.im/post/5d2dee0851882569755f5494(JakeWharton評價我的代碼像是在打地鼠)

12哆档、http://www.reibang.com/p/b7a6ee994a52(Android應(yīng)用構(gòu)建速度提升的十個小技巧)

13蔽挠、https://blog.csdn.net/weixin_34290352/article/details/88009764(Android面試題之Gradle配置篇)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓜浸,隨后出現(xiàn)的幾起案子澳淑,更是在濱河造成了極大的恐慌,老刑警劉巖插佛,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杠巡,死亡現(xiàn)場離奇詭異,居然都是意外死亡雇寇,警方通過查閱死者的電腦和手機(jī)忽孽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谢床,“玉大人兄一,你說我怎么就攤上這事∈锻龋” “怎么了出革?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渡讼。 經(jīng)常有香客問我骂束,道長耳璧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任展箱,我火速辦了婚禮旨枯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘混驰。我一直安慰自己攀隔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布栖榨。 她就那樣靜靜地躺著昆汹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婴栽。 梳的紋絲不亂的頭發(fā)上满粗,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音愚争,去河邊找鬼映皆。 笑死,一個胖子當(dāng)著我的面吹牛轰枝,可吹牛的內(nèi)容都是我干的捅彻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼狸膏,長吁一口氣:“原來是場噩夢啊……” “哼沟饥!你這毒婦竟也來了添怔?” 一聲冷哼從身側(cè)響起湾戳,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎广料,沒想到半個月后砾脑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艾杏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年韧衣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片购桑。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡畅铭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勃蜘,到底是詐尸還是另有隱情硕噩,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布缭贡,位于F島的核電站炉擅,受9級特大地震影響辉懒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谍失,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一眶俩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧快鱼,春花似錦颠印、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柒莉,卻和暖如春闻坚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背兢孝。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工窿凤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跨蟹。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓雳殊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窗轩。 傳聞我的和親對象是個殘疾皇子夯秃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容