AndroidManifest.xml 是每个 Android 应用程序的必需配置文件,描述其组件、权限和元数据。Android 系统在安装和启动每个应用时读取此文件。根据 Android Developers, 2025,没有正确的清单,应用将无法安装在设备上。AndroidManifest.xml 为操作系统注册 Activity、Service、BroadcastReceiver 和 ContentProvider。
要点
AndroidManifest.xml 是 XML 格式的主要配置文件,每个 Android 项目必须在 app/src/main 目录中包含它。Android 系统在执行任何应用程序代码之前——在安装时解析 APK 的阶段——对其进行分析。如果清单中存在语法错误或缺少必需声明,安装将中断并显示错误消息。
该文件包含应用程序的完整声明:所有组件的列表(Activity、Service、BroadcastReceiver、ContentProvider)、请求的权限、最低 SDK 版本、硬件要求以及主题和样式的配置。每个可能被系统或其他应用程序调用的组件都必须在清单中显式声明。这是一项安全要求:没有显式声明,组件无法被调用。
没有正确配置的清单,应用无法通过 Google Play 或侧载安装。系统在 APK 解析阶段检查清单,并在出错时拒绝安装。Google Play 还会扫描清单中的不安全配置:对于没有 intent-filter 的组件上的 exported=true 会发出警告,如果缺少 targetSdk 34+ 的必需权限,则发布被阻止。因此,理解清单结构是 Android 开发人员的必备技能。
Android 应用程序的每个组件都必须在清单中显式注册。这是平台对所有四种组件类型的强制要求。没有注册,组件无法由系统创建,尝试启动它将导致 ActivityNotFoundException 或类似异常。组件在 application 标签内注册,顺序不影响其运行。
activity 标签注册应用程序的屏幕。exported 属性确定其他应用是否可以启动此 Activity。从 Android 12 开始,在有 intent-filter 的情况下缺少 exported 会导致编译错误——这是一项安全要求。入口点通过带有 action MAIN 和 category LAUNCHER 的 intent-filter 设置。每个 Activity 必须具有唯一的 android:name,与类的完整或相对名称对应。
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
service 标签定义后台服务。从 Android 8 开始,后台服务有严格的限制:foreground service 需要带有用户可见图标的消息通知,而 bound service 仅在存在绑定的客户端时存活。在后台运行时没有通知的服务会在应用程序切换到后台模式几分钟后被系统自动终止。对于长时间运行的任务,请使用 WorkManager 代替 Service。
<service
android:name=".SyncService"
android:exported="false"
android:foregroundServiceType="dataSync" />
receiver 标签声明系统或自定义广播消息的接收器。从 Android 8 开始,大多数隐式广播不再传递给在清单中静态声明的接收器。取而代之的是,建议通过代码中的 Context.registerReceiver 动态注册接收器。例外情况是某些系统广播,例如 BOOT_COMPLETED,它们仍然需要在清单中进行静态注册。
<receiver
android:name=".ConnectivityReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Android 中的每个危险权限都需要通过 uses-permission 标签在清单中声明。从 Android 6 开始,危险权限在运行时通过用户对话框请求,但在清单中的声明仍然是强制性的。没有它,requestPermissions 方法会抛出 SecurityException。普通级别的权限,如 INTERNET 和 ACCESS_NETWORK_STATE,在安装时自动授予。
| 权限 | 用途 |
|---|---|
| CAMERA | 访问设备摄像头进行拍照和录像 |
| ACCESS_FINE_LOCATION | 通过 GPS 和网络获取精确地理位置 |
| RECORD_AUDIO | 从设备麦克风录制音频 |
| READ_CONTACTS | 从电话簿读取联系人 |
| POST_NOTIFICATIONS | 在 Android 13+ 上发送通知 |
uses-permission-sdk-23 标签指定仅在 Android 6.0+ 上需要的权限。这允许保持与旧版本的兼容性,而无需请求不存在的权限。例如,POST_NOTIFICATIONS 仅在 Android 13+ 上可用,因此必须通过 uses-permission-sdk-33 指定,以避免在旧设备上出现未知权限错误。uses-permission 中的 maxSdkVersion 属性允许在应用程序在新版本 Android 上更新时自动撤销不必要的权限。
普通级别权限(INTERNET、ACCESS_NETWORK_STATE)在安装时自动授予,不需要运行时请求。它们也通过 uses-permission 声明,但不会在对话框中显示给用户。为了控制来自其他应用对应用组件的访问,使用 permission-protected components 机制:可以在 Activity 或 Service 级别指定自定义权限,当组件从外部调用时系统将检查该权限。这为进程间通信提供了额外的安全级别。
清单中的 intent-filter 标签声明组件可以处理哪些隐式 Intent。这是 Android 将系统或自定义操作与应用程序关联的机制。Intent filter 由三个元素组成:action(操作)、category(类别)和 data(数据)。所有三个可以组合以精确描述组件应接收哪些 Intent。系统根据最具体的过滤器选择合适的组件。
<activity android:name=".DeepLinkActivity">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="itsectr.com"
android:pathPrefix="/app" />
</intent-filter>
</activity>
autoVerify 属性启用 Android App Links 验证:系统联系服务器以确认域所有权。没有验证,深度链接通过标准选择器对话框工作,用户在其中选择用哪个应用打开链接。成功验证后,链接直接在应用中打开,无需对话框。Google Search Console 也使用 autoVerify 来索引深度链接并将其显示在搜索结果中。
带有 action.VIEW 以及 DEFAULT 和 BROWSABLE 类别的过滤器处理来自浏览器、电子邮件和其他应用的链接。这是在 Android 中实现深度链接的主要机制。要支持自定义 URL 方案,例如 myapp://,只需指定不带 host 的 scheme 即可。但 Google 建议使用 HTTPS 深度链接而不是自定义方案,因为它们更安全且不需要额外权限。自定义方案可能被注册了相同方案的任何应用拦截。
根 manifest 标签包含包、版本和 SDK 的属性。application 标签存储全局设置:主题、图标、标签和调试标志。manifest 属性设置在包级别进行的版本控制,application 属性定义应用程序的整体外观和行为。值可以是通过 @-语法的资源引用或字符串字面量。
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.itsectr.myapp"
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34" />
<application
android:label="MyApp"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.MyApp"
android:supportsRtl="true"
android:allowBackup="true">
<!-- 应用程序组件 -->
</application>
</manifest>
application 内的 meta-data 标签允许存储任意的键值对。这对于配置第三方库很方便:API 密钥、端点地址和功能标志。meta-data 中的数据可以通过 PackageManager.getApplicationInfo().metaData 在运行时访问。例如,Firebase 和 Google Maps 使用 meta-data 传递访问密钥而无需在源代码中硬编码。密钥在清单中指定,并且可能因不同的构建变体而异。
android:extractNativeLibs 属性控制从 APK 中提取原生库。对于 targetSdk 34+ 的应用,此属性必须显式指定,否则构建可能会失败并显示错误 INSTALL_FAILED_INVALID_APK。如果 extractNativeLibs=false,原生库保留在 APK 内而不解压,这缩小了已安装应用的大小,但增加了库的加载时间。对于大多数现代应用,建议使用 extractNativeLibs=false 以节省用户磁盘空间。
android:networkSecurityConfig 属性允许指定网络安全配置文件。这对于 targetSdk 28+ 的应用尤其重要,因为 HTTP 流量默认被阻止。配置文件定义了受信任的证书、用于 HTTP 连接的域名以及证书固定的规则。这取代了已弃用的 android:usesCleartextTraffic 属性,并提供了在操作系统级别管理连接安全的更灵活机制。
android:largeHeap 属性请求为应用程序增大堆大小。默认情况下,Android 为每个应用分配有限的内存,取决于设备和操作系统版本。如果应用处理重图像、视频或大数据集,largeHeap 可以防止 OutOfMemoryError。但滥用此属性是有害的:高内存消耗的应用在资源不足时会被系统更快地终止。只有在性能分析并确认必要性后才使用 largeHeap。
常见问题
从 Android 12 开始,在有 intent-filter 的情况下缺少 exported 属性会导致编译错误。系统要求显式指定每个带有 intent-filter 的组件的可见性——这是一项安全措施,以防止其他应用意外打开组件。对于没有 intent-filter 的 Activity,exported 默认为 false。
可以,但启动器中会显示应用的多个图标。每个带有 MAIN/LAUNCHER 的 Activity 成为单独的入口点。这用于创建到应用不同部分的快捷方式,例如直接进入设置或创建新记录。每个图标直接打开相应的 Activity。
Android 将库中的清单与应用程序的主清单合并。当属性冲突时,使用 tools:replace 或 tools:node="merge" 来解决。此机制是自动的:通过 Gradle 添加库时,其清单会与主清单合并。要取消或替换来自库的属性,请使用 tools:node="remove" 或 tools:replace="attributeName"。
典型原因:权限未通过 uses-permission 在清单中声明,使用的是普通级别权限(无需运行时请求),用户选择了"不再询问"并且权限被永久拒绝,或者 targetSdkVersion 低于 23,此时权限在安装时请求。要诊断,请检查清单和通过 adb logcat 的日志。
android:debuggable 属性通过 ADB 启用应用程序调试。对于 Google Play 中的发布版本,它必须为 false。如果发布版本中 debuggable=true,攻击者可以通过 ADB 连接到应用程序、读取数据并执行任意代码。Google Play 会自动阻止发布 debuggable=true 的构建。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。