合并多个清单文件

APK 文件只能包含一个 AndroidManifest.xml 文件,但 Android Studio 项目可以包含多个文件(通过主源集、构建变体和导入的库提供)。因此,在构建应用时,Gradle 构建会将所有清单文件合并到一个封装到 APK 的清单文件中。

清单合并工具通过遵循某些合并启发式算法,并遵守您通过特殊 XML 属性定义的合并首选项,来合并各个文件中的所有 XML 元素 。 本页介绍清单合并的工作方式以及如何应用合并首选项来解决合并冲突。

提示: 使用 Merged Manifest 视图预览合并清单的效果并找出冲突 错误。

合并优先级

合并工具根据每个清单文件的优先级将所有清单文件按顺序合并到一个文件中。 例如,如果您有 3 个清单文件,则会先将优先级最低的清单合并到优先级第 2 高的清单中,然后再将合并后的清单合并到优先级最高的清单中(如图 1 所示)。

图 1. 合并 3 个清单 文件(从优先级最低的文件(左)合并至优先级最高的文件(右))的流程

有 3 种基本的清单文件可以互相合并,它们的合并优先级如下(按优先级由高到低的顺序):

  1. 清单文件构建变体 如果您的变体有多个源集,则其清单优先级如下:

    • 构建变体清单(如 src/demoDebug/)
    • 构建类型清单(如src/debug/)
    • 产品定制清单(如 src/demo/)
      如果您使用的是定制维度,清单优先级将与每个维度在flavorDimensions 属性中的列示顺序(按优先级由高到低的顺序排列)对应。
  2. 应用模块的主清单文件

  3. 所包括库中的清单文件
    如果您有多个库,则其清单优先级与依赖顺序(库出现在 Gradle dependencies 块中的顺序)匹配。

例如,库清单合并至主清单,然后主清单合并至构建变体清单。

注:这些是对所有源集都相同的合并优先级,如使用源集构建 中所述。

重要说明: build.gradle 文件中的构建配置将替换合并清单文件中的任何对应属性。 例如,build.gradle
文件中的minSdkVersion 将替换 清单元素中的匹配属性。 为了避免混淆,您只需省去
元素并在 build.gradle 文件中定义这些属性。 For more details, see Configure Your
Build.

合并冲突启发式算法

合并工具可以在逻辑上将一个清单中的每个 XML 元素与另一个清单中的对应元素相匹配。 (有关匹配如何进行的详细信息,请参阅有关合并策略的附录)。

如果优先级较低的清单中的元素与优先级较高的清单中的任何元素均不匹配,则该元素将被添加至合并清单。 但是,如果有匹配元素,则合并工具会尝试将其中的所有属性合并到相同元素中。如果工具发现两个清单包含相同属性,但值不相同,则会出现合并冲突。

表 1 描述合并工具尝试将所有属性合并到同一元素时可能出现的结果。

表 1. 属性值的默认合并行为


但是,在某些情况下,合并工具会采取其他行为方式以避免合并冲突:

  • manifest 元素中的属性绝不合并—仅使用优先级最高的清单中的属性。
  • android:required 属性
  • uses-feature and uses-library 元素使用 OR 合并,因此如果出现冲突,系统将应用 “true” 并始终包括某个清单所需的功能或库。
  • uses-sdk 元素始终使用优先级较高的清单中的值,但以下情况除外:
    • 如果低优先级清单的minSdkVersion 值较高,除非您应用 overrideLibrary 合并规则。
    • 如果低优先级清单的targetSdkVersion值较低,合并工具将使用高优先级清单中的值,但也会添加任何必要的系统权限,以确保所导入的库继续正常工作(适用于较高的 Android 版本具有更多权限限制的情况)。如需了解有关此行为的详细信息,请参阅有关隐式系统权限的部分。
  • 绝不会在清单之间匹配
    intent-filter 元素。 每个元素都被视为唯一元素,并添加至合并清单中的常用父元素。
    对于属性之间的所有其他冲突,您将收到一则错误,并且必须通过在高优先级清单文件中添加特殊属性来指示合并工具如何解决此错误(请参阅下一节,其中介绍了有关合并规则标记的内容)。

