概述
之前写过一篇文章说明如何编译期间修改manifest,但是那个方法读取的是本地manifest清单,会同时修改本地的代码,下面给出优化后的实现方案,不会有这个问题。
实现
创建Plugin作为入口
推荐以插件的形式进行修改, 维护方便一些。
class PluginGroovy implements Plugin<Project> {
private String variantName
@Override
void apply(Project target) {
}
}
获取当前的编译变体名称
/**
* 获取当前编译的变体名称
*
* @param project
*/
private void getVariantNameInBuild(Project project) {
try { // 根据实际的情况处理为真正的变体名称
variantName = project.gradle.startParameter.taskNames[0]
} catch (Exception e) {
e.printStackTrace()
}
}
检验当前的变体是否符合要求
private boolean isValidVariantName() {
variantName != null && variantName.length() > 0 && !variantName.contains("clean")
}
添加修改manifest的Task
/**
* 添加处理manifest的Task
*
* @param project
*/
private void addTaskForPackageManifest(Project project) {
// 找到 processManifestTask
def processManifestTask = project.getTasks().getByName(String.format("process%sManifest", variantName.capitalize()))
// 创建自定义任务
def modifyManifestTask = project.tasks.create("modify${variantName.capitalize()}Manifest") {
doLast {
// 获取编译后的 AndroidManifest.xml 文件路径
def manifestFile = new File("${project.buildDir}/intermediates/merged_manifests/${variantName}/AndroidManifest.xml")
if (manifestFile.exists()) {
// 执行修改
handlerVariantManifestFile(manifestFile)
} else {
println("Manifest file not found: ${manifestFile}")
}
}
}
// 确保自定义任务在 processManifestTask 任务之后执行
processManifestTask.finalizedBy(modifyManifestTask)
}
修改文件并重新写入
/**
* 处理单个变体的Manifest文件
*/
private static void handlerVariantManifestFile(File manifestFile) {
SAXReader saxReader = new SAXReader()
def mergedManifestDoc = saxReader.read(manifestFile)
modifyBaseManifestContent(mergedManifestDoc, manifestFile)
}
/**
* 修改Manifest文件
*
* @param document
* @param xmlFile
*/
private static void modifyBaseManifestContent(Document document, File xmlFile) {
Element rootNode = document.getRootElement()
Element applicationElement = rootNode.element("application")
if (applicationElement != null) {
Attribute directBootNode = applicationElement.attribute("directBootAware")
if (directBootNode != null) {
directBootNode.setValue("false")
}
OutputFormat format = OutputFormat.createPrettyPrint()
format.setEncoding("UTF-8")
XMLWriter writer = new XMLWriter(
new OutputStreamWriter(new FileOutputStream(xmlFile)), format)
writer.write(document)
writer.close()
}
}
完整实现
private void modifyManifest(Project target) {
println("modifyManifest start! need directBoot : $needDirectBoot")
// 在sync中无法获取到variantName
getVariantNameInBuild(target)
System.out.println(String.format("Welcome %s ManifestProject", variantName))
if (!isValidVariantName()) {
return
}
// 添加处理manifest文件的task
addTaskForVariantAfterEvaluate(target)
}
/**
* 获取当前编译的变体名称
*
* @param project
*/
private void getVariantNameInBuild(Project project) {
try { // 因为ape插件的原因, 需要做还原
variantName = project.gradle.startParameter.taskNames[0].replace("apeSign", "")
} catch (Exception e) {
e.printStackTrace()
}
}
private boolean isValidVariantName() {
variantName != null && variantName.length() > 0 && !variantName.contains("clean")
}
/**
* 在项目配置完成之后添加task
* @param project
*/
private void addTaskForVariantAfterEvaluate(Project project) {
//在项目配置完成后,添加自定义Task
project.afterEvaluate {
//为当前变体的task都加入到这个任务队列中。
//所以通过project.getTasks().each {}去匹配每个task的startsWith&&endsWith的逻辑是一致的
//并且这种性能会更高
//直接通过task的名字找到ProcessApplicationManifest这个task
addTaskForPackageManifest(project)
}
}
/**
* 添加处理manifest的Task
*
* @param project
*/
private void addTaskForPackageManifest(Project project) {
// 找到 processManifestTask
def processManifestTask = project.getTasks().getByName(String.format("process%sManifest", variantName.capitalize()))
// 创建自定义任务
def modifyManifestTask = project.tasks.create("modify${variantName.capitalize()}Manifest") {
doLast {
// 获取编译后的 AndroidManifest.xml 文件路径
def manifestFile = new File("${project.buildDir}/intermediates/merged_manifests/${variantName}/AndroidManifest.xml")
if (manifestFile.exists()) {
handlerVariantManifestFile(manifestFile)
} else {
println("Manifest file not found: ${manifestFile}")
}
}
}
// 确保自定义任务在 processManifestTask 任务之后执行
processManifestTask.finalizedBy(modifyManifestTask)
}
/**
* 处理单个变体的Manifest文件
*/
private static void handlerVariantManifestFile(File manifestFile) {
SAXReader saxReader = new SAXReader()
def mergedManifestDoc = saxReader.read(manifestFile)
modifyBaseManifestContent(mergedManifestDoc, manifestFile)
}
/**
* 修改Manifest文件
*
* @param document
* @param xmlFile
*/
private static void modifyBaseManifestContent(Document document, File xmlFile) {
Element rootNode = document.getRootElement()
Element applicationElement = rootNode.element("application")
if (applicationElement != null) {
Attribute directBootNode = applicationElement.attribute("directBootAware")
if (directBootNode != null) {
directBootNode.setValue("false")
}
OutputFormat format = OutputFormat.createPrettyPrint()
format.setEncoding("UTF-8")
XMLWriter writer = new XMLWriter(
new OutputStreamWriter(new FileOutputStream(xmlFile)), format)
writer.write(document)
writer.close()
}
}
修改效果
解压apk可以看到,directBootAware属性被成功修改为false