每个应用项目都必须在项目源代码集的根目录下有一个AdnroidManifest.xml
文件。在 Android 系统可以启动应用程序组件之前,系统必须通过读取应用程序的清单文件AndroidManifest.xml
来知道该组件存在。您的应用程序在此文件中声明了其所有组件。
除了声明应用程序的组件外,清单还做了许多事情,例如:
- 标识应用程序所需的任何用户权限,例如互联网访问或对用户联系人的读取权限。
- 根据应用程序使用的 API,声明应用程序所需的最低 API 级别。
- 声明应用程序使用或要求的硬件和软件功能,如摄像头、蓝牙服务或多点触控屏幕。
- 声明应用程序需要链接的 API 库(Android 框架 API 除外),如谷歌地图库。
1 声明组件
清单的主要任务是向系统通知应用程序的组件。对于在应用中创建的每个组件,可以在清单文件中声明一个相应的 XML 元素:
- 为
Activity
的每个子类声明<activity>
。 - 为
Service
的每个子类声明<service>
。 - 为
BroadcastReceiver
的每个子类声明<receiver>
。 - 为
ContentProvider
的每个子类声明<provider>
。
如果将上述任一组件加入子类而未在清单文件中声明该组件,则系统无法启动该组件。但是,广播接收器可以在清单中声明,也可以在代码中动态创建为BroadcastReceiver
对象,并通过调用registerReceiver()
向系统注册。
使用完整的软件包标识指定带有name
属性的子类的名称。例如,按如下方式声明Activity
的子类:
<manifest ... >
<application ... >
<activity android:name="com.example.myapp.MainActivity" ... >
</activity>
</application>
</manifest>
不过,如果name
值中的第一个字符是一个句点,则来自模块级build.gradle
文件的namespace
属性的应用的命名空间会作为该名称的前缀。例如,如果命名空间为"com.example.myapp"
,则以下 activity 名称将解析为com.example.myapp.MainActivity
:
<manifest ... >
<application ... >
<activity android:name=".MainActivity" ... >
...
</activity>
</application>
</manifest>
如果某些应用组件位于子软件包中(如在com.example.myapp.purchases
中),则name
值必须添加缺少的子软件包名称(如".purchases.PayActivity"
)或使用完全限定的软件包名称。
2 声明组件功能
2.1 intent 过滤器
您可以使用Intent
激活活动、服务和广播接收器。intent 描述了要执行的操作,包括作为操作对象的数据、应执行操作的组件类别,以及其他说明。
您可以通过在意图中使用组件类名显式命名目标组件来实现这一点。您还可以使用隐式意图,它描述了要执行的操作类型,以及(可选)要对其执行操作的数据。隐式意图允许系统在设备上找到可以执行操作的组件并启动它。如果有多个组件可以执行意图描述的操作,用户可以选择使用哪个组件。
当应用向系统发出某个 intent 时,系统会根据每个应用的清单文件中的 intent 过滤器声明来查找可以处理该 intent 的应用组件。系统会启动符合条件的组件的实例,并将Intent
对象传递给该组件。如果多个应用可以处理相应的 intent,则用户可以选择要使用哪个应用。
系统通过将接收到的意图与设备上其他应用程序的清单文件中提供的意图过滤器进行比较来识别可以响应意图的组件。
一个应用组件可以具有任意多个 intent 过滤器(使用<intent-filter>
元素定义),每个 intent 过滤器描述该组件的不同功能。
当您在应用程序的清单中声明活动时,您可以选择包含声明活动功能的意图过滤器,以便它可以响应其他应用程序的意图。您可以通过添加一个<intent-filter>
元素作为组件声明元素的子元素来实现这一点。
例如,如果你构建了一个带有撰写新电子邮件活动的电子邮件应用程序,你可以声明一个意图过滤器来响应“发送”意图以发送新电子邮件,如下例所示:
<manifest ... >
...
<application ... >
<activity android:name="com.example.project.ComposeEmailActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:type="*/*" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
如果另一个应用程序使用ACTION_SEND
操作创建意图并将其传递给startActivity()
,系统可能会启动您的活动,以便用户起草和发送电子邮件。
3 权限
Android 应用必须请求权限才能访问敏感的用户数据(如联系人和短信)或某些系统功能(如相机和互联网接入)。每种权限都由唯一的标签进行标识。例如,需要发送短信的应用必须在清单中添加以下代码行:
<manifest ... >
<uses-permission android:name="android.permission.SEND_SMS"/>
...
</manifest>
用户可以在运行时批准或拒绝某些应用权限。用户必须在清单文件中使用<uses-permission>
元素声明所有权限请求。如果向应用授予了相应的权限,应用便可以使用受保护的功能。否则,应用在尝试使用这些功能时会失败。
应用也可以利用权限来保护它自己的组件。它可以使用由 Android 定义的任何权限(如android.Manifest.permission
中所列),也可以使用在其它应用中声明的权限。此外,应用也可以定义它自己的权限。新权限使用<permission>
元素进行声明。
4 设备兼容性
在清单文件中,还可以声明应用需要哪些类型的硬件或软件功能,进而声明应用与哪些类型的设备兼容。这些声明大多仅供参考。系统不会读取它们,但 Google Play 等外部服务会读取它们,以便在用户从设备搜索应用程序时为其提供过滤。Google Play 商店不允许应用安装在不提供应用所需的功能或系统版本的设备上。
有几个清单标记用于定义应用与哪些设备兼容。以下是一些最常见的清单标记。
4.1 <uses-feature>
<uses-feature>
元素可以声明应用所需的硬件和软件功能。例如,如果应用在不带罗传感器的设备上无法获得基本功能,则可以使用以下清单标记将罗盘传感器声明为必需功能:
<manifest ... >
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />
...
</manifest>
4.2 <uses-sdk>
每个后续的平台版本通常会添加之前版本中不可用的新 API。为了指明与应用兼容的最低版本,清单必须包含<uses-sdk>
标记及其minSdkVersion
属性。
但请注意,<uses-sdk>
元素中的属性会被替换为build.gradle(.kts)
文件中的相应属性。因此,如果使用的是 Adnroid Studio,则在此处指定minSdkVersion
和targetSdkVersion
的值:
- Groovy
android {
defaultConfig {
applicationId 'com.example.myapp'
// Defines the minimum API level required to run the app.
minSdkVersion 21
// Specifies the API level used to test the app.
targetSdkVersion 33
...
}
}
5 文件约定
本部分介绍了通常适用于清单文件中的所有元素和属性的约定和规则。
5.1 元素
只有<manifest>
和<application>
元素是必需的。这两个元素都只能出现一次。大多数其他元素可以出现零次或多次。
所有值均通过属性进行设置,而不是通过元素内的字符数据设置。
同一级别的元素通常不分先后顺序。例如,<activity>
、<provider>
和<service>
元素可按任意顺序放置。此规则主要有两种例外情况:
<activity-alias>
元素必须跟在它作为其别名的<activity>
后面。<application>
元素必须是<manifest>
元素内的最后一个元素。
5.2 属性
严格意义上来说,所有属性都是可选的。不过,必须指定许多属性,这样元素才能实现其目的。
除了<manifest>
根元素的某些属性之外,所有属性名称都以android:
前缀开头,例如 android:alwaysRetainTaskState
。由于该前缀是通用的,因此在按名称引用属性时,文档中通常会将其省略。
5.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>
5.4 资源值
某些属性具有显示给用户的值,如 activity 的标题或您的应用图标。这些属性的值可能因用户的语言或其他设备配置不同而异(例如,根据设备的像素密度提供不同的图标大小),因此应该从资源或主题设置这些值,而不是将其硬编码到清单文件中。实际值随后可以根据您针对不同设备配置提供的备用资源发生变化。
资源表示为值,格式如下:"@[package:]type/name"
。
如果资源由您的应用提供(包括资源由库依赖项提供的情况,因为库资源会合并到您的资源中),则您可以省略 package
名称。当您想要使用来自 Android 框架的资源时,唯一一个其他有效的软件包名称是android
。
type
是资源的类型,如string
或drawable
;name
是标识特定资源的名称。 示例如下:
<activity android:icon="@drawable/smallPic" ... >
如需应用在主题背景中定义的值,第一个字符必须是?
,而不是@
:"?[package:]type/name"
。
5.5 字符串值
如果属性值是一个字符串,则使用双反斜线 (\\
) 转义字符,如\\n
表示换行符,\\uxxxx
表示 Unicode 字符。