不依赖于默认属性值。由于所有唯一属性都合并到相同元素中,如果高优先级清单实际上依赖于属性的默认值而不需要声明,则可能会导致意外结果。例如,如果高优先级清单不声明android:launchMode
属性,则会使用 “standard”
的默认值;但如果低优先级清单声明此属性具有其他值,该值将应用于合并清单(替代默认值)。因此,您应该按期望明确定义每个属性。(每个属性的默认值都会记录在
Manifest reference 中)。

合并规则标记

合并规则标记是一个 XML 属性,可用于表达您对关于如何解决合并冲突或删除不需要的元素和属性的首选项。 您可以对整个元素或只对元素中的特定属性应用标记。

合并两个清单文件时,合并工具会在高优先级清单文件中寻找这些标记。

所有标记均属于 Android tools 命名空间,因此您必须先在 元素中声明此命名空间,如下文所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"xmlns:tools="http://schemas.android.com/tools">

节点标记
要向整个 XML 元素(给定清单元素中的所有元素及其所有子标记)应用合并规则,请使用以下属性:

tools:node=”merge”
如果使用合并冲突启发式算法时没有冲突,则合并此标记中的所有属性以及所有嵌套元素。这是元素的默认行为。
低优先级清单:

<activity android:name=”com.example.ActivityOne”android:windowSoftInputMode=”stateUnchanged”><intent-filter><action android:name="android.intent.action.SEND" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

高优先级清单:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”tools:node="merge”>
</activity>

合并的清单结果:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”android:windowSoftInputMode=”stateUnchanged”><intent-filter><action android:name="android.intent.action.SEND" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

tools:node=”merge-only-attributes”
仅合并此标记中的属性,不合并嵌套元素。
Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:windowSoftInputMode=”stateUnchanged”><intent-filter><action android:name="android.intent.action.SEND" /><data android:type="image/*" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

高优先级清单:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”tools:node="merge-only-attributes”>
</activity>

合并的清单结果:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”android:windowSoftInputMode=”stateUnchanged”>
</activity>

tools:node=”remove”
从合并清单中删除此元素。 尽管您似乎应该仅删除此元素,但如果您发现合并清单中有不需要的元素,则必须使用此选项。该选项由不受您控制的低优先级清单(如导入的库)提供。
Low priority manifest:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”cow”android:value=”@string/moo”/><meta-data android:name=”duck”android:value=”@string/quack”/>
</activity-alias>

高优先级清单:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”cow”tools:node=”remove”/>
</activity-alias>

合并的清单结果:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”duck”android:value=”@string/quack”/>
</activity-alias>

tools:node=”removeAll”
与 tools:node=”remove” 类似,但它会删除与此元素类型相匹配的所有元素(同一父元素内)。
Low priority manifest:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”cow”android:value=”@string/moo”/><meta-data android:name=”duck”android:value=”@string/quack”/>
</activity-alias>

高优先级清单:

<activity-alias android:name=”com.example.alias”><meta-data tools:node=”removeAll”/>
</activity-alias>

合并的清单结果:

<activity-alias android:name=”com.example.alias”>
</activity-alias>

tools:node=”replace”
完全替换低优先级元素。 也就是说,如果低优先级清单中有匹配元素,请将其忽略并完全按照其在此清单中显示样子来使用该元素。
Low priority manifest:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”cow”android:value=”@string/moo”/><meta-data android:name=”duck”android:value=”@string/quack”/>
</activity-alias>

高优先级清单:

<activity-alias android:name=”com.example.alias”tools:node=”replace”><meta-data android:name=”fox”android:value=”@string/dingeringeding”/>
</activity-alias>

合并的清单结果:

<activity-alias android:name=”com.example.alias”><meta-data android:name=”fox”android:value=”@string/dingeringeding”/>
</activity-alias>

tools:node=”strict”
当此元素在低优先级清单中的情况与在高优先级清单中的情况不完全匹配时生成构建故障(除非已通过其他合并规则标记解决)。 这将替换合并冲突启发式算法。 例如,如果低优先级清单仅包括额外属性,则构建将会失败(而默认行为会向合并清单添加额外属性)。
Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:windowSoftInputMode=”stateUnchanged”><intent-filter><action android:name="android.intent.action.SEND" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

High priority manifest:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”tools:node="strict”>
</activity>

