? ? ? ? 我們知道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配置篇)