Android Developer:合并清单文件

来源:互联网 发布:oracle数据库保存 编辑:程序博客网 时间:2024/05/22 00:35

使用Android Studio并且基于Gradle构建,每个App能在多个位置包含清单文件,例如在src/main文件夹下productFlavor、库、Android ARchive(AAR) bundles of Android Library项目,和第三方依赖。在构建过程中,包含在你的app中的多个AndroidMainfest.xml设置合并成一个,生成APK清单文件用于app的打包和发布。清单文件的设置基于清单优先级来合并,取决于清单文件的位置。从制定build variant清单文件的元素,属性,和子元素构建合并你的app清单文件。 

 

合并冲突规则 

------------------------------------------------------------------ 

合并的冲突发生在清单文件包含相同的清单元素,并且有不同的属性值,无法使用默认的合并规则解决的时候。Conflict markers和selectors也能定义自定义的合并规则,例如允许一个导入的库有一个minSdkVersion大于在其它更高优先级清单中定义的版本。 

 

清单合并优先级决定了哪个清单设置在合并冲突中保留,使用高优先级订单文件设置覆盖低优先级清单。下面的列表详细描述了在合并过程中,哪个清单设置的优先级最高: 

  • 最高优先级:buildType清单设置 

  • 高优先级:productFlavor清单设置 

  • 中优先级:app项目在src/main/目录下清单 

  • 低优先级:依赖和库清单设置 

清单冲突合并基于下面的合并规则在XML节点和属性级别被解决: 


清单合并规则例外: 

  • uses-feature android:required;和use-library android:required元素默认值为true,并且使用一个或者合并,这样任何要求的功能和库在成成的APK都被包含。 

  • 如果没有声明,<uses-sdk>元素,minSdkVersion和targetSdkVersion,默认的值为1。当合并冲突发生,更高优先级的清单文件值被使用; 

  • 导入一个包含minSdkVersion值高于app的src/main/清单文件,清单产生一个错误,除非overrideLibrary冲突记号被使用; 

注意:如果没有明确的声明,targetSdkVersion默认为minSdkVersion值。当没有元素在任何清单文件或者build.gradle文件中出现的时候,minSdkVersion默认为1。 

  • 当导入一个包含targetSdkVersion值低于app的src/main清单文件的库,清单合并过程明确授予权限并,并确保正确的导入库库函数。 

  • manifest元素仅仅合并孩子清单元素。 

  • intent-filter元素从不改变并且总是添加到合并的清单相同的父节点下。 

重要:在清单文件被合并后,构建过程使用build.gradle文件中的任何设置覆盖最终的清单设置。更多详情,请阅读Configure Gradle Builds。 

 

合并冲突标记和选择器 

------------------------------------------------------------------ 

清单标记和选择器通过制定冲突解决办法覆盖默认的规则。例如,使用冲突标识来合并一个库清单的minSdkVersion高于更高优先级清单,或者合并清单相同的Activity,但是不同的android:theme值。 

 

合并冲突标识 

一个合并冲突标识是一个在Android工具空间的指定元素,它定义了一个指定的冲突合并方案。创建一个冲突标识是为了避免使用默认合并规则没有解决的合并冲突错误。支持的合并冲突标识包括: 

merge 

    当没有合并规则冲突的时候合并属性。默认的合并动作。 

replace 

    使用高优先级的清单替代低优先级清单中的属性; 

strict 

merge-only 

    允许指定低优先级属性的合并动作; 

remove 

    删除合并后的清单指定的低级别元素; 

remove-All 

    删除合并后清单的相同节点类型的所有低优先级元素;  

     

默认情况下,清单的合并过程在节点级别应用merge冲突标识。所有声明的清单属性默认是strict合并策略。 

 

为了设置一个合并冲突标识,首先在AndroidManifest.xml文件中声明命名空间。然后在清单中输入合并冲突标识的一个指定的合并冲突动作。这个例子插入了replace标识来设置一个replace动作,来解决在android:icon和android:lable清单元素的冲突。 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.android.tests.flavorlib.app"    xmlns:tools="http://schemas.android.com/tools">     <application        android:icon="@drawable/icon"        android:label="@string/app_name"        tools:replace="icon, label">        ...  

标记属性 

冲突标识使用tools:node和tools:attr属性来在XML节点或者属性级别的冲突动作。 

 

tools:attr标识仅仅使用restrict,remove,和replace合并动作。多个tools:attr标识的值可以被应用到一个指定的元素。例如,使用tools:replace="icon,lable,theme"来提来更低的优先级icon,lable和theme属性。 

 

向清单文件中注入构建值 

----------------------------------------------------------------- 

清单文件合并也能使用清单占位符,从build.gradle文件向清单属性注入属性值。 

 

清单占位符使用这个语法${name}设置属性值,name是注入build.gradle属性,build.gradle文件使用manifestPlaceholders属性来定义占位符的值。 

注意:在app中未解析的占位符名称会导致构建失败。在库中未解析的占位符生成警告,并且将这个库导入一个app的时候必须解决。 

 

这个例子展示了清单占位符${applcationId}用于映射build.gradle的applicationID属性值到android:name属性值。 