这会生成清单合并错误。两个清单元素在严格模式下也完全无法区分。 因此,您必须应用其他合并规则标记来解决这些差异。 (通常,这两个元素会完全地合并在一起,如以上 tools:node=”merge” 示例所示)。

属性标记

要改为仅向清单标记中的特定属性应用合并规则,请使用以下属性。每个属性接受一个或多个属性名称(包括属性命名空间),并以逗号分隔。

tools:remove=”attr, …”
从合并清单中删除指定属性。 尽管 您似乎可以仅删除这些属性,但如果 低优先级清单文件不包括这些 属性,而且您希望确保它们不纳入合并 清单,则必须使用此选项。
Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:windowSoftInputMode=”stateUnchanged”>

高优先级清单:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”tools:remove=”android:windowSoftInputMode”>

合并的清单结果:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”>

tools:replace=”attr, …”
将低优先级清单中的指定属性替换为 此清单中的属性。 换言之,始终保持 高优先级清单的值。
Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:theme=”@oldtheme”android:exported=”false”android:windowSoftInputMode=”stateUnchanged”>

高优先级清单:

<activity android:name=”com.example.ActivityOne”android:theme=”@newtheme”android:exported=”true”android:screenOrientation=”portrait”tools:replace=”android:theme,android:exported”>

合并的清单结果:

<activity android:name=”com.example.ActivityOne”android:theme=”@newtheme”android:exported=”true”android:screenOrientation=”portrait”android:windowSoftInputMode=”stateUnchanged”>

tools:strict=”attr, …”
当这些属性在低优先级清单中的情况与 在高优先级 清单中的不完全匹配时生成构建故障。 这是所有属性的默认行为,具有 合并冲突启发式算法中介绍的特殊行为的属性除外。
Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”landscape”>
</activity>

High priority manifest:

<activity android:name=”com.example.ActivityOne”android:screenOrientation=”portrait”tools:strict="android:screenOrientation”>
</activity>

这会生成清单合并错误。 您必须应用其他合并规则标记来解决冲突。 (请谨记:这是默认行为,因此如果您删除 tools:strict=”screenOrientation”,上面的示例将具有相同的结果。)

您也可以对一个元素应用多个标记,如下所示。

Low priority manifest:

<activity android:name=”com.example.ActivityOne”android:theme=”@oldtheme”android:exported=”false”android:allowTaskReparenting="true"android:windowSoftInputMode=”stateUnchanged”>

高优先级清单:

<activity android:name=”com.example.ActivityOne”android:theme=”@newtheme”android:exported=”true”android:screenOrientation=”portrait”tools:replace=”android:theme,android:exported”tools:remove=”android:windowSoftInputMode”>

Merged manifest result:

<activity android:name=”com.example.ActivityOne”android:theme=”@newtheme”android:exported=”true”android:allowTaskReparenting="true"android:screenOrientation=”portrait”>

标记选择器

如果您想仅对某个特定的导入库应用合并规则标记,请添加具有库包名称的 tools:selector 属性。

例如,对于下面的清单,仅在低优先级清单文件来自 com.example.lib1 库时应用 remove 合并规则。

<permission android:name="permissionOne"tools:node="remove"tools:selector="com.example.lib1">

如果低优先级清单来自其他源,系统将会忽略 remove 合并规则。

注: 如果您将此功能与其中一个属性标记配合使用,它将应用至标记中指定的所有选项。

对于所导入库,将替换

默认情况下,导入 minSdkVersion 值高于主清单文件的库时会出错,而且无法导入该库。 要使合并工具忽略此冲突并导入库,同时保持应用的低 minSdkVersion 值,请将 overrideLibrary 属性添加至 标记。属性值可以是一个或多个库包名称(以逗号分隔),指明可能替换主清单的 minSdkVersion 的库。

例如,如果应用的主清单按如下所示应用 overrideLibrary:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.app"xmlns:tools="http://schemas.android.com/tools"><uses-sdk android:targetSdkVersion="22" android:minSdkVersion="2"tools:overrideLibrary="com.example.lib1, com.example.lib2"/>


则一下清单可以合并,并且不会出现与 <uses-sdk> 标记相关的错误,合并清单将保留应用清单中的 minSdkVersion=”2”。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.lib1"><uses-sdk android:minSdkVersion="4" />

