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

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

问题描述

我使用以下 Gradle 脚本在编译时对 AndroidManifest.xml 进行了一些修改.在这个例子中,我想注入一个 元素.代码基于这个答案.

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')
            }
        }
    }
}

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

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.

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

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.

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

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.

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

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..

重现这个最简单的方法是首先清理项目(在 Android Studio 中),这会导致清单被重新处理(如果出现语法错误,我会按预期失败),然后运行应用程序,即使使用无效的清单也能工作.

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.

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

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

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

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

问题出在哪里?

我使用的是带有 Android Gradle 插件 2.0.0 的 Android Studio 2.0.

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

推荐答案

我发现它与 Android Studio 2.0 中引入的 Instant Run 功能有关.如果我关闭它,一切都会按预期进行.但是因为我想使用 Instant Run,所以我深入挖掘了一点.

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.

问题是,启用 Instant Run 后,中间 AndroidManifest.xml 文件将位于另一个位置,即 /build/intermediates/bundles/myflavor/instant-run/.这意味着我有效地编辑了错误的文件.另一个清单文件可通过属性 instantRunManifestOutputFile 访问,该属性可用于代替 manifestOutputFile.

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')
                }
            })
        }
    }
}

实际上没有 instantRunManifestOutputFile 的文档.我得到的唯一谷歌搜索结果是 Android Gradle 插件源代码.但后来我还发现了第三个潜在的清单文件属性 aaptFriendlyManifestOutputFile,我也不知道它是关于什么的......

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...

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

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