在Gradle任务processManifest.doLast中编辑AndroidManifest.xml从Android Studio运行应用程序时无效 [英] Editing AndroidManifest.xml in Gradle task processManifest.doLast has no effect when running app from Android Studio

查看:364
本文介绍了在Gradle任务processManifest.doLast中编辑AndroidManifest.xml从Android Studio运行应用程序时无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在编译时使用以下Gradle脚本对AndroidManifest.xml进行了一些修改.在此示例中,我想注入一个<meta-data>元素.该代码基于此答案.

 android {
    // ...
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.processManifest.doLast {
                def manifestOutFile = output.processManifest.manifestOutputFile
                def newFileContents = manifestOutFile.getText('UTF-8').replace("</application>", "<meta-data ... /></application>")
                manifestOutFile.write(newFileContents, 'UTF-8')
            }
        }
    }
}
 

当我在Android Studio中执行Gradle同步或从命令行进行干净的构建时,这可以按预期工作:可从应用程序内部访问元数据.

但是,当我运行▶Android Studio中的应用程序时,修改后的清单似乎会被忽略,因为插入的元数据也不是APK中已编译清单的一部分,并且应用程序本身也无法在运行时找到它,元数据根本就不存在.

在所有情况下,合并的中间AndroidManifest.xml(在/build/intermediates/manifests/中)确实包含更改,但是由于某些原因,如果我运行该应用,它似乎会被忽略.

为了更加明显,我尝试插入一些无效的XML:在这种情况下,由于清单中的语法错误,Gradle同步和清理构建均按预期失败.但是我仍然能够从Android Studio运行该应用程序,因此修改实际上被忽略了.

最简单的方法是首先清理项目(在Android Studio中),这将导致清单被重新处理(在语法错误的情况下,我得到了预期的失败),然后运行该应用程序,即使清单无效也可以使用.

请注意,doLast中的任务每次都会执行:打印任务中的println(),并且中间清单包含更改.

就好像清单文件在执行我的任务之前被编译到APK中一样.

这里的问题在哪里?

我正在将Android Studio 2.0与Android Gradle插件2.0.0结合使用.

解决方案

我发现它与Android Studio 2.0中引入的即时运行"功能有关.如果我关闭它,一切都会按预期进行.但是由于我想使用Instant Run,所以我进行了进一步的挖掘.

问题是,启用即时运行后,中间的AndroidManifest.xml文件将位于另一个位置,即/build/intermediates/bundles/myflavor/instant-run/.这意味着我实际上在编辑错误的文件.可以使用属性instantRunManifestOutputFile访问其他清单文件,该属性可以代替manifestOutputFile来使用.

为使其在所有用例中都能正常工作,我检查了两个临时清单文件是否存在,如果存在,请进行修改:

 applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.processManifest.doLast {
            [output.processManifest.manifestOutputFile,
             output.processManifest.instantRunManifestOutputFile
            ].forEach({ File manifestOutFile ->
                if (manifestOutFile.exists()) {
                    def newFileContents = manifestOutFile.getText('UTF-8').replace("</application>", "<meta-data ... /></application>")
                    manifestOutFile.write(newFileContents, 'UTF-8')
                }
            })
        }
    }
}
 

几乎没有instantRunManifestOutputFile的文档.我获得的唯一Google搜索结果是Android Gradle插件源代码.但是后来我又发现了第三个潜在的清单文件属性aaptFriendlyManifestOutputFile,我也不知道这是怎么回事...

I use the following Gradle script to make some modifications to the AndroidManifest.xml at compile time. In this example I want to inject a <meta-data> element. The code is based on this answer.

android {
    // ...
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.processManifest.doLast {
                def manifestOutFile = output.processManifest.manifestOutputFile
                def newFileContents = manifestOutFile.getText('UTF-8').replace("</application>", "<meta-data ... /></application>")
                manifestOutFile.write(newFileContents, 'UTF-8')
            }
        }
    }
}

This works as expected when I do a Gradle sync in Android Studio or make a clean build from command line: The meta-data is accessible from within the app.

But when I run ▶ the application from Android Studio the modified manifest seems to be ignored, since the inserted meta-data is not part of the compiled manifest in the APK, and the app itself cannot find it at runtime either, the meta-data is simply not there.

In all cases the merged intermediate AndroidManifest.xml (in /build/intermediates/manifests/) does contain the changes, but for some reason it looks like it gets ignored if I run the app.

To make it even more obvious, I tried to insert some invalid XML: In this case, the Gradle sync and the clean build failed as expected because of a syntax error in the manifest. But I was still able to run the app from Android Studio, thus the modification effectively gets ignored..

The easiest way to reproduce this is to clean the project first (in Android Studio), which causes the manifest to be reprocessed (in case of the syntax error I get a failure as expected), and then run the app, which works even with an invalid manifest.

Note that the task in doLast gets executed everytime: A println() in the task is printed and the intermediate manifest contains the changes.

It's as if the manifest gets compiled into the APK before my task is executed.

Where is the issue here?

I'm using Android Studio 2.0 with the Android Gradle Plugin 2.0.0.

解决方案

I figured out that it's related to the Instant Run feature introduced in Android Studio 2.0. If I turn it off, everything works as expected. But since I want to use Instant Run, I digged a little further.

The thing is, with Instant Run enabled the intermediate AndroidManifest.xml file will be at another location, namely /build/intermediates/bundles/myflavor/instant-run/. That means I was effectively editing the wrong file. That other manifest file is accessible with the property instantRunManifestOutputFile, which can be used instead of manifestOutputFile.

To make it work in all use-cases I check both temporary manifest files whether they exist and modify them if so:

applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.processManifest.doLast {
            [output.processManifest.manifestOutputFile,
             output.processManifest.instantRunManifestOutputFile
            ].forEach({ File manifestOutFile ->
                if (manifestOutFile.exists()) {
                    def newFileContents = manifestOutFile.getText('UTF-8').replace("</application>", "<meta-data ... /></application>")
                    manifestOutFile.write(newFileContents, 'UTF-8')
                }
            })
        }
    }
}

There is literally no documentation of instantRunManifestOutputFile. The only Google search result I got was the Android Gradle Plugin source code. But then I also found a third potential manifest file property aaptFriendlyManifestOutputFile, which I don't know what it's about either...

这篇关于在Gradle任务processManifest.doLast中编辑AndroidManifest.xml从Android Studio运行应用程序时无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