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插件很是重要.