Gradle DSL 文档html
Gradle基于Groovy,而Groovy基于Java,最后始终得运行在JVM之上.Gradle、build.gradle、settings.gradle之类的最终都会被搞成一个对象,而后才能执行.java
gradle taskName
时,Gradle都会默认构造出一个Gradle对象.在执行过程当中,只有这么一个Gradle对象,通常不多去定制它.它们的生命周期节点以下:node
先建立buildSrc这个module,用于开发插件.(不清楚的能够看我以前发的Gradle系列(四) Gradle插件). 而后新建一个插件类: ManifestDemoPlugin
.android
import org.gradle.api.Plugin
import org.gradle.api.Project
class ManifestDemoPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
}
}
复制代码
上面这份代码是标准代码,写插件都得继承自Plugin.git
需求: 假设是移除android.permission.READ_PHONE_STATE
权限(有时三方库aar里面可能会定义一些权限,可是又不能让app有这些权限,就须要移除掉.这里仅仅是为了练习Gradle,其实有更好的方式移除权限tools:remove
).github
思路: 咱们须要拿到合并以后的AndroidManifest.xml文件,且在打包以前修改这个AndroidManifest.xml文件,将android.permission.READ_PHONE_STATE
内容移除.api
可是咱们怎么hook这个合并AndroidManifest.xml文件的时机,从而拿到清单文件内容呢?首先经过./gradlew tasks --all
命令看看有哪些task,由于合并清单文件确定是一个task里面作的,咱们只须要在这个task以后执行咱们写的代码逻辑便可.markdown
//task实在太多了,这里只是节选.
> Task :tasks
......
app:makeApkFromBundleForDebug
app:makeApkFromBundleForRelease
app:mergeDebugAndroidTestAssets
app:mergeDebugAndroidTestGeneratedProguardFiles
app:mergeDebugAndroidTestJavaResource
app:mergeDebugAndroidTestJniLibFolders
app:mergeDebugAndroidTestNativeLibs
app:mergeDebugAndroidTestResources
app:mergeDebugAndroidTestShaders
app:mergeDebugAssets
app:mergeDebugGeneratedProguardFiles
app:mergeDebugJavaResource
app:mergeDebugJniLibFolders
app:mergeDebugNativeLibs
app:mergeDebugResources
app:mergeDebugShaders
app:mergeDexRelease
app:mergeExtDexDebug
app:mergeExtDexDebugAndroidTest
app:mergeExtDexRelease
app:mergeLibDexDebug
app:mergeLibDexDebugAndroidTest
app:mergeProjectDexDebug
app:mergeProjectDexDebugAndroidTest
app:packageDebug
app:packageDebugAndroidTest
app:packageDebugBundle
app:packageDebugUniversalApk
app:packageRelease
app:packageReleaseBundle
app:packageReleaseUniversalApk
app:parseDebugIntegrityConfig
app:parseReleaseIntegrityConfig
app:preBuild
app:preDebugAndroidTestBuild
app:preDebugBuild
app:preDebugUnitTestBuild
prepareKotlinBuildScriptModel
app:prepareKotlinBuildScriptModel
app:prepareLintJar
app:prepareLintJarForPublish
......
复制代码
其中有一个task叫app:mergeDebugResources
,翻译过来就是合并资源嘛,看起来就是咱们要找的.下面是Android Plugin Task的大体含义.网络
class ManifestDemoPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
//在afterEvaluate,配置完成以后才能拿到那些task完整的有向图
project.afterEvaluate {
//1. 找到mergeFreeDebugResources这个task
def mergeDebugResourcesTask = project.tasks.findByName("mergeFreeDebugResources")
if (mergeDebugResourcesTask != null) {
//2. 建立一个task
def parseDebugTask = project.tasks.create("ParseDebugTask", ParseDebugTask.class)
//3. 添加一个mergeDebugResourcesTask结束后立马执行的task: parseDebugTask
mergeDebugResourcesTask.finalizedBy(parseDebugTask)
}
}
}
}
复制代码
project.tasks
拿到全部的task(API文档地址在这里),而后再findByName方法找到这个task.mergeFreeDebugResources
执行完成以后立马开始执行.来看看咱们的Task该怎么写:app
class ParseDebugTask extends DefaultTask {
@TaskAction
void doAction() {
//1. 找到清单文件这个file
def file = new File(project.buildDir, "/intermediates/merged_manifests/freeDebug/AndroidManifest.xml")
if (!file.exists()) {
println("文件不存在")
return
}
//2. 得到文件内容
def fileContent = file.getText()
removePermission(file, fileContent)
}
/** * 动态给清单文件移除权限 * @param rootNode Node * @param file 清单文件 */
void removePermission(File file,String fileContent) {
//方案1 这样会把全部权限都移除了,暂时没找到合适的办法
//def rootNode = new XmlParser().parseText(fileContent)
//def node = new Node(rootNode, "uses-permission"/*,["android:name" : "android.permission.READ_PHONE_STATE"]*/)
//rootNode.remove(node)
//def updateXmlContent = XmlUtil.serialize(rootNode)
//println(updateXmlContent)
//方案2 读取到xml内容以后,将制定权限的字符串给替换掉,,妙啊 妙啊
fileContent = fileContent.replace("android.permission.READ_PHONE_STATE", "")
println(fileContent)
//将字符串写入文件
file.write(fileContent)
}
}
复制代码
build/intermediates/merged_manifests/freeDebug/
目录下,先获得这个文件file.getText()
获取文件内容,再将内容里面的字符串"android.permission.READ_PHONE_STATE"移除掉.顺便,咱还能够再来一个,动态添加一个权限:android.permission.INTERNET
/** * 动态给清单文件添加权限 * @param rootNode Node * @param file 清单文件 */
void addPermission(File file,,String fileContent) {
def rootNode = new XmlParser().parseText(fileContent)
//3. 添加网络权限 这里得加上xmlns:android
//<uses-permission android:name="android.permission.INTERNET"/>
//xmlns:android="http://schemas.android.com/apk/res/android"
rootNode.appendNode("uses-permission", ["xmlns:android": "http://schemas.android.com/apk/res/android",
"android:name" : "android.permission.INTERNET"])
//还能够动态将meta-data加到Application中
//rootNode.application[0].appendNode("meta-data", ['android:name': 'appId', 'android:value': 546525])
//4. 拿到修改后的xml内容
def updateXmlContent = XmlUtil.serialize(rootNode)
println(updateXmlContent)
//5. 将修改后的xml 写入file中
file.write(updateXmlContent)
}
复制代码
刚开始的时候API很是不熟悉,咱得疯狂地查API.尽可能想一些需求作练习,多写写代码,多查查API,熟悉这个过程.Gradle插件很是重要.