gradle(4.1.0以上和4.0以下) 对AndroidManifest.xml文件增删改查

前言

现项目有一个需求,不同的渠道打包,需要对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类里面的内容也变了,没有获取路径的函数了,我只能手写路径。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容