The Android Developer Challenge is back! Submit your idea before December 2.

应用清单概览

每个应用项目必须在项目源设置的根目录中加入 AndroidManifest.xml 文件(且必须使用此名称)。 清单文件会向 Android 构建工具、Android 操作系统和 Google Play 描述应用的基本信息。

重点是,清单文件需声明以下内容:

  • 应用的软件包名称,其通常与代码的命名空间相匹配。 构建项目时,Android 构建工具会使用此信息来确定代码实体的位置。 打包应用时,构建工具会使用 Gradle 构建文件中的应用 ID 来替换此值,而此 ID 则用作系统和 Google Play 上的唯一应用标识符。了解关于软件包名称和应用 ID 的更多内容
  • 应用的组件,包括所有 Activity、服务、广播接收器和内容提供程序。 每个组件都必须定义基本属性,例如其 Kotlin 或 Java 类的名称。 清单文件还能声明一些功能,例如其所能处理的设备配置,以及描述组件如何启动的 Intent 过滤器。了解关于应用组件的更多内容
  • 应用为访问系统或其他应用的受保护部分所需的权限。 如果其他应用想要访问此应用的内容,则清单文件还会声明其必须拥有的权限。 了解关于权限的更多内容
  • 应用需要的硬件和软件功能,这些功能会影响哪些设备能够从 Google Play 安装应用。了解关于设备兼容性的更多内容

如果您使用 Android Studio 构建应用,则系统会为您创建清单文件,并在您构建应用时(尤其是在使用代码模板时)添加大部分基本清单元素。

文件功能

下文介绍如何在清单文件中反映某些最重要的应用特性。

软件包名称和应用 ID

清单文件的根元素需包含应用软件包名称(通常与项目目录结构,即 Java 命名空间相匹配)的属性。

例如,以下代码段显示包含软件包名称 "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 中识别应用的唯一方式。

清单中的 package 名称与 build.gradle 文件中 applicationId 的区别可能会令人感到有点困惑。 但若您保持二者一致,便无需担心任何问题。

不过,如果您决定让代码的命名空间(以及清单中的 package 名称)有别于构建文件的 applicationId,请务必完全理解设置应用 ID的影响。 本页面将说明如何不依赖构建文件的 applicationId,安全调整清单的 package 名称,以及如何更改不同构建配置的应用 ID。

应用组件

对于在应用中创建的每个应用组件,您必须在清单文件中声明相应的 XML 元素:

如果您创建此类组件的任何子类,但未在清单文件中对其进行声明,则系统便无法启动该子类。

必须使用 name 属性指定子类的名称,且其必须使用完整的软件包名称。 例如,可对 Activity 子类进行如下声明:

<manifest ... >
    <application ... >
        <activity android:name="com.example.myapp.MainActivity" ... >
        </activity>
    </application>
</manifest>

不过,如果 name 值的第一个字符是句点,则应用的软件包名称(来自 <manifest> 元素的 package 属性)将作为此名称的前缀。 例如,以下 Activity 名称将解析为 `"com.example.myapp.MainActivity"`:

<manifest package="com.example.myapp" ... >
    <application ... >
        <activity android:name=".MainActivity" ... >
            ...
        </activity>
    </application>
</manifest>

如果您拥有位于子软件包中(如在 com.example.myapp.purchases 中)的应用组件,则 name 值必须添加缺失的子软件包名称(如 ".purchases.PayActivity")或使用完全限定的软件包名称。

Intent 过滤器

应用的 Activity、服务和广播接收器均由 Intent 激活。 Intent 是由 Intent 对象定义的消息,用于描述要执行的操作,其中包括要执行操作的数据、应执行操作的组件类别以及其他相关说明。

当应用向系统发布 Intent 后,系统会根据每个应用清单文件中的 Intent 过滤器来查找可处理此 Intent 的应用组件。 系统会启动匹配组件的实例,并向该组件传递 Intent 对象。 如果有多个应用可以处理此 Intent,则用户可选择使用哪个应用。

应用组件可包含任意数量的 Intent 过滤器(通过 <intent-filter> 元素定义),每个过滤器描述该组件的不同功能。

如需了解更多信息,请参阅 Intent 和 Intent 过滤器文档。

图标和标签

许多清单元素拥有 iconlabel 属性,二者分别用于向对应应用组件的用户显示小图标和文本标签。

任何情况下,在父元素中设置的图标和标签都会成为所有子元素的默认 iconlabel 值。 例如,在 <application> 元素中设置的图标和标签即为每个应用组件(如所有 Activity)的默认图标和标签。

只要以实现 Intent 的选项形式呈现组件,系统便会向用户显示在该组件的 <intent-filter> 中设置的图标和标签。 默认情况下,此图标继承自为父组件(<activity><application> 元素)声明的任何图标,但如果 Intent 过滤器提供唯一操作,且您希望该操作在选择器对话框中有更好的指示,则您可能需更改此图标。 如需了解更多信息,请参阅允许其他应用启动您的 Activity