隐式系统权限

在最近的 Android 版本中,应用曾经可以自由访问的某些 Android API 已受 系统 权限限制。 为了避免中断预期会访问这些 API 的应用,最近的 Android 版本允许应用在无权限的情况下继续访问这些 API,前提是它们已将 targetSdkVersion 设置为低于添加限制的版本的值。此行为有效地向应用授予了隐式 权限,以允许访问 API。 因此,这可能会对具有不同 targetSdkVersion 值的合并清单产生以下影响。

如果低优先级清单文件提供隐式权限的 targetSdkVersion 值较低,而且高优先级清单没有相同的隐式权限(由于其 targetSdkVersion 等于或高于添加限制的版本),合并工具将向合并清单显式添加系统权限。

例如,如果您的应用将 targetSdkVersion 设置为 4 或更高值,并且导入了将 targetSdkVersion 设置为 3 或更低值的库,合并工具会将 WRITE_EXTERNAL_STORAGE 权限添加至合并清单。 表 2 列出了可以添加至合并清单的所有可能权限。

注:如果您将应用的 targetSdkVersion 设置为 23 或更高值,则必须在应用尝试访问受这些权限保护的 API 时为任何危险权限执行运行时权限请求。 如需获得更多指导,请参阅使用系统权限。

表 2. 合并工具可添加至合并清单的权限列表

会检查合并清单并查找冲突

即使在构建 APK 之前,也可以预览合并清单,具体方法是:在 Android Studio 中打开您的 AndroidManifest.xml 文件,然后单击编辑器底部的 Merged Manifest 选项卡。

Merged Manifest 视图在左侧显示合并清单的结果,在右侧显示每个合并清单文件的相关信息,如图 2 所示。从低优先级文件中合并的元素在左侧以不同颜色突出显示。 每种颜色的关键字在右侧的 Manifest Sources 下方指定。

图 2. Merged Manifest 视图

属于构建的一部分但不构成元素或属性的清单文件列在右侧的 Other Manifest Files 下方。

要查看有关元素来源的信息,请在左侧单击元素,详细信息将显示在右侧的 Merging Log 下方。

如果发生任何冲突,它们将显示在右侧的 Merging Errors 下方,并且包含有关如何使用 合并规则标记解决冲突的建议。 错误也会 打印在 Event Log 窗口(请选择 View > Tool Windows > Event Log)中。

如果您想要查看合并决策树的完整日志,则可以在模块的 build/outputs/logs/ 目录(名为 manifest-merger-buildVariant-report.txt)中查找该日志文件。

附录:合并策略

