Android 开发基本概念(七)
每个应用项目都必须在项目源集的根目录中具有一个 AndroidManifest.xml 文件(具有该名称)。 清单文件向 Android 构建工具,Android操作系统和Google Play介绍了有关您的应用的重要信息。
清单文件需要声明以下内容:
- 应用的软件包名称,通常与您的代码的命名空间相匹配。 Android 构建工具使用它来确定构建项目时代码实体的位置。打包应用时,构建工具将此值替换为 Gradle 构建文件中的应用 ID,该文件用作系统和 Google Play 上的唯一应用标识符。
- 该应用的组件,其中包括所有 Activity,服务,广播接收器和内容提供器。每个组件都必须定义基本属性,例如其 Kotlin 或 Java 类的名称。它还可以声明能够处理的设备配置,以及描述组件如何启动的 Intent 过滤器。
- 应用访问系统的受保护部分或其他应用所需的权限。它还声明了其他应用必须具有的权限,以便从此应用访问内容。
- 应用所需的硬件和软件功能,这会影响哪些设备可以从 Google Play 安装应用。
File features
Package name and application 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 类的命名空间(用于访问应用的资源)。
- 它使用该名称来解析清单文件中声明的任何相关类名称。
因此,清单的 package 属性中的名称应始终与您的项目的基本包名称保持一致,并在其中保留 Activity 和其他应用代码。当然,您可以在项目中使用其他子包,但这些文件必须使用 package 属性中的命名空间导入 R.java 类。
但是,请注意,一旦 APK 编译完成,package 属性也代表您的应用的通用唯一应用 ID。在构建工具根据 package 名称执行上述任务后,他们用项目的 build.gradle 文件(用于 Android Studio 项目)中的 applicationId 属性值替换 package 值。 package 属性的最终值必须是通用唯一的,因为它是在系统和 Google Play 中识别您的应用的唯一保证方式。
清单中的 package 名称与 build.gradle 文件中的 applicationId 之间的区别可能有点混淆。但是如果你让它们保持一致,你就没有什么可担心的。
但是,如果您决定让代码的命名空间(以及清单中的 package 名称)与构建文件中的 applicationId 不同,请确保您完全理解设置应用 ID 的含义。
App components
对于您在应用中创建的每个应用组件,您必须在清单文件中声明相应的 XML 元素:
- <activity> 用于 Activity 的每个子类。
- <service> 用于 Service 的每个子类。
- <receiver> 用于 BroadcastReceiver 的每个子类。
- <provider> 用于 ContentProvider 的每个子类。
如果您将这些组件中的任何一个子类没有在清单文件中声明,则系统无法启动它。
您的子类名称必须使用 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 filters
应用的 Activity、服务和广播接收器由 Intent 激活。 Intent 是一个由 Intent 对象定义的消息,用于描述要执行的操作,包括要执行的数据、应该执行操作的组件类别以及其他指令。
当应用向系统发出 Intent 时,系统会根据每个应用的清单文件中的 Intent 过滤器声明来查找可处理 Intent 的应用组件。 系统启动匹配组件的实例并将 Intent 对象传递给该组件。 如果多个应用可以处理该 Intent,则用户可以选择使用哪个应用。
应用组件可以具有任意数量的 Intent 过滤器(使用 <intent-filter> 元素定义),每个过滤器描述该组件的不同功能。
Icons and labels
许多清单元素具有 icon 和 label 属性,分别向用户显示相应应用组件的小图标和文本标签。
在任何情况下,在父元素中设置的图标和标签都将成为所有子元素的默认 icon 和 label 值。 例如,在 <application> 元素中设置的图标和标签是每个应用组件(例如所有 Activity)的默认图标和标签。
在组件的 <intent-filter> 中设置的图标和标签将显示给用户,只要该组件显示为满足 Intent 的选项。 默认情况下,此图标是从为父组件声明的任何图标(<activity> 或 <application> 元素)继承的,但如果它提供了一个你希望更好的在选择对话框指示的唯一操作,那么您可能需要更改 Intent 过滤器的图标。
Permissions
Android 应用必须请求访问敏感用户数据(如联系人和短信)或某些系统功能(例如相机和互联网访问)的权限。 每个许可都由唯一标签标识。 例如,需要发送 SMS 消息的应用必须在清单中包含以下行:
<manifest ... >
<uses-permission android:name="android.permission.SEND_SMS"/>
...
</manifest>
从 Android 6.0(API 级别 23)开始,用户可以在运行时批准或拒绝某些应用权限。 但无论您的应用支持哪种 Android 版本,您都必须在清单中使用 <uses-permission> 元素声明所有权限请求。 如果授予权限,则应用可以使用受保护的功能。 如果不是,它尝试访问这些功能失败。
您的应用还可以通过权限来保护自己的组件。 它可以使用 Android 定义的任何权限,如 android.Manifest.permission 中列出的权限或在另一个应用中声明的权限。 你的应用也可以定义自己的权限。 使用 <permission> 元素声明新权限。
Device compatibility
清单文件也是您可以声明应用需要哪些类型的硬件或软件功能的地方,因此您可以声明应用兼容哪种类型的设备。 Google Play 商店不允许将您的应用安装在不提供应用所需功能或系统版本的设备上。
有几个清单标签可以定义您的应用与哪些设备兼容。 以下只是几个最常见的标签。
<uses-feature>
<uses-feature> 元素允许您声明应用需要的硬件和软件功能。 例如,如果您的应用无法在没有指南针传感器的设备上实现基本功能,则可以根据需要使用以下清单标签声明指南针传感器:
<manifest ... >
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />
...
</manifest>
注意:如果您希望在 Chromebook 上提供您的应用,则应考虑一些重要的硬件和软件功能限制。
<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 26
...
}
}
File conventions
本节介绍通常适用于清单文件中所有元素和属性的约定和规则。
Elements
只有 <manifest> 和 <application> 元素是必需的。 它们每个只能出现一次。 大多数其他元素可能会出现零次或多次。 但是,它们中的一些必须存在才能使清单文件有用。
所有的值都是通过属性设置的,而不是作为元素中的字符数据。
同一级别的元素通常是不排序的。 例如,<activity>、<provider> 和 <service> 元素可以按任意顺序放置。 这条规则有两个关键的例外:
- 一个 <activity-alias> 元素必须在它作为别名的 <activity> 之后。
- <application> 元素必须是 <manifest> 元素内的最后一个元素。
Attributes
从技术上讲,所有属性都是可选的。 但是,必须指定许多属性,以便元素可以达到其目的。 对于真正的可选属性,参考文档指出了默认值。
除了根 <manifest> 元素的某些属性外,所有属性名称都以 android: 前缀开头。 例如,android:alwaysRetainTaskState。 由于前缀是通用的,因此通过名称引用属性时,文档通常会省略它。
Multiple values
如果可以指定多个值,则元素几乎总是重复的,而不是单个元素中列出的多个值。 例如,一个 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>
Resource values
某些属性具有显示给用户的值,例如 Activity 的标题或应用图标。 这些属性的值可能会根据用户的语言或其他设备配置(例如根据设备的像素密度提供不同的图标大小)而有所不同,因此应该从资源或主题设置值,而不是硬编码到清单文件。 然后,实际值可以根据您为不同设备配置提供的替代资源进行更改。
资源用以下格式表示为值:
“@[package:]type/name”
如果资源是由您的应用提供的(包括它是否由库依赖项提供,因为库资源已合并到您的应用中),则可以省略 package 名称。 当您想使用 Android 框架中的资源时,唯一的其他有效包名是 android。
type 是一种资源类型,如字符串或 drawable,name 是标识特定资源的名称。 这里是一个例子:
<activity android:icon="@drawable/smallPic" ... >
要替代应用主题中定义的值,第一个字符必须是 ? 代替 @:
“?[package:]type/name”
String values
如果属性值是一个字符串,则必须使用双反斜杠(\\)来转义字符,例如换行符为 \\n 或 Unicode 字符为 \\uxxxx。
Example manifest file
<?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>
Manifest elements reference
<action>
SYNTAX
<action android:name="string" />
CONTAINED IN
DESCRIPTION
将行为添加到 Intent 过滤器。 一个 <intent-filter> 元素必须包含一个或多个 <action> 元素。 如果 Intent 过滤器中没有 <action> 元素,则过滤器不接受任何 Intent 对象。
ATTRIBUTES
-
android:name
行动的名称。 一些标准行为在 Intent 类中定义为 ACTION_string 常量。 要将这些行为之一分配给该属性,请添加「android.intent.action.」 到 ACTION_ 后面的字符串。 例如,对于 ACTION_MAIN,请使用「android.intent.action.MAIN」,对于 ACTION_WEB_SEARCH,请使用「android.intent.action.WEB_SEARCH」。
对于您定义的操作,最好将您应用的软件包名称用作前缀以确保唯一性。 例如,TRANSMOGRIFY 行为可以如下指定:
<action android:name="com.example.project.TRANSMOGRIFY" />
INTRODUCED IN
API Level 1
SEE ALSO
<activity>
SYNTAX
<activity android:allowEmbedded=["true" | "false"]
android:allowTaskReparenting=["true" | "false"]
android:alwaysRetainTaskState=["true" | "false"]
android:autoRemoveFromRecents=["true" | "false"]
android:banner="drawable resource"
android:clearTaskOnLaunch=["true" | "false"]
android:colorMode=[ "hdr" | "wideColorGamut"]
android:configChanges=["mcc", "mnc", "locale",
"touchscreen", "keyboard", "keyboardHidden",
"navigation", "screenLayout", "fontScale",
"uiMode", "orientation", "density",
"screenSize", "smallestScreenSize"]
android:directBootAware=["true" | "false"]
android:documentLaunchMode=["intoExisting" | "always" |
"none" | "never"]
android:enabled=["true" | "false"]
android:excludeFromRecents=["true" | "false"]
android:exported=["true" | "false"]
android:finishOnTaskLaunch=["true" | "false"]
android:hardwareAccelerated=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:launchMode=["standard" | "singleTop" |
"singleTask" | "singleInstance"]
android:maxRecents="integer"
android:maxAspectRatio="float"
android:multiprocess=["true" | "false"]
android:name="string"
android:noHistory=["true" | "false"]
android:parentActivityName="string"
android:persistableMode=["persistRootOnly" |
"persistAcrossReboots" | "persistNever"]
android:permission="string"
android:process="string"
android:relinquishTaskIdentity=["true" | "false"]
android:resizeableActivity=["true" | "false"]
android:screenOrientation=["unspecified" | "behind" |
"landscape" | "portrait" |
"reverseLandscape" | "reversePortrait" |
"sensorLandscape" | "sensorPortrait" |
"userLandscape" | "userPortrait" |
"sensor" | "fullSensor" | "nosensor" |
"user" | "fullUser" | "locked"]
android:showForAllUsers=["true" | "false"]
android:stateNotNeeded=["true" | "false"]
android:supportsPictureInPicture=["true" | "false"]
android:taskAffinity="string"
android:theme="resource or theme"
android:uiOptions=["none" | "splitActionBarWhenNarrow"]
android:windowSoftInputMode=["stateUnspecified",
"stateUnchanged", "stateHidden",
"stateAlwaysHidden", "stateVisible",
"stateAlwaysVisible", "adjustUnspecified",
"adjustResize", "adjustPan"] >
. . .
</activity>
CONTAINED IN
<application>
CAN CONTAIN
- <intent-filter>
- <meta-data>
- <layout>
DESCRIPTION
声明一个 Activity(一个 Activity 子类),它实现了应用的可视化用户界面的一部分。 所有 Activity 必须由清单文件中的 <activity> 元素表示。 任何未声明的内容都不会被系统看到,并且永远不会运行。
ATTRIBUTES
-
android:allowEmbedded
表明该 Activity 可以作为其他 Activity 的嵌入子进程启动。 特别是子 Activity 存活在其它 Activity 所拥有的容器(如 Display)中的情况下。 例如,用于 Wear 自定义通知的活动必须声明这一点,以便 Wear 可以在驻留在另一个进程中的上下文流中显示活动。
此属性的默认值为 false。
-
android:allowTaskReparenting
Activity 是否可以从启动它的任务转移到当任务接下来推到前台时具有关联性的任务 - 如果它可以移动,则为「true」;如果该任务必须与它启动的任务保持一致,则为「false」。
如果未设置此属性,则由 <application> 元素的相应 allowTaskReparenting 属性设置的值将应用于该 Activity。默认值是「false」。
-
android:alwaysRetainTaskState
系统是否始终维护任务的状态 - 如果是,则为「true」;如果允许系统在某些情况下将任务重置为初始状态,则为「false」。 默认值是「false」。 该属性仅对任务的根 Activity 有意义; 所有其他 Activity 都被忽略。
通常,当用户从主屏幕重新选择任务时,系统会在某些情况下清除任务(从根 Activity 之上的堆栈中移除所有 Activity)。 通常,如果用户在一定时间内未访问任务(例如30分钟),则会执行此操作。
但是,如果此属性为「true」,则用户将始终返回处于其最后状态的任务,无论他们如何到达该状态。
-
android:autoRemoveFromRecents
具有此属性的 Activity 所启动的任务是否保留在总览屏幕中,直到任务中的最后一项 Activity 完成。 如果为 true,则会从总览屏幕中自动删除该任务。 这将覆盖调用者对 FLAG_ACTIVITY_RETAIN_IN_RECENTS 的使用。 它必须是一个布尔值,可以是「true」或「false」。
-
android:banner
Drawable 资源为其关联的项目提供扩展图形横幅。 与 <activity> 标签一起使用可为特定 Activity 提供默认横幅,或者使用 <application> 标签为所有应用活动提供横幅。
该属性必须设置为对包含图像的 drawable 资源的引用。 没有默认横幅。
-
android:clearTaskOnLaunch
除了根 Activity 之外,无论何时从主屏幕重新启动的所有 Activity 是否将从任务移除 - 如果任务总是被降落至其根 Activity,则为「true」,否则为「false」。默认值是「false」。该属性仅对开始新任务的活动(根 Activity)有意义;它在任务中的所有其他 Activity 都被忽略。
当值为“true”时,每次用户再次启动任务时,无论他们上一次在任务中执行什么操作,并且无论他们是使用“返回”还是“主页”按钮离开它,都会将其引导至其根目录。当值为“false”时,可能会在某些情况下清除任务中的活动(请参阅alwaysRetainTaskState属性),但并非总是如此。
-
android:colorMode
请求 Activity 在兼容设备上以宽色域模式显示。 在宽色域模式下,可以在 SRGB 色域外渲染窗口以显示更鲜艳的色彩。 如果设备不支持宽色域渲染,则此属性不起作用。
-
android:configChanges
列出 Activity 将自行处理的配置更改。 当运行时发生配置更改时,该 Activity 默认关闭并重新启动,但使用此属性声明配置将会阻止 Activity 重新启动。 相反,该 Activity 仍在运行,并调用 onConfigurationChanged() 方法。
下表是此属性可用的值,多个值使用「|」进行分割。
Value Description “density” 显示密度已更改 - 用户可能指定了不同的显示比例,或者现在可能会激活不同的显示。在 API Level 24 时添加。 “fontScale” 字体比例因子已更改 - 用户选择了新的全局字体大小。 “keyboard” 键盘类型已更改 - 例如,用户插入了外置键盘 “keyboardHidden” 键盘可访问性已更改 - 例如,用户已经显示硬件键盘。 “layoutDirection” 布局方向发生了变化 - 例如,从左到右(LTR)变为从右到左(RTL)。 API Level 17 加入。 “locale” 语言环境已更改 - 用户已选择应显示文本的新语言。 “mcc” IMSI移动国家代码(MCC)已更改 - 已检测到SIM并更新了MCC。 “mnc” IMSI移动网络代码(MNC)已更改 - 已检测到SIM并更新了MNC。 “navigation” 导航类型(轨迹球/ dpad)已更改。 (这通常不会发生。) “orientation” 屏幕方向已更改 - 用户旋转了设备。 Note: Android 3.2 (API Level 13) 或更新版本需同时声明「screenSize」。 “screenLayout” 屏幕布局已更改 - 现在可能会激活不同的显示。 “screenSize” 当前可用的屏幕尺寸已更改。这表示当前可用尺寸相对于当前宽高比的变化,因此当用户在横向和纵向之间切换时会发生变化。 API Level 13 加入。 “smallestScreenSize” 物理屏幕尺寸已更改。无论方向如何,这代表大小的变化,所以只有在实际物理屏幕尺寸发生变化时才会改变,例如切换到外部显示器。 对此配置的更改对应于最小宽度配置的更改。 API Level 13 加入。 “touchscreen” 触摸屏已经改变。 (这通常不会发生。) “uiMode” 用户界面模式已更改 - 用户将设备放置在桌面或汽车底座上,或者夜间模式已更改。 API Level 8 加入。 -
android:directBootAware
Activity 是否可以直接启动;也就是说,在用户解锁设备之前它是否可以运行。注意:在直接引导过程中,应用中的活动只能访问存储在设备保护存储中保存的数据。默认值是「false」。
-
android:documentLaunchMode
-
android:enabled
-
android:excludeFromRecents
-
android:exported
-
android:finishOnTaskLaunch
-
android:hardwareAccelerated
-
android:icon
-
android:label
-
android:launchMode
-
android:maxRecents
-
android:maxAspectRatio
-
android:multiprocess
-
android:name
-
android:noHistory
-
android:parentActivityName
-
android:persistableMode
-
android:permission
-
android:process
-
android:relinquishTaskIdentity
-
resizeableActivity
-
android:screenOrientation
-
android:showForAllUsers
-
android:stateNotNeeded
-
supportsPictureInPicture
-
android:taskAffinity
-
android:theme
-
android:uiOptions
-
android:windowSoftInputMode
INTRODUCED IN
除了 noHistory 和 windowSoftInputMode 是在 API Level 3 添加的之外,其余所有属性都是在 API Level 1。
SEE ALSO
<application>
<activity-alias>