合并多个清单文件
Merge multiple manifest files
APK 文件只能包含一个 AndroidManifest.xml 文件,但 Android Studio 项目 may contain several provided by the main source set, build variants, and imported libraries。因此,在构建应用时,Gradle 构建会 merges all manifest files into a single manifest file that‘s packaged into your APK。
清单合并工具通过遵循某些合并启发式算法[merge heuristics],并遵守您通过特殊 XML 属性定义的合并首选项,来合并各个文件中的所有 XML 元素 。 本页介绍清单合并的工作方式以及如何应用合并首选项来解决合并冲突。
提示: 使用 Merged Manifest view 预览合并清单的效果并找出冲突错误。
1
1
1
提示: 使用 Merged Manifest view 预览合并清单的效果并找出冲突错误。
合并优先级
Merge priorities
合并工具根据每个清单文件的优先级将所有清单文件按顺序合并到一个文件中。 例如,如果您有 3 个清单文件,则会先将优先级最低的清单合并到优先级第 2 高的清单中,然后再将合并后的清单合并到优先级最高的清单中(如图 1 所示)。
图 1. 合并 3 个清单 文件(从优先级最低的文件(左)合并至优先级最高的文件(右))的流程
有 3 种基本的清单文件可以互相合并,它们的合并优先级如下(按优先级由高到低的顺序):
- 1、Manifest file for your build variant
- 如果您的变体有多个源集,则其清单优先级如下:
- Build variant manifest (such as src/demoDebug/)
- Build type manifest (such as src/debug/)
- Product flavor manifest (such as src/demo/)
- 如果您使用的是 flavor dimensions,清单优先级将与每个维度在 flavorDimensions 属性中的列示顺序(按优先级由高到低的顺序排列)对应。
- 2、Main manifest file for the app module
- 3、Manifest file from an included library
- 如果您有多个库,则其清单优先级与依赖顺序(库出现在 dependencies 块中的顺序)匹配。
For example, a library manifest is merged into the main manifest, then the main manifest is merged into the build variant manifest.
重要说明: build.gradle 文件中的构建配置将替换合并清单文件中的任何对应属性。 例如,build.gradle 文件中的minSdkVersion 将替换<uses-sdk> 清单元素中的匹配属性。为了避免混淆,您只需省去 <uses-sdk> 元素并在 build.gradle 文件中定义这些属性。For more details, see Configure Your Build.
1
1
1
重要说明: build.gradle 文件中的构建配置将替换合并清单文件中的任何对应属性。 例如,build.gradle 文件中的minSdkVersion 将替换<uses-sdk> 清单元素中的匹配属性。为了避免混淆,您只需省去 <uses-sdk> 元素并在 build.gradle 文件中定义这些属性。For more details, see Configure Your Build.
合并冲突启发式算法
Merge conflict heuristics
合并工具可以在逻辑上将一个清单中的每个 XML 元素与另一个清单中的对应元素相匹配。
如果优先级较低的清单中的元素与优先级较高的清单中的任何元素均不匹配,则该元素将被添加至合并清单。 但是,如果有匹配元素,则合并工具会尝试将其中的所有属性合并到相同元素中。如果工具发现两个清单包含相同属性,但值不相同,则会出现合并冲突。
下表 1 描述了合并工具尝试将所有属性合并到同一元素时可能出现的结果。
High priority attribute |
Low priority attribute |
Attribute‘s merged result |
No value | No value | No value (use default value) |
Value B | Value B | |
Value A | No value | Value A |
Value A | Value A | |
Value B | Conflict error—you must add a merge rule marker |
但是,在某些情况下,合并工具会采取其他行为方式以避免合并冲突:
- <manifest> 元素中的属性绝不合并—仅使用优先级最高的清单中的属性。
- <uses-feature> and <uses-library> 元素中的 android:required 属性使用 OR 合并,因此如果出现冲突,系统将应用 "true" ,并且 the feature or library required by one manifest is always included。
<uses-feature
android:name="android.hardware.camera"
android:required="false"/>
3
3
1
<uses-feature
2
android:name="android.hardware.camera"
3
android:required="false"/>
- <uses-sdk> 元素始终使用优先级较高的清单中的值,但以下情况除外:
- 如果低优先级清单的 minSdkVersion 值较高,an error occurs unless you apply the overrideLibrary merge rule。
- 如果低优先级清单的 targetSdkVersion 值较低,合并工具将使用高优先级清单中的值,但也会添加任何必要的系统权限,以确保所导入的库继续正常工作(适用于较高的 Android 版本具有更多权限限制的情况)。 如需了解有关此行为的详细信息,请参阅有关隐式系统权限[implicit system permissions]的部分。
- <intent-filter> 元素绝不会在清单之间匹配。Each is treated as unique and is added to the common parent element in the merged manifest.
对于属性之间的所有其他冲突,您将收到一则错误,并且必须通过在高优先级清单文件中添加特殊属性来指示合并工具如何解决此错误。
Do not depend on default attribute values.
由于所有 unique attributes 都合并到同一元素中,如果高优先级清单实际上依赖于属性的默认值而不需要声明,则可能会导致意外结果。
例如,如果高优先级清单不声明 android:launchMode 属性,则会使用 "standard" 的默认值;但如果低优先级清单声明此属性具有其他值,该值将应用于合并清单(替代默认值)。
因此,您应该按期望明确定义每个属性。(每个属性的默认值都会记录在 Manifest reference 中)。
4
4
1
Do not depend on default attribute values.
2
由于所有 unique attributes 都合并到同一元素中,如果高优先级清单实际上依赖于属性的默认值而不需要声明,则可能会导致意外结果。
3
例如,如果高优先级清单不声明 android:launchMode 属性,则会使用 "standard" 的默认值;但如果低优先级清单声明此属性具有其他值,该值将应用于合并清单(替代默认值)。
4
因此,您应该按期望明确定义每个属性。(每个属性的默认值都会记录在 Manifest reference 中)。
合并规则的标记
Merge rule markers
合并规则标记是一个 XML 属性,可用于表达您对关于如何解决合并冲突或删除不需要的元素和属性的首选项。 您可以对整个元素或只对元素中的特定属性应用标记。
合并两个清单文件时,合并工具会在高优先级清单文件中寻找这些标记。
所有标记均属于 Android tools 命名空间,因此您必须先在 <manifest> 元素中声明此命名空间,如下文所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
xmlns:tools="http://schemas.android.com/tools">
3
3
1
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
package="com.example.myapp"
3
xmlns:tools="http://schemas.android.com/tools">
节点标记 Node markers
向整个 XML 元素(给定清单元素中的所有元素及其所有子标记)应用合并规则
merge
如果使用合并冲突启发式算法时没有冲突,则合并此标记中的所有属性以及所有嵌套元素。This is the default behavior for elements.
merge-only-attributes
仅合并此标记中的属性,不合并嵌套元素。
低优先级清单:
<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>
8
8
1
<activity android:name=”com.example.ActivityOne”
2
android:windowSoftInputMode=”stateUnchanged”>
3
<intent-filter>
4
<action android:name="android.intent.action.SEND"/>
5
<data android:type="image/*" />
6
<category android:name="android.intent.category.DEFAULT"/>
7
</intent-filter>
8
</activity>
高优先级清单:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
tools:node="merge-only-attributes”/>
3
3
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”
3
tools:node="merge-only-attributes”/>
合并的清单结果:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
android:windowSoftInputMode=”stateUnchanged”/>
3
3
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”
3
android:windowSoftInputMode=”stateUnchanged”/>
remove
从合并清单中删除此元素。Although it seems like you should instead just delete this element, using this is necessary when you discover an element in your merged manifest that you don‘t need, and it was provided by a lower-priority manifest file that‘s out of your control (such as an imported library).
低优先级清单:
<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>
6
6
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”cow”
3
android:value=”@string/moo”/>
4
<meta-data android:name=”duck”
5
android:value=”@string/quack”/>
6
</activity-alias>
高优先级清单:
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”cow”
tools:node=”remove”/>
</activity-alias>
4
4
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”cow”
3
tools:node=”remove”/>
4
</activity-alias>
合并的清单结果:
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”duck”
android:value=”@string/quack”/>
</activity-alias>
4
4
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”duck”
3
android:value=”@string/quack”/>
4
</activity-alias>
removeAll
与 tools:node="remove" 类似,但它会删除同一父元素内与此元素类型相匹配的所有元素[all elements matching this element type]。
低优先级清单:
<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>
6
6
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”cow”
3
android:value=”@string/moo”/>
4
<meta-data android:name=”duck”
5
android:value=”@string/quack”/>
6
</activity-alias>
高优先级清单:
<activity-alias android:name=”com.example.alias”>
<meta-data tools:node=”removeAll”/>
</activity-alias>
3
3
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data tools:node=”removeAll”/>
3
</activity-alias>
合并的清单结果:
<activity-alias android:name=”com.example.alias”/>
1
1
1
<activity-alias android:name=”com.example.alias”/>
replace
完全替换低优先级元素。也就是说,if there is a matching element in the lower-priority manifest, ignore it and use this element exactly as it appears in this 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>
6
6
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”cow”
3
android:value=”@string/moo”/>
4
<meta-data android:name=”duck”
5
android:value=”@string/quack”/>
6
</activity-alias>
高优先级清单:
<activity-alias android:name=”com.example.alias”
tools:node=”replace”>
<meta-data android:name=”fox”
android:value=”@string/dingeringeding”/>
</activity-alias>
5
5
1
<activity-alias android:name=”com.example.alias”
2
tools:node=”replace”>
3
<meta-data android:name=”fox”
4
android:value=”@string/dingeringeding”/>
5
</activity-alias>
合并的清单结果:
<activity-alias android:name=”com.example.alias”>
<meta-data android:name=”fox”
android:value=”@string/dingeringeding”/>
</activity-alias>
4
4
1
<activity-alias android:name=”com.example.alias”>
2
<meta-data android:name=”fox”
3
android:value=”@string/dingeringeding”/>
4
</activity-alias>
strict
当此【元素】在低优先级清单中的情况与在高优先级清单中的情况不完全匹配[does not exactly match]时生成构建故障(除非已通过其他合并规则标记解决)。 这将 overrides 合并冲突启发式算法。 例如,如果低优先级清单仅包括 an extra attribute,则构建将会失败(而默认行为会向合并清单添加额外属性)。
低优先级清单:
<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>
7
7
1
<activity android:name=”com.example.ActivityOne”
2
android:windowSoftInputMode=”stateUnchanged”>
3
<intent-filter>
4
<action android:name="android.intent.action.SEND"/>
5
<category android:name="android.intent.category.DEFAULT"/>
6
</intent-filter>
7
</activity>
高优先级清单:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
tools:node="strict”/>
3
3
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”
3
tools:node="strict”/>
This creates a manifest merge error. 两个清单元素在严格模式下 cannot differ at all。 因此,您必须应用其他合并规则标记来解决这些差异。(通常,这两个元素会完全地合并在一起,如以上 tools:node="merge" 示例所示)。
属性标记 Attribute markers
要改为仅向清单标记中的特定属性[specific attributes]应用合并规则,请使用属性标记。每个属性接受一个或多个属性名称(包括属性命名空间),并以逗号分隔。
remove
从合并清单中删除指定属性。 Although it seems like you could instead just delete these attributes, it‘s necessary to use this when the lower-priority manifest file does include these attributes and you want to ensure they do not go into the merged manifest.
低优先级清单:
<activity android:name=”com.example.ActivityOne”
android:windowSoftInputMode=”stateUnchanged”/>
2
2
1
<activity android:name=”com.example.ActivityOne”
2
android:windowSoftInputMode=”stateUnchanged”/>
高优先级清单:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
tools:remove=”android:windowSoftInputMode”/>
3
3
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”
3
tools:remove=”android:windowSoftInputMode”/>
合并的清单结果:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”/>
2
2
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”/>
replace
将低优先级清单中的指定属性替换为 此清单中的属性。 换言之,始终保持 高优先级清单的值。
低优先级清单:
<activity android:name=”com.example.ActivityOne”
android:theme=”@oldtheme”
android:exported=”false”
android:windowSoftInputMode=”stateUnchanged”>
4
4
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@oldtheme”
3
android:exported=”false”
4
android:windowSoftInputMode=”stateUnchanged”>
高优先级清单:
<activity android:name=”com.example.ActivityOne”
android:theme=”@newtheme”
android:exported=”true”
android:screenOrientation=”portrait”
tools:replace=”android:theme,android:exported”>
5
5
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@newtheme”
3
android:exported=”true”
4
android:screenOrientation=”portrait”
5
tools:replace=”android:theme,android:exported”>
合并的清单结果:
<activity android:name=”com.example.ActivityOne”
android:theme=”@newtheme”
android:exported=”true”
android:screenOrientation=”portrait”
android:windowSoftInputMode=”stateUnchanged”>
5
5
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@newtheme”
3
android:exported=”true”
4
android:screenOrientation=”portrait”
5
android:windowSoftInputMode=”stateUnchanged”>
strict
当这些【属性】在低优先级清单中的情况与 在高优先级 清单中的不完全匹配时生成构建故障。This is the default behavior for all attributes, except for those with special behaviors as described in the merge conflict heuristics.
低优先级清单:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”landscape”/>
2
2
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”landscape”/>
高优先级清单:
<activity android:name=”com.example.ActivityOne”
android:screenOrientation=”portrait”
tools:strict="android:screenOrientation”/>
3
3
1
<activity android:name=”com.example.ActivityOne”
2
android:screenOrientation=”portrait”
3
tools:strict="android:screenOrientation”/>
This creates a manifest merge error. 您必须应用其他合并规则标记来解决冲突。Remember: This is the default behavior, so the above example has the same result if you remove tools:strict="screenOrientation"
同时使用多个标记
您也可以对一个元素同时应用多个标记,如下所示。
低优先级清单:
<activity android:name=”com.example.ActivityOne”
android:theme=”@oldtheme”
android:exported=”false”
android:allowTaskReparenting="true"
android:windowSoftInputMode=”stateUnchanged”>
5
5
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@oldtheme”
3
android:exported=”false”
4
android:allowTaskReparenting="true"
5
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”>
6
6
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@newtheme”
3
android:exported=”true”
4
android:screenOrientation=”portrait”
5
tools:replace=”android:theme,android:exported”
6
tools:remove=”android:windowSoftInputMode”>
合并的清单结果:
<activity android:name=”com.example.ActivityOne”
android:theme=”@newtheme”
android:exported=”true”
android:allowTaskReparenting="true"
android:screenOrientation=”portrait”>
5
5
1
<activity android:name=”com.example.ActivityOne”
2
android:theme=”@newtheme”
3
android:exported=”true”
4
android:allowTaskReparenting="true"
5
android:screenOrientation=”portrait”>
标记选择器 Marker selector
如果您想仅对某个特定的导入库应用合并规则标记,请添加具有库包名称的 tools:selector 属性。
例如,对于下面的清单,仅在低优先级清单文件来自 com.example.lib1 库时应用 remove 合并规则,如果低优先级清单来自其他源,系统将会忽略 remove 合并规则。
<permission android:name="permissionOne"
tools:node="remove"
tools:selector="com.example.lib1">
3
3
1
<permission android:name="permissionOne"
2
tools:node="remove"
3
tools:selector="com.example.lib1">
注:If you use this with one of the attribute markers, then it applies to all attributes specified in the marker.
overrideLibrary
Override <uses-sdk> for imported libraries,替换所导入库的 <uses-sdk>
默认情况下,导入 minSdkVersion 值高于主清单文件的库时会出错,而且无法导入该库。 要使合并工具忽略此冲突并导入库,同时保持应用的低 minSdkVersion 值,请将 overrideLibrary 属性添加至 <uses-sdk> 标记。属性值可以是一个或多个库包名称(以逗号分隔),指明可能替换主清单的 minSdkVersion 的库。
例如,如果应用的主清单按如下所示应用 overrideLibrary:
<uses-sdk android:targetSdkVersion="22"
android:minSdkVersion="2"
tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
3
3
1
<uses-sdk android:targetSdkVersion="22"
2
android:minSdkVersion="2"
3
tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
则下面这个清单(来自com.example.lib1)可以合并,并且不会出现与 <uses-sdk> 标记相关的错误,且合并清单将保留应用清单中的 minSdkVersion="2"。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lib1">
<uses-sdk android:minSdkVersion="4"/>
...
4
4
1
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
package="com.example.lib1">
3
<uses-sdk android:minSdkVersion="4"/>
4
...
隐式系统权限
Implicit system permissions
在最近的 Android 版本中,应用曾经可以自由访问的某些 Android API 已受系统权限限制。To avoid breaking apps that expect access to these APIs,最近的 Android 版本允许应用在无权限的情况下继续访问这些 API,前提是它们已将 targetSdkVersion 设置为低于添加限制的版本的值。此行为有效地向应用授予了隐式 权限,以允许访问 API。因此,这可能会对具有不同 targetSdkVersion 值的合并清单产生以下影响。
如果低优先级清单文件提供隐式权限的 targetSdkVersion 值较低,而且高优先级清单没有相同的隐式权限(由于其 targetSdkVersion 等于或高于添加限制的版本),合并工具将向合并清单显式添加系统权限。
例如,如果您的应用将 targetSdkVersion 设置为 4 或更高值,并且导入了将 targetSdkVersion 设置为 3 或更低值的库,合并工具会将 WRITE_EXTERNAL_STORAGE 权限添加至合并清单。 表 2 列出了可以添加至合并清单的所有可能权限。
注:如果您将应用的 targetSdkVersion 设置为 23 或更高值,则必须在应用尝试访问受这些权限保护的 API 时为任何危险权限执行运行时权限请求。 如需获得更多指导,请参阅使用系统权限。
1
1
1
注:如果您将应用的 targetSdkVersion 设置为 23 或更高值,则必须在应用尝试访问受这些权限保护的 API 时为任何危险权限执行运行时权限请求。 如需获得更多指导,请参阅使用系统权限。
表 2. 合并工具可添加至合并清单的权限列表
Lower-priority manifest declares |
Permissions added to the merged manifest |
targetSdkVersion is 3 or lower |
WRITE_EXTERNAL_STORAGE, READ_PHONE_STATE |
targetSdkVersion is 15 or lower and using READ_CONTACTS |
READ_CALL_LOG |
targetSdkVersion is 15 or lower and using WRITE_CONTACTS |
WRITE_CALL_LOG |
检查合并清单并查找冲突
Inspect the merged manifest and find conflicts
即使在构建 APK 之前,也可以预览合并清单,具体方法是:在 Android Studio 中打开您的 AndroidManifest.xml 文件,然后单击编辑器底部的 Merged Manifest 选项卡。
Merged Manifest 视图在左侧显示合并清单的结果,在右侧显示每个合并清单文件的相关信息。
从低优先级文件中合并的元素在左侧以不同颜色突出显示,每种颜色的关键字在右侧的 Manifest Sources 下方指定。
属于构建的一部分但不构成元素或属性的清单文件列在右侧的 Other Manifest Files 下方。
要查看有关元素来源的信息,请在左侧单击元素,详细信息将显示在右侧的 Merging Log 下方。
如果发生任何冲突,它们将显示在右侧的 Merging Errors 下方,并且包含有关如何使用合并规则标记解决冲突的建议。错误也会打印在 Event Log 窗口中(请选择 View > Tool Windows > Event Log)。
如果您想要查看合并决策树的完整日志,则可以在【各个模块】的 build/outputs/logs/manifest-merger-buildVariant-report.txt 中查找该日志文件。
附录:合并策略
Appendix: Merge policies
清单合并工具可以在逻辑上[logically]将某个清单中的 every XML element 与其他清单中的对应元素[corresponding element]相匹配。 合并工具会使用“匹配关键字”[match key]匹配每个元素,匹配关键字可以是唯一的属性值(如 android:name)或标记本身的天然唯一性[the natural uniqueness of the tag itself](例如,只能有一个 <supports-screen> 元素)。 如果两个清单具有相同的 XML 元素,工具将采用三种合并策略中的一种来合并这两个元素:
- 合并[Merge]:将所有非冲突属性合并到同一标记中[Combine all non-conflicting attributes into the same tag], 然后按其各自的合并策略合并子元素[merge child elements according to their respective merging policy]。 如果任何属性 相互冲突,请使用合并规则标记将它们合并在一起。
- 仅合并子项[Merge children only]:不整合或合并属性[Do not combine or merge the attributes](仅保留优先级最高的清单文件提供的属性),并按照其合并策略 合并子项。
- 保留[Keep]:将元素“按原样”保留[Leave the element "as is"] ,然后将其添加至合并文件中的同一父元素[add it to the common parent element in the merged file]。此策略仅在可接受相同元素的多个 声明时使用[it is acceptable for there to be several declarations of the same element]。
表 3. 清单元素合并策略和合并关键字[Manifest element merge policies and match keys]
元素 | 合并策略 | 合并关键字 |
<action> | 合并 | android:name 属性 |
<activity> | 合并 | android:name 属性 |
<application> | 合并 | 每个 <manifest> 仅一个 |
<category> | 合并 | android:name 属性 |
<data> | 合并 | 每个 <intent-filter> 仅 1 个 |
<grant-uri-permission> | 合并 | 每个 <provider> 仅 1 个 |
<instrumentation> | 合并 | android:name 属性 |
<intent-filter> | 保留 | 不匹配;允许父元素内的多个声明 |
<manifest> | 合并 | 每个文件仅 1 个 |
<meta-data> | 合并 | android:name 属性 |
<path-permission> | 合并 | 每个 <provider> 仅 1 个 |
<permission-group> | 合并 | android:name 属性 |
<permission> | 合并 | android:name 属性 |
<permission-tree> | 合并 | android:name 属性 |
<provider> | 合并 | android:name 属性 |
<receiver> | 合并 | android:name 属性 |
<screen> | 合并 | android:screenSize 属性 |
<service> | 合并 | android:name 属性 |
<supports-gl-texture> | 合并 | android:name 属性 |
<supports-screen> | 合并 | 每个 <manifest> 仅 1 个 |
<uses-configuration> | 合并 | 每个 <manifest> 仅 1 个 |
<uses-feature> | 合并 | android:name 属性(如果不存在,则使用 android:glEsVersion 属性) |
<uses-library> | 合并 | android:name 属性 |
<uses-permission> | 合并 | android:name 属性 |
<uses-sdk> | 合并 | 每个 <manifest> 仅 1 个 |
自定义元素 | 合并 | 无匹配;合并工具不了解这些信息,因此它们始终 包括在合并清单中 |
2018-7-24
原文地址:https://www.cnblogs.com/baiqiantao/p/9363208.html