1. Gradle
Gradle是开源的自动化构建工具,基于JVM,有良好的扩展性和性能,对IDE支持,支持编写自定义任务,在Android领域,用于构建和编译应用的资源和源代码,然后将它们打包成可供您测试、部署、签署和分发的 APK,另外在插件化和热修复的领取中起重要的作用。
gradle构建有三个阶段
初始化
分析哪些module将参与构建,settings.gradle文件会被解析。配置
处理module的build脚本,处理属性和task的依赖关系,build.gradle文件会被解析配置执行
按照配置过程处理的任务依赖关系相继执行task
2. 通过Gradle动态修改Manifest文件
例如:在release包manifest中动态添加标签为meta-data的渠道号channel<meta-data android:name=“channel" android:value=“1001" />
思路
在项目配置结束的task中,找到生成Release的manifest的task
通过该task找到输出的manifest文件并读取文本内容
使用Groovy的Xml Api对manifest进行修改
修改后重新写,输出至原始目录
完整代码如下,代码解释见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) } } } }
终端中运行: gradle clean aR -P channel=101
查看apk中的manifest文件发现渠道号已经动态的添加进去了
image.png
3.1 project
project和build.gralde一一对应,在构建初始化期间,Gradle Project为每个参与构建的项目组装一个对象。
project.afterEvaluate(Closure closure)
参数是一个闭包,在项目配置后立即调用。project作为参数传递给闭包。
3.2 ApplicationVariant
Android的构建变体,可以理解为一个版本,例如debug,release等等,在项目配置结束后可以通过AppExtension.getApplicationVariants().all方法获取,或者通过DefaultGroovyMethods.each()方法获取。
官方ApplicationVariant文档说明.png
由api可知,使用all可以处理后面添加进来的构建变体,使用each只能处理当前的,所以建议用all。
3.3 variant.name.capitalize()
通过查看源码发现capitalize()是org.codehaus.groovy.runtime下StringGroovyMethods的一个方法,查看Groovy Api:
image.png
将第一个字母变大写,便于后续字符串拼接获取manifest,variant.name= release
variant.name.capitalize()= Release
3.4 project.tasks.getByName(String name)
T getByName(String name) throws UnknownTaskException;
根据Api可知,通过task的名称获取该task
3.5 task.doLast
task是gradle的执行单元,gradle的构建是通过taks的执行来完成。
定义名为hello的task如下:
task hello { printf "hello\n"} hello.doLast { printf "doLast\n"}
执行gradle clean
> Configure project :apphello
执行gradle hello
> Configure project :apphello > Task :app:hellodoLast
可以看到在执行一些配置任务时候hello任务也会一起执行,但是hello的doLast并没有执行,如果不需要在配置时候执行我们的自定义的任务,可以使用doLast来完成。
3.6 manifestOutputDirectory
通过该task的manifest输出路径获取manifest文件
processManifestTask.doLast { pmt -> String manifestPath = "$pmt.manifestOutputDirectory/AndroidManifest.xml".......
代码是个闭包,pmt是processManifestTask的自定义简称,可以不定义,那么代码为
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)); }
传入个file对象通过BufferedReader读取从而获取文本
3.8 操作XML
使用Groovy解析XML的最常用方法如下:
groovy.util.XmlParser
groovy.util.XmlSlurper
相同点
两者都是基于SAX它们都是低内存占用
两者都可以更新/转换XML
不同点
返回值
XmlSlurper. parseText返回GPathResult
XmlParser. parseText返回Node
使用场景
如果将现有文档转换成另一个文档,那么推荐用XmlSlurper
如果只有少许节点,也推荐用XmlSlurper,这样不用在内存中创建完整的结构
如果想同时更新和阅读,那么推荐用XmlParser
3.8.1 添加节点
用到的api:appendNode(XmlParser为例)
def xml = new XmlParser().parseText(manifest) xml.application[0].appendNode("meta-data", ['android:name': 'channel', 'android:value': channelNo])
此时xml.application[0]是获取第一个application节点,虽然manifest只有一个application,也需要带上[0],例如获取application内的第一个activity节点为:
xml.application.activity[0]
3.8.2 序列化并更新
将修改过的xml进行序列化为原生manifest,再通过文件路径写入更新
def serialize = XmlUtil.serialize(xml)file(manifestPath).write(serialize)
作者:小波_po
链接:https://www.jianshu.com/p/f5cd48019109
共同学习,写下你的评论
评论加载中...
作者其他优质文章