通過(guò)Gradle動(dòng)態(tài)修改Manifest文件

1. Gradle

Gradle是開(kāi)源的自動(dòng)化構(gòu)建工具,基于JVM剥哑,有良好的擴(kuò)展性和性能,對(duì)IDE支持,支持編寫(xiě)自定義任務(wù)占卧,在Android領(lǐng)域,用于構(gòu)建和編譯應(yīng)用的資源和源代碼溢吻,然后將它們打包成可供您測(cè)試乌庶、部署、簽署和分發(fā)的 APK左痢,另外在插件化和熱修復(fù)的領(lǐng)取中起重要的作用靡羡。

gradle構(gòu)建有三個(gè)階段

  • 初始化
    分析哪些module將參與構(gòu)建系洛,settings.gradle文件會(huì)被解析。
  • 配置
    處理module的build腳本略步,處理屬性和task的依賴(lài)關(guān)系描扯,build.gradle文件會(huì)被解析配置
  • 執(zhí)行
    按照配置過(guò)程處理的任務(wù)依賴(lài)關(guān)系相繼執(zhí)行task

2. 通過(guò)Gradle動(dòng)態(tài)修改Manifest文件

例如:在release包manifest中動(dòng)態(tài)添加標(biāo)簽為meta-data的渠道號(hào)channel<meta-data android:name=“channel" android:value=“1001" />

思路

  1. 在項(xiàng)目配置結(jié)束的task中,找到生成Release的manifest的task
  2. 通過(guò)該task找到輸出的manifest文件并讀取文本內(nèi)容
  3. 使用Groovy的Xml Api對(duì)manifest進(jìn)行修改
  4. 修改后重新寫(xiě)趟薄,輸出至原始目錄

完整代碼如下绽诚,代碼解釋見(jiàn)3.X

project.afterEvaluate {  //3.1
    android.applicationVariants.all { ApplicationVariant variant ->  //3.2
        String variantName = variant.name.capitalize()  //3.3
        def processManifestTask = project.tasks.getByName("process${variantName}Manifest")  //3.4

        processManifestTask.doLast { pmt ->  //3.5
            String manifestPath = "$pmt.manifestOutputDirectory/AndroidManifest.xml"  //3.6
            def manifest = file(manifestPath).getText()  //3.7

            if (project.hasProperty("channel")) {
                def channelNo = project.property("channel")
                
                def xml = new XmlParser().parseText(manifest)  //3.8 
                xml.application[0].appendNode("meta-data", ['android:name': 'channel', 'android:value': channelNo])
                def serialize = XmlUtil.serialize(xml)
                file(manifestPath).write(serialize)
            }
        }
    }
}

終端中運(yùn)行: gradle clean aR -P channel=101
查看apk中的manifest文件發(fā)現(xiàn)渠道號(hào)已經(jīng)動(dòng)態(tài)的添加進(jìn)去了


image.png

3.1 project

project和build.gralde一一對(duì)應(yīng),在構(gòu)建初始化期間杭煎,Gradle Project為每個(gè)參與構(gòu)建的項(xiàng)目組裝一個(gè)對(duì)象恩够。

project.afterEvaluate(Closure closure)
參數(shù)是一個(gè)閉包,在項(xiàng)目配置后立即調(diào)用羡铲。project作為參數(shù)傳遞給閉包蜂桶。

3.2 ApplicationVariant

Android的構(gòu)建變體,可以理解為一個(gè)版本也切,例如debug扑媚,release等等,在項(xiàng)目配置結(jié)束后可以通過(guò)AppExtension.getApplicationVariants().all方法獲取贾费,或者通過(guò)DefaultGroovyMethods.each()方法獲取钦购。


官方ApplicationVariant文檔說(shuō)明.png

由api可知,使用all可以處理后面添加進(jìn)來(lái)的構(gòu)建變體褂萧,使用each只能處理當(dāng)前的押桃,所以建議用all。

3.3 variant.name.capitalize()

通過(guò)查看源碼發(fā)現(xiàn)capitalize()是org.codehaus.groovy.runtime下StringGroovyMethods的一個(gè)方法导犹,查看Groovy Api:


image.png

將第一個(gè)字母變大寫(xiě)唱凯,便于后續(xù)字符串拼接獲取manifest,
variant.name= release
variant.name.capitalize()= Release

3.4 project.tasks.getByName(String name)

    T getByName(String name) throws UnknownTaskException;

根據(jù)Api可知,通過(guò)task的名稱(chēng)獲取該task

3.5 task.doLast

task是gradle的執(zhí)行單元谎痢,gradle的構(gòu)建是通過(guò)taks的執(zhí)行來(lái)完成磕昼。
定義名為hello的task如下:

task hello {
    printf "hello\n"
}

hello.doLast {
    printf "doLast\n"
}

執(zhí)行g(shù)radle clean

> Configure project :app
hello

執(zhí)行g(shù)radle hello

> Configure project :app
hello
> Task :app:hello
doLast

可以看到在執(zhí)行一些配置任務(wù)時(shí)候hello任務(wù)也會(huì)一起執(zhí)行,但是hello的doLast并沒(méi)有執(zhí)行节猿,如果不需要在配置時(shí)候執(zhí)行我們的自定義的任務(wù)票从,可以使用doLast來(lái)完成。

3.6 manifestOutputDirectory

通過(guò)該task的manifest輸出路徑獲取manifest文件

 processManifestTask.doLast { pmt ->
            String manifestPath = "$pmt.manifestOutputDirectory/AndroidManifest.xml"
.......

代碼是個(gè)閉包滨嘱,pmt是processManifestTask的自定義簡(jiǎn)稱(chēng)峰鄙,可以不定義,那么代碼為

 processManifestTask.doLast { ->
            String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml"
.......

3.7 file(manifestPath).getText()

 public static String getText(File file) throws IOException {
        return IOGroovyMethods.getText(newReader(file));
    }

傳入個(gè)file對(duì)象通過(guò)BufferedReader讀取從而獲取文本

3.8 操作XML

使用Groovy解析XML的最常用方法如下:

  • groovy.util.XmlParser
  • groovy.util.XmlSlurper
相同點(diǎn)
  • 兩者都是基于SAX它們都是低內(nèi)存占用
  • 兩者都可以更新/轉(zhuǎn)換XML
不同點(diǎn)
  1. 返回值
  • XmlSlurper. parseText返回GPathResult
  • XmlParser. parseText返回Node
  1. 使用場(chǎng)景
  • 如果將現(xiàn)有文檔轉(zhuǎn)換成另一個(gè)文檔太雨,那么推薦用XmlSlurper
  • 如果只有少許節(jié)點(diǎn)吟榴,也推薦用XmlSlurper,這樣不用在內(nèi)存中創(chuàng)建完整的結(jié)構(gòu)
  • 如果想同時(shí)更新和閱讀囊扳,那么推薦用XmlParser

3.8.1 添加節(jié)點(diǎn)

用到的api:appendNode(XmlParser為例)

 def xml = new XmlParser().parseText(manifest)
 xml.application[0].appendNode("meta-data", ['android:name': 'channel', 'android:value': channelNo])

此時(shí)xml.application[0]是獲取第一個(gè)application節(jié)點(diǎn)吩翻,雖然manifest只有一個(gè)application兜看,也需要帶上[0],例如獲取application內(nèi)的第一個(gè)activity節(jié)點(diǎn)為:

 xml.application.activity[0]

3.8.2 序列化并更新

將修改過(guò)的xml進(jìn)行序列化為原生manifest狭瞎,再通過(guò)文件路徑寫(xiě)入更新

def serialize = XmlUtil.serialize(xml)
file(manifestPath).write(serialize)

引用參考
groovy Xml Api解析
groovy Api
遷移到 Android Plugin for Gradle 3.0.0
Android DSL官方文檔
全面理解Gradle - 定義Task

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末细移,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子熊锭,更是在濱河造成了極大的恐慌葫哗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件球涛,死亡現(xiàn)場(chǎng)離奇詭異劣针,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)亿扁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)捺典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人从祝,你說(shuō)我怎么就攤上這事襟己。” “怎么了牍陌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵擎浴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我毒涧,道長(zhǎng)贮预,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任契讲,我火速辦了婚禮仿吞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捡偏。我一直安慰自己唤冈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布银伟。 她就那樣靜靜地躺著你虹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彤避。 梳的紋絲不亂的頭發(fā)上傅物,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音忠藤,去河邊找鬼挟伙。 笑死楼雹,一個(gè)胖子當(dāng)著我的面吹牛模孩,可吹牛的內(nèi)容都是我干的尖阔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼榨咐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼介却!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起块茁,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤齿坷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后数焊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體永淌,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年佩耳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遂蛀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡干厚,死狀恐怖李滴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛮瞄,我是刑警寧澤所坯,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站挂捅,受9級(jí)特大地震影響芹助,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闲先,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一周瞎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饵蒂,春花似錦声诸、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至渊迁,卻和暖如春慰照,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背琉朽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工毒租, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箱叁。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓墅垮,卻偏偏與公主長(zhǎng)得像惕医,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子算色,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354