注意:Android Studio为build.gradle applicationID值提供了一个默认的${applicationId}占位符,它不显示在构建文件中。当为库模块构建一个AAR(Android ARchive)包时,不需要在清单合并设置中提供一个自动的@{applicationID}占位符。相反,使用一个不同的占位符,例如@{libApplicationID},并为如果你想包括归档库的appliction Id,为它提供一个值。 

清单实体: 

<activity android:name=".Main">      <intent-filter>      <action android:name="${applicationId}.foo">          </action> </intent-filter> </activity> 
构建文件: 

android {    compileSdkVersion 22    buildToolsVersion "22.0.1"     productFlavors {        flavor1 {            applicationId = "com.mycompany.myapplication.productFlavor1"        } } 
合并清单值: 

<action android:name="com.mycompany.myapplication.productFlavor1.foo"> 
清单文件占位符和构建文件manifestPlaceholders属性能被用于注入其它清单文件值。对于applicationId依赖的属性,manifestPlaceholders属性明确的在build.gradle文件中声明。这个例子展示了清单占位符注入activityLabel值。 

Gradle build 文件: 

android {     defaultConfig {         manifestPlaceholders = [ activityLabel:"defaultName"]     }     productFlavors {         free {         }         pro {             manifestPlaceholders = [ activityLabel:"proName" ]         }     } 
构建文件: 

android {     defaultConfig {         manifestPlaceholders = [ activityLabel:"defaultName"]     }     productFlavors {         free {         }         pro {             manifestPlaceholders = [ activityLabel:"proName" ]         }     } 

在清单文件中的占位符: 

<activity android:name=".MainActivity" android:label="${activityLabel}" > 
注意:占位符的值支持部分值注入,例如android:authority="com.acme.${localApplicationId}.foo". 

 

通过Product Flavor组合并清单文件 

----------------------------------------------------------------- 

当使用GroupbleProductFlavor属性,任何在Product flavor组的清单文件的合并优先级取决于在构建文件中的排列顺序。清单文件合并的过程基于build variant的构建配置,为product flavor组创建一个单独合并清单文件。 

 

例如,如果一个build varian从各自的product flavor组ABI,Density,API和Prod参考了product flavors x86,mdpi,21,和paid,在build.gradle文件中以该顺序排列,然后清单文件以product flavors在构建文件中排列的顺序为优先级合并。 

 

为了说明这个例子,下面的标识展示了每个product flavor组列举了什么product flavor。这个product flavors和组的组合定义了build variant。 

Product Flavor Group 

Product Flavor 

ABI 

x86 

density 

mdpi 

API 

22 

prod 

paid 

清单合并顺序: 

  • prod-paid AndroidManifest.xml(低优先级)合并到API-22 AndroidManifest.xml 

  • API-22 AndroidManifest.xml合并到density-mpi AndroidManifest.xml 

  • density-mpi AndroidManifest.xml合并到ABI-x86 AndroidManifest.xml(高优先级) 

 

隐式权限 

----------------------------------------------------------------- 

导入一个支持隐式授予权限的Android运行的库,可能会自动往合并清单中添加这个权限。例如,如果一个targetSdkVersion为16的应用程序,导入一个targetSdkVersion为2的库,Andorid Studio添加WRITE_EXTERNAL_STORAGE权限,以确保跨SDK版本的兼容性。 

注意:更多现在的Android版本取代隐式的权限声明。 

Importing this library version 

Declares this permission in the manifest 

targetSdkVersion < 2 

WRITE_EXTERNAL_STORAGE 

targetSdkVersion < 4 

WRITE_EXTERNAL_STORAGE,READ_PHONE_STATE 

Declared WRITE_EXTERNAL_STORAGE 

READ_EXTERNAL_STORAGE 

targetSdkVersion < 16 and using the READ_CONTACTS permission 

READ_CALL_LOG 

targetSdkVersion < 16 and using WRITE_CONTACTS permission 

WRITE_CALL_LOG 

 

处理清单合并构建错误 

------------------------------------------------------------------ 

在构建过中,清单合并过程在模块的build/outputs/logs目录下mainfest-merge-<productFlavor>-report.txt文件中记录了每个合并事务。每个模块的build variants生成不同的日志文件。 

 

当一个清单合并构建错误发生的时候,构建过程在日志文件中记录了描述合并冲突错误消息。例如,在下面的清单之间导致了一个构建错误android:screenOrientation合并冲突。 

 

高优先级的清单声明: 

<activity    android:name="com.foo.bar.ActivityOne"    android:screenOrientation="portrait"    android:theme="@theme1"/> 
低优先级的清单声明: 

<activity    android:name="com.foo.bar.ActivityOne"    android:screenOrientation="landscape"/> 
错误日志: 

/project/app/src/main/AndroidManifest.xml:3:9 Error:  Attribute activity@screenOrientation value=(portrait) from AndroidManifest.xml:3:9  is also present at flavorlib:lib1:unspecified:3:18 value=(landscape)  Suggestion: add 'tools:replace="icon"' to  element at AndroidManifest.xml:1:5 to override 

1 0