清单合并工具可以在逻辑上将某个清单中的每个 XML 元素与其他清单中的对应元素相匹配。 合并工具会使用“匹配关键字”匹配每个元素,匹配关键字可以是唯一的属性值(如 android:name或标记本身的天然唯一性(例如,只能有一个 元素)。 如果两个清单具有相同的 XML 元素,工具将采用三种合并策略中的一种来合并这两个元素:

合并
将所有非冲突属性合并到同一标记中, 然后按其各自的合并策略合并子元素。 如果任何属性 相互冲突,请使用合并规则标记将它们合并在一起。
仅合并子项
不整合或合并属性(仅保留 优先级最高的清单文件提供的属性)并按照其合并策略 合并子项。
保留
将元素“按原样”保留,然后将其添加至 合并文件中的常用父元素。 此策略仅在可接受相同元素的多个 声明时使用。
表 1 列出了每种元素类型、使用的合并策略类型以及用于确定两个清单之间的元素匹配的关键字。

表 3. 清单元素合并策略和 合并关键字

Merged Manifest官方文档相关推荐

  1. Spring Boot 官方文档学习(一)入门及使用

    Spring Boot 官方文档学习(一)入门及使用 个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问 ...

  2. android mvvm官方文档,MVVM: 这是一个android MVVM 框架,基于谷歌dataBinding技术实现

    MVVM 这是一个android MVVM 框架,基于谷歌dataBinding技术实现.dataBinding 实现的 V 和 VM的关联:使用IOC架构实现了 M 和 V的关联. 框架具有以下功能 ...

  3. [Linux Kernel] memory-barriers 内存屏蔽 官方文档

    文章目录 DISCLAIMER | 免责声明 CONTENTS | 目录 一.ABSTRACT MEMORY ACCESS MODEL | 抽象内存访问模型 1. DEVICE OPERATIONS ...

  4. Vue CLI 官方文档(一)@vue/cli、@vue/cli-service、插件和 Preset

    Vue CLI 官方文档(一)@vue/cli.@vue/cli-service.插件和 Preset 文章目录 Vue CLI 官方文档(一)@vue/cli.@vue/cli-service.插件 ...

  5. 官方文档-丰富你的数据

    对应7.16官方文档路径: Ingest pipelines » Enrich your data 官方地址如下: https://www.elastic.co/guide/en/elasticsea ...

  6. HarmonyOS(一) 快速开始学习鸿蒙开发,官方文档学习路线解析

    系列文章目录 HarmonyOS(一):快速开始学习鸿蒙开发,官方文档学习路线解析 HarmonyOS(二):应用开发环境搭建准备 HarmonyOS(三):创建你的第一个HelloWorld应用 文 ...

  7. Android官方文档之App Components(Activities)

    Activity是Android四大组件之首,本文将介绍Activity的含义.创建.启动.销毁.生命周期 等. 如需访问官方原文,您可以点击这个链接:<Activities> Activ ...

  8. chrome扩展官方文档(中文版)

    译者注 这里是 chrome 扩展官方文档 中文翻译版本 ,对应版本号「Manifest V3」.文章都是博主自个翻译校对的,方便大家学习. ⚠️ 再次说明!文章翻译的的 Manifest 版本为 V ...

  9. CDH6官方文档中文系列(2)----Cloudera安装指南(安装前)

    Cloudera安装指南 最近在学习cdh6的官方文档,网上也比较难找到中文的文档. 其实官方英文文档的阅读难度其实并不是很高,所以在这里在学习官方文档的过程中,把它翻译成中文,在翻译的过程中加深学习 ...

  10. chrome扩展官方文档(中文版)—— chrome 扩展的新功能

    传送门:chrome扩展官方文档(中文版) 原文地址:What's new in Chrome extensions Chrome扩展有什么新功能 发布于 2021 年 2 月 25 日,星期四 • ...

最新文章

  1. python学习费用-Python培训多少钱?学习Python技术成本高?
  2. Go嵌套并发实现EDM,附坑点分析#1
  3. 在数字图像处理中特征点是什么
  4. CentOS 网络设置修改
  5. 培训师 每小时多少钱_每个产品设计师需要了解的品牌知识
  6. .net core grpc consul 实现服务注册 服务发现 负载均衡(二)
  7. 史上最详细nodejs版本管理器nvm的安装与使用(附注意事项和优化方案)
  8. Spring基础——AOP
  9. fetch 不是xhr_fetch与XHR的区别与优势
  10. 大数据之-Hadoop3.x_MapReduce_WordCount案例环境准备---大数据之hadoop3.x工作笔记0088
  11. PostgreSql之在group by查询下拼接列字符串
  12. Ubuntu18.04 下面安装docker
  13. 阿里五年晋升三次,选择真的大于努力?
  14. Winform 下拉框绑定问题
  15. 微电子计算机是信息技术的,信息技术说第三十五说,计算机微电子技术
  16. vue3.0脚手架搭建(vscode)
  17. 使用am instrument验证CTS问题
  18. Android工具类篇 清理APP应用缓存
  19. 坚持不懈2 android游戏,坚持不懈的赛跑者
  20. 精通CSS.DIV网页样式与布局(二)—— 段落

热门文章

  1. python编写程序计算梯形面积公式_肿么用c语言编写程序梯形面积
  2. 人脸美化随笔1——研究方向总结
  3. CentOS 美化记录
  4. 北京大学肖臻老师《区块链技术与应用》公开课笔记:以太坊原理(三):智能合约
  5. java字节数计算_计算一个Java对象占用字节数的方法
  6. 唐福林《新浪微博开放平台中的Redis实践》演讲视频
  7. Typora结合LightBox放大查看图片
  8. SwiftUI实战教程 第三章 土豆List
  9. 第七周 项目4 - 队列数组
  10. 当国际贸易撞上AI,会产生怎样的化学反应?