1 AndroidManifest用意
当用户启动的时候,Android应用系统没有一个简单地执行主入口,相反在清单的<application>标签下会发布应用程序可以完成的各种事件的相应入口。这些入口被分为四种不同的类型:活动、服务、接收器和内容提供器。如此这样做有两大好处:
1)应用程序在清单中静态的声明它们的入口,因此在安装时不需要执行任何程序代码,通过查看清单即可确定应用程序的顶层关系,无须保留关于应用程序的功能信息的独立数据库。这种去中心化的方法可以避免Windows的中心化注册表所导致的问题,使得系统更加健壮。
2)将应用程序分解为更细粒度的组件有助于实现支持应用程序间互操作和协作的设计目标。应用程序可以按照片段的形式发布特定的功能,其他应用程序可以直接或间接的利用这些功能。
2 应用清单概览
每个应用项目必须在项目源设置的根目录中加入 AndroidManifest.xml 文件(且必须使用此名称)。 清单文件会向 Android 构建工具、Android 操作系统和 Google Play 描述应用的基本信息。清单文件需声明以下内容:
- 应用的软件包名称,其通常与代码的命名空间相匹配。 构建项目时,Android 构建工具会使用此信息来确定代码实体的位置。 打包应用时,构建工具会使用 Gradle 构建文件中的应用 ID 来替换此值,而此 ID 则用作系统和 Google Play 上的唯一应用标识符。
- 应用的组件,包括所有 Activity、服务、广播接收器和内容提供程序。 每个组件都必须定义基本属性,例如其 Kotlin 或 Java 类的名称。 清单文件还能声明一些功能,例如其所能处理的设备配置,以及描述组件如何启动的 Intent 过滤器。
- 为访问系统或其他应用的受保护部分所需的权限。 如果其他应用想要访问此应用的内容,则清单文件还会声明其必须拥有的权限。
- 应用需要的硬件和软件功能,这些功能会影响哪些设备能够从 Google Play 安装应用。
3 文件功能
3.1 软件包名称和应用 ID
清单文件的根元素需包含应用软件包名称的属性。例如,以下代码段显示包含软件包名称 "com.example.myapp" 的 <manifest> 根元素:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
android:versionCode="1"
android:versionName="1.0" >
...
</manifest>
在将应用构建为最终的应用软件包 (APK) 时,Android构建工具会使用package属性完成两件事情:
它会将此名称用作应用所生成 R.java 类(用于访问应用资源)的命名空间。
示例:在上方的清单中,您可以在com.example.myapp.R处创建R类。它会使用此名称解析清单文件中声明的任何相关类名称。
示例:在上方的清单中,系统会将声明为 <activity android:name=".MainActivity"> 的Activity解析为 com.example.myapp.MainActivity。
因此,清单package属性中的名称应始终与项目中保存Activity和其他应用代码的基础软件包的名称相匹配。 当然,您可以在项目中加入其他子软件包,但此类文件必须使用package属性的命名空间导入R.java类。
但请注意,APK 编译完成后,package 属性还可表示应用的通用唯一应用ID。当构建工具根据package名称执行上述任务后,它们会将package值替换为项目 build.gradle 文件(用于 Android Studio 项目)中赋予applicationId属性的值。 package 属性的这一最终值必须是通用唯一值,因为这是能确保在系统和Google Play中识别应用的唯一方式。
3.2 应用组件
3.2.1 组件声明
对于在应用中创建的每个应用组件,您必须在清单文件中声明相应的 XML 元素:
- <activity> 用于 Activity 的每个子类。
- <service> 用于 Service 的每个子类。
- <receiver> 用于 BroadcastReceiver 的每个子类。
- <provider> 用于 ContentProvider 的每个子类。
如果您创建此类组件的任何子类,但未在清单文件中对其进行声明,则系统便无法启动该子类。例如,可对Activity子类进行如下声明:
<manifest ... >
<application ... >
<activity android:name="com.example.myapp.MainActivity" ... >
// <activity android:name=".MainActivity" ... >
</activity>
</application>
</manifest>
3.2.2 Intent 过滤器
应用的 Activity、服务和广播接收器均由Intent激活。Intent是由Intent对象定义的消息,用于描述要执行的操作,其中包括要执行操作的数据、应执行操作的组件类别以及其他相关说明。
当应用向系统发布Intent后,系统会根据每个应用清单文件中的Intent过滤器来查找可处理此Intent的应用组件。系统会启动匹配组件的实例,并向该组件传递Intent对象。如果有多个应用可以处理此Intent,则用户可选择使用哪个应用。
应用组件可包含任意数量的Intent过滤器(通过<intent-filter>元素定义),每个过滤器描述该组件的不同功能。
3.2.3 图标和标签
许多清单元素拥有icon和label属性,二者分别用于向对应应用组件的用户显示小图标和文本标签。
任何情况下,在父元素中设置的图标和标签都会成为所有子元素的默认icon和label值。例如,在<application>元素中设置的图标和标签即为每个应用组件(如所有 Activity)的默认图标和标签。
只要以实现Intent的选项形式呈现组件,系统便会向用户显示在该组件的<intent-filter>中设置的图标和标签。默认情况下,此图标继承自为父组件(<activity> 或 <application> 元素)声明的任何图标,但如果Intent过滤器提供唯一操作,且您希望该操作在选择器对话框中有更好的指示,则您可能需更改此图标。
3.3 权限
如要访问敏感用户数据(如联系人和短信)或某些系统功能(如相机和互联网访问),则 Android 应用必须请求相关权限。 每个权限均由唯一标签标识。 例如,如果应用需要发送短信,则必须在清单中添加以下代码行:
<manifest ... >
<uses-permission android:name="android.permission.SEND_SMS"/>
...
</manifest>
从Android 6.0(API级别23)开始,用户可以在运行时同意或拒绝某些应用权限。但是,无论您的应用支持哪个Android版本,您都必须使用清单中的<uses-permission>元素声明所有权限请求。授予应用权限后,该应用便能使用受保护的功能。否则,该应用在尝试访问这些功能时会失败。
应用也可使用权限保护自己的组件。 它可以使用Android定义的任何权限(如android.Manifest.permission中所列),或在其他应用中声明的权限。应用也可定义自己的权限,可通过<permission> 元素来声明新权限。
3.4 设备兼容性
清单文件也可用于声明应用所需的硬件或软件功能类型,以及应用兼容的设备类型。 Google Play商店不允许在未提供应用所需功能或系统版本的设备上安装应用。以下是一些最常见的此类标签:
- <uses-feature>
声明应用所需的硬件和软件功能。例如,如果您的应用无法在缺少罗盘传感器的设备上实现基础功能,则您可使用以下清单标记将罗盘传感器声明为必需功能:
<manifest ... >
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />
...
</manifest>
- <uses-sdk>
每个后续平台版本往往都会新增先前版本未提供的API。如要指明与应用兼容的最低版本,您的清单必须包含<uses-sdk>标签及其minSdkVersion属性。
但请注意,<uses-sdk>元素中的这些属性会被build.gradle文件中的相应属性覆盖。因此,如果您使用的是Android Studio,则必须在此处指定minSdkVersion和targetSdkVersion值:
android {
defaultConfig {
applicationId 'com.example.myapp'
// Defines the minimum API level required to run the app.
minSdkVersion 15
// Specifies the API level used to test the app.
targetSdkVersion 28
...
}
}
4 文件约定
此部分描述普遍适用于清单文件中所有元素和属性的约定和规则。
4.1 元素
只有<manifest>和<application>元素是必需的,二者必须且只能出现一次。大多数其他元素可以不出现或多次出现。但是,必须提供某些元素才能使清单文件发挥作用。
同一级别的元素通常不分先后顺序。例如,<activity>、<provider>和<service>元素可按任何顺序放置。这条规则有两个主要的例外情况:
- <activity-alias>元素必须跟在别名所指的<activity>之后。
- <application>元素必须是<manifest>元素内的最后一个元素。
4.2 属性
严格来说,所有属性都是可选的。 但是,必须指定某些属性才可让元素实现其目的。 对于真正可选的属性,参考文档会指定默认值。
除了根<manifest>元素的某些属性外,所有属性名称均以android:前缀开头。例如,android:alwaysRetainTaskState。由于该前缀是通用的,因此在按名称引用属性时,参考文档通常会将其忽略。
4.3 多个值
例如,Intent 过滤器可以列出多个操作:
<intent-filter ... >
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.INSERT" />
<action android:name="android.intent.action.DELETE" />
...
</intent-filter>
4.4 资源值
某些属性的值可以显示给用户,例如,Activity的标题或应用图标。这些属性的值可能因用户的语言或其他设备配置而异(例如根据设备的像素密度提供不同的图标大小),因此您应根据资源或主题设置值,而非将其硬编码到清单文件中。 随后,您可根据为不同设备配置提供的备用资源更改实际值。资源将通过以下格式表示为值:"@[package:]type/name"
- package
如果资源由您的应用提供,则您可以忽略软件包名称(其亦适用于资源由库依赖项提供的情况,因为库资源会合并到您的资源中)。当您想要使用Android框架中的资源时,其有效包名称是 android。 - type
type是资源类型(例如 string 或 drawable); - name
name是标识特定资源的名称。
示例代码如下所示:
<activity android:icon="@drawable/smallPic" ... >
注意:如要应用主题中定义的值,第一个字符必须是 ?,而非 @,例如:"?[package:]type/name"
4.4 字符串
如果属性值为字符串,则您必须使用双反斜杠 (\) 来转义字符,例如:使用 \n 表示换行符或使用 \uxxxx 表示 Unicode 字符。
5 清单元素参考
下表提供AndroidManifest.xml文件中所有有效元素的参考文档链接。
元素 | 说明 |
---|---|
<action> | 向Intent过滤器添加操作。 |
<activity> | 声明Activity组件。 |
<activity-alias> | 声明Activity的别名。 |
<application> | 应用的声明。 |
<category> | 向Intent过滤器添加类别名称。 |
<compatible-screens> | 指定与应用兼容的每个屏幕配置。 |
<data> | 向Intent过滤器添加数据规范。 |
<grant-uri-permission> | 指定父级内容提供程序有权访问的应用数据的子集。 |
<instrumentation> | 声明支持您监控应用与系统进行交互的Instrumentation类。 |
<intent-filter> | 指定 Activity、服务或广播接收器可以响应的 Intent 类型。 |
<manifest> | AndroidManifest.xml文件的根元素。 |
<meta-data> | 可以提供给父级组件的其他任意数据项的名称-值对。 |
<path-permission> | 定义内容提供程序中特定数据子集的路径和所需权限。 |
<permission> | 声明安全权限,可用于限制对此应用或其他应用的特定组件或功能的访问。 |
<permission-group> | 为相关权限的逻辑分组声明名称。 |
<permission-tree> | 声明权限树的基本名称。 |
<provider> | 声明内容提供程序组件。 |
<receiver> | 声明广播接收器组件。 |
<service> | 声明服务组件。 |
<supports-gl-texture> | 声明应用支持的一种GL纹理压缩格式。 |
<supports-screens> | 声明应用支持的屏幕尺寸,并为大于此尺寸的屏幕启用屏幕兼容模式。 |
<uses-configuration> | 指明应用要求的特定输入功能。 |
<uses-feature> | 声明应用使用的单个硬件或软件功能。 |
<uses-library> | 指定应用必须链接到的共享库。 |
<uses-permission> | 指定为使应用正常运行,用户必须授予的系统权限。 |
<uses-permission-sdk-23> | 指明应用需要特定权限,但仅当应用在运行Android 6.0(API级别23)或更高版本的设备上安装时才需要。 |
<uses-sdk> | 您可以通过整数形式的API级别,表示应用与一个或多个版本的Android平台的兼容性。 |
说明:元素具体使用,参看官方文档链接[2]
6 清单文件示例
以下XML文件为AndroidManifest.xml的一个简单示例,该示例为应用声明两个Activity。
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.example.myapp">
<!-- Beware that these values are overridden by the build.gradle file -->
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- This name is resolved to com.example.myapp.MainActivity
based upon the package attribute -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DisplayMessageActivity"
android:parentActivityName=".MainActivity" />
</application>
</manifest>
参考资料:
[1] 现代操作系统,
[2] App manifest file