前言
现项目有一个需求,不同的渠道打包,需要对AndroidManifest.xml进行增删修改,简单的修改可以通过productFlavors占位符替换即可完成相应的功能,但是有时候我们想要进行增加或者删除呢,比如需要删除一个结点(四大组件)怎么办?或者想要动态增加一个结点怎么办呢?大家首先想到的是通过gradle编译打包的时候进行修改,但是gradle版本的不同,对向下兼容又做的不好,就需要我们对各个版本进行去适配,因为现在用的最多的是4.0以上或者3.5的版本,我就拿这两个版本做例子:
gradle3.5动态修改Manifest文件
网上也有很多种不同的实现,我这里只讲解我自己在项目上用的一种,实际上gradle就是一种工具,只要能实现我们的需求就行。
android {
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
output.processResources.doFirst { pm ->
String manifestPath = output.processResources.manifestFile
String manifestContent = file(manifestPath).getText()
def android = new Namespace("http://schemas.android.com/apk/res/android", "android")
def xml = new XmlParser().parseText(manifestContent)
xml.application[0].appendNode("meta-data", ['android:name': 'channel', 'android:value': 'test'])
xml.application[0].appendNode("provider", ['android:name' : 'com.test.provider',
'android:authorities': 'com.test.provider',
'android:enabled' : 'true',
'android:exported' : 'true'])
xml.application[0].'*'.removeAll {
(it.attributes()[android.name] == 'com.test.provider')
}
def nodes=xml.application[0].'*'.findAll{
(it.name()=='provider' && provider.attributes()[android.name] == 'com.test.provider') }
nodes.each { provider->
println 'provider attributes ' + provider.attributes()
println 'provider name ' + provider.attributes()[android.name]
}
def serialize = groovy.xml.XmlUtil.serialize(xml)
file(manifestPath).write(serialize)
}
}
}
}
以上就是对AndroidManifest的增删改查,另外教大家一个可以查看gradle源码的小技巧,在我们项目module(通常对应的是app)中的build.gradle里面增加:
android {
dependencies{
implementation "com.android.tools.build:gradle:3.5.2"
}
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
}
}
}
这样就可以看到里面的源码了,找到BaseVariantOutput类,里面有:
/**
* Returns the Android Resources processing task.
*
* @deprecated Use {@link #getProcessResourcesProvider()}
*/
@NonNull
@Deprecated
ProcessAndroidResources getProcessResources();
/**
* Returns the {@link TaskProvider} for the Android Resources processing task.
*
* <p>Prefer this to {@link #getProcessResources()} as it triggers eager configuration of the
* task.
*/
@NonNull
TaskProvider<ProcessAndroidResources> getProcessResourcesProvider();
/**
* Returns the manifest merging task.
*
* @deprecated Use {@link #getProcessManifestProvider()}
*/
@NonNull
@Deprecated
ManifestProcessorTask getProcessManifest();
/**
* Returns the {@link TaskProvider} for the manifest merging task
*
* <p>Prefer this to {@link #getProcessManifest()} as it triggers eager configuration of the
* task.
*/
@NonNull
TaskProvider<ManifestProcessorTask> getProcessManifestProvider();
发现咱们刚才用的getProcessResources过时了,但是在3.5还是能使用的,最终改变的Manifest文件会放到
app/build/intermediates/merged_manifests里面,getProcessResourcesProvider的使用跟getProcessResources差不多
output.processResourcesProvider.get().doFirst {
...
}
用getProcessManifest和getProcessManifestProvider也能实现上面的功能的,我在这里就不一一列出来了,大家可以进去看看ManifestProcessorTask这个类里面的函数:
/** The processed Manifests files folder. */
@NonNull
@OutputDirectory
public DirectoryProperty getManifestOutputDirectory() {
return manifestOutputDirectory;
}
/**
* The bundle manifest which is consumed by the bundletool (as opposed to the one packaged with
* the apk when built directly).
*/
@OutputDirectory
@Optional
public File getBundleManifestOutputDirectory() {
return bundleManifestOutputDirectory;
}
上面这两个函数应该都可以获取manifest的路径,这两个函数的区别我没有仔细研究,有兴趣的可以去查看一下
由于项目工程升级到4.1.2了,发现上面的函数都行不通了,修改的文件通过app/build/intermediates/merged_manifests路径也能看到,但是就是不打包到APK里面,让我很苦恼,最后发现gradle4.0升级后,改变路径了,所生成的manifest文件放到了app/build/intermediates/merged_manifest里面(真坑人,让我找了好长时间),而且之前使用的getProcessResources也不行了,下面是4.0以上的写法
gradle4.1.2(这是我项目的版本)动态修改Manifest文件
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
output.processManifestProvider.get().doFirst {
def manifestPath = new File("${buildDir}/intermediates/merged_manifest/${variant.name}/out/AndroidManifest.xml")
String manifestContent = file(manifestPath).getText()
下面的就和上面的一样了
}
}
}
我使用processResources就不行,必须使用processManifestProvider函数,而且4.0以上的ManifestProcessorTask类里面的内容也变了,没有获取路径的函数了,我只能手写路径。