权限

如要访问敏感用户数据(如联系人和短信)或某些系统功能(如相机和互联网访问),则 Android 应用必须请求相关权限。 每个权限均由唯一标签标识。 例如,如果应用需要发送短信,则必须在清单中添加以下代码行:

<manifest ... >
    <uses-permission android:name="android.permission.SEND_SMS"/>
    ...
</manifest>

从 Android 6.0(API 级别 23)开始,用户可以在运行时同意或拒绝某些应用权限。 但是,无论您的应用支持哪个 Android 版本,您都必须使用清单中的 <uses-permission> 元素声明所有权限请求。 授予应用权限后,该应用便能使用受保护的功能。 否则,该应用在尝试访问这些功能时会失败。

应用也可使用权限保护自己的组件。 它可以使用 Android 定义的任何权限(如 android.Manifest.permission 中所列),或在其他应用中声明的权限。 应用也可定义自己的权限。 应用可通过 <permission> 元素来声明新权限。

如需了解更多信息,请参阅权限概览

设备兼容性

清单文件也可用于声明应用所需的硬件或软件功能类型,以及应用兼容的设备类型。 Google Play 商店不允许在未提供应用所需功能或系统版本的设备上安装应用。

某些清单标签可定义与应用兼容的设备。 以下是一些最常见的此类标签。

<uses-feature>

<uses-feature> 元素允许您声明应用所需的硬件和软件功能。 例如,如果您的应用无法在缺少罗盘传感器的设备上实现基础功能,则您可使用以下清单标记将罗盘传感器声明为必需功能:

<manifest ... >
    <uses-feature android:name="android.hardware.sensor.compass"
                  android:required="true" />
    ...
</manifest>

注意: 如果您想在 Chromebook 上使用自己的应用,则应考虑一些重要的硬件和软件功能限制。 如需了解更多信息,请参阅 Chromebook 的应用清单兼容性

<uses-sdk>

每个后续平台版本往往都会新增先前版本未提供的 API。 如要指明与应用兼容的最低版本,您的清单必须包含 <uses-sdk> 标签及其 minSdkVersion 属性。

但请注意,<uses-sdk> 元素中的这些属性会被 build.gradle 文件中的相应属性覆盖。 因此,如果您使用的是 Android Studio,则必须在此处指定 minSdkVersiontargetSdkVersion 值:

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

    ...
  }
}

如需了解关于 build.gradle 文件的更多信息,请阅读如何配置您的构建

如要详细了解如何声明应用对不同设备的支持,请参阅设备兼容性概览

文件约定

此部分描述普遍适用于清单文件中所有元素和属性的约定和规则。

元素
只有 <manifest><application> 元素是必需的, 二者必须且只能出现一次。 大多数其他元素可以不出现或多次出现。 但是,必须提供某些元素才能使清单文件发挥作用。

必须通过属性(而非以元素内的字符数据形式)设置所有值。

同一级别的元素通常不分先后顺序。 例如,<activity><provider><service> 元素可按任何顺序放置。 这条规则有两个主要的例外情况:

属性
严格来说,所有属性都是可选的。 但是,必须指定某些属性才可让元素实现其目的。 对于真正可选的属性,参考文档会指定默认值。

除了根 <manifest> 元素的某些属性外,所有属性名称均以 android: 前缀开头。 例如,android:alwaysRetainTaskState。 由于该前缀是通用的,因此在按名称引用属性时,参考文档通常会将其忽略。

多个值
如果可以指定多个值,则几乎总是在重复元素,而非列出单个元素内的多个值。 例如,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>
资源值
某些属性的值可以显示给用户,例如,Activity 的标题或应用图标。 这些属性的值可能因用户的语言或其他设备配置而异(例如根据设备的像素密度提供不同的图标大小),因此您应根据资源或主题设置值,而非将其硬编码到清单文件中。 随后,您可根据为不同设备配置提供的备用资源更改实际值。

资源将通过以下格式表示为值:

"@[package:]type/name"

如果资源由您的应用提供,则您可以忽略软件包名称(其亦适用于资源由库依赖项提供的情况,因为 库资源会合并到您的资源中)。 当您想要使用 Android 框架中的资源时,唯一的其他有效包名称是 android

type 是资源类型(例如 stringdrawable),name 是标识特定资源的名称。 下面是示例:

<activity android:icon="@drawable/smallPic" ... >

有关如何在项目中添加资源的更多信息,请阅读提供资源

如要应用主题中定义的值,第一个字符必须是 ?,而非 @

"?[package:]type/name"

字符串值
如果属性值为字符串,则您必须使用双反斜杠 (\\) 来转义字符,例如:使用 \\n 表示换行符或使用 \\uxxxx 表示 Unicode 字符。

清单元素参考

下表提供 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 平台的兼容性。

清单文件示例

以下 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>