android - 从 Android Studio 运行应用程序时,在 Gradle 任务 processManifest.doLast 中编辑 AndroidManifest.xml 无效

标签 android android-studio android-gradle-plugin android-manifest android-studio-2.0

我使用以下 Gradle 脚本在编译时对 AndroidManifest.xml 进行一些修改。在这个例子中我想注入(inject)一个 <meta-data>元素。代码基于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 同步或从命令行进行干净构建时,这按预期工作:可以从应用程序内部访问元数据。

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

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

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

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

请注意 doLast 中的任务每次都被执行:A println()打印任务中的内容并且中间 list 包含更改。

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

这里的问题在哪里?

我正在使用 Android Studio 2.0 和 Android Gradle 插件 2.0.0。

最佳答案

我发现它与 Android Studio 2.0 中引入的 Instant Run 功能有关。如果我将其关闭,一切都会按预期进行。但由于我想使用 Instant Run,所以我深入了解了一下。

事实是,启用 Instant Run 后,中间 AndroidManifest.xml 文件将位于另一个位置,即 /build/intermediates/bundles/myflavor/instant-run/。这意味着我实际上是在编辑错误的文件。其他 list 文件可通过属性 instantRunManifestOutputFile 访问,可以用来代替 manifestOutputFile

为了让它适用于所有用例,我检查两个临时 list 文件是否存在,如果存在则修改它们:

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 插件源代码。但后来我还发现了第三个潜在的 list 文件属性 aaptFriendlyManifestOutputFile,我也不知道它是关于什么的......

关于android - 从 Android Studio 运行应用程序时,在 Gradle 任务 processManifest.doLast 中编辑 AndroidManifest.xml 无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36874191/

相关文章:

java - 如何重复我的背景图像但使用不同的图像

android - 编译gradle文件中的问题

android - Android Studio Mac 快捷方式中的重构重命名变量不起作用

android - 一种产品口味的不同 native 库

android - Android Studio如何打包来自多个库项目的单个AAR?

android - Android 上的 Youtube 播放器 - 无限加载

android - Android 应用的 Google Analytics v3 中缺少跟踪 ID (&id) 参数

android - 在 Android 中下载一个或多个文件的最佳做法是什么...?

android - Atrix 4G和其他安卓手机在OpenGl渲染上有什么不同?

android - Android Studio 中缺少设备文件资源管理器