AndroidManifest Permissions:关键概念、声明和权限类型

作者: IT Sectr 发布日期: 2026-05-21 阅读时间: 10 分钟

AndroidManifest Permissions 是 AndroidManifest.xml 文件中的权限声明,用于确定应用程序可以访问哪些系统资源和数据。Android 要求在使用相应 API 之前,必须在清单中声明每个权限:从相机和地理位置到发送短信和访问联系人。根据 Android Developer Documentation每个权限都分为四个保护级别之一:normal、dangerous、signature 和 special。

要点

  • AndroidManifest.xml — 包含应用所有权限声明的清单文件
  • 保护级别 — normal、dangerous、signature、special,具有不同的请求机制
  • Runtime Permission — dangerous 权限需要在运行时请求(Android 6+)
  • 声明与请求 — 清单中的声明是强制性的,但 dangerous 需要在代码中额外请求
  • — 权限被分组,同意一个即可访问整个组

什么是 AndroidManifest Permissions?

AndroidManifest Permissions 是 Android 的安全机制,用于控制应用对受保护数据和系统功能的访问。每个应用必须使用 <uses-permission> 元素在 AndroidManifest.xml 文件中声明所需的权限。如果不声明,调用相应的 API 将以安全错误 SecurityException 告终。

Android 的权限模型经历了几个发展阶段。在 Android 6.0(API 23)之前,所有权限都在安装时授予 — 用户看到完整列表并同意或拒绝安装应用。从 Android 6.0 开始,dangerous 级别的权限在运行时(Runtime Permissions)请求,为用户提供更灵活的控制。

权限分为四个保护级别:normal(安装时自动授予)、dangerous(需要运行时请求)、signature(仅对使用相同证书签名的应用可用)和 special(需要在设置中单独启用)。每个级别都有自己的授予和撤销机制。

根据 Google I/O 2024 的信息,Android 15 计划引入更细粒度的权限 — 用户可以只授予对媒体库中特定文件的访问权限,而不是整个库。这延续了 Android 默认情况下最小化提供数据量的趋势。

与 iOS 权限模型的区别

与所有权限都在运行时请求的 iOS 不同,Android 将权限分为安装时(install-time)和运行时(runtime)。normal 级别在安装时自动授予,无需通知用户。dangerous 级别需要明确的对话框,就像在 iOS 中一样。

另一个区别:在 Android 中,权限被分组为(permission groups)。如果用户同意访问相机,应用会自动获得麦克风的访问权限 — 它们属于同一个 MICROPHONE 组。在 iOS 中,每个权限都独立于组单独请求。

各 Android 版本的权限演变

Android 版本权限模型的变化
Android 1.0–5.x所有权限在安装时授予(install-time)
Android 6.0(API 23)为 dangerous 级别引入 Runtime Permissions
Android 10(API 29)Scoped Storage — 限制对文件系统的访问
Android 11(API 30)权限自动重置 — 未使用的权限被重置
Android 14(API 34)媒体访问的运行时权限(照片、视频、音频)

有哪些类型的权限

Android 为权限定义了四个保护级别(protection levels),每个级别都有自己的授予规则。让我们详细查看每个级别。

Normal Permissions(安装时)

Normal 权限在安装应用时自动授予,无需通知或请求用户。它们涵盖对低风险功能的访问,这些功能不会威胁用户隐私:INTERNET、ACCESS_NETWORK_STATE、VIBRATE、BLUETOOTH。用户看不到同意对话框 — 权限被视为通过安装事实而授予。

开发人员无需为 normal 权限在代码中处理请求 — 只需在清单中声明即可。但是,在 Android 12+ 中从 Google Play 安装时,用户会看到 “权限” 选项卡,其中列出了所有 normal 权限,这提高了透明度。根据 Statista(2024) 的数据,Google Play 中超过 90% 的应用都使用 INTERNET 作为最常见的 normal 权限。

Dangerous Permissions(运行时)

Dangerous 权限涵盖对可能侵犯隐私的数据和功能的访问:相机、麦克风、地理位置、联系人、短信、电话、日历、身体传感器。这些权限需要两步机制:在清单中声明 + 通过 ActivityCompat.requestPermissions() 在运行时请求。

用户可以拒绝授予 dangerous 权限,应用必须正确处理此场景。在 Android 11+ 中,如果用户两次拒绝,后续请求不会显示系统对话框 — 系统自动返回 DENIED。在这种情况下,需要将用户引导至设置。

Signature 和 Special Permissions

Signature 级别 — 如果应用与系统或定义权限的其他应用使用相同的证书签名,则权限会自动授予。用于系统和企业应用。示例:BIND_ACCESSIBILITY_SERVICE — 仅系统应用可用。

Special 级别(SYSTEM_ALERT_WINDOW、WRITE_SETTINGS、REQUEST_INSTALL_PACKAGES、MANAGE_EXTERNAL_STORAGE) — 需要用户通过系统设置单独操作。应用可以使用 Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)打开设置页面。Google Play 限制使用 special 权限,并在发布时要求在表单中提供理由。

Runtime Permission:处理 dangerous 权限

从 Android 6.0 开始,所有 dangerous 权限都需要在运行时请求。让我们看看在 Kotlin 中使用运行时权限的完整工作流程。

检查和请求权限

在调用需要 dangerous 权限的 API 之前,始终通过 ContextCompat.checkSelfPermission() 检查当前状态。如果状态为 PERMISSION_GRANTED — 可以调用 API。如果为 PERMISSION_DENIED — 需要通过 ActivityResultContract RequestPermission(AndroidX)或已弃用的 requestPermissions() 请求权限。

建议使用 ActivityResultContracts.RequestMultiplePermissions 同时请求多个权限。Google 建议将相关权限(例如,用于录制视频的相机 + 麦克风)分组到一个对话框中,以便用户看到请求的完整上下文。

kotlin
import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat

class CameraActivity : AppCompatActivity() {
    private val requestPermissionLauncher =
        registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted: Boolean ->
            if (isGranted) {
                openCamera()
            } else {
                explainWhyPermissionNeeded()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        checkCameraPermission()
    }

    private fun checkCameraPermission() {
        when {
            ContextCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED -> {
                openCamera()
            }
            shouldShowRequestPermissionRationale(
                Manifest.permission.CAMERA
            ) -> {
                showRationale()
            }
            else -> {
                requestPermissionLauncher.launch(
                    Manifest.permission.CAMERA
                )
            }
        }
    }
}

处理 “不再询问” 拒绝

如果用户两次拒绝权限,Android 将请求转为 “Never ask again” 状态。在这种情况下,shouldShowRequestPermissionRationale() 返回 false,系统对话框将不会显示。应用必须通过 Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)将用户引导至系统设置。

重要提示:不要在第一次拒绝后立即显示建议打开设置的对话框 — 这被视为攻击性行为。使用 shouldShowRequestPermissionRationale() 来确定是否需要显示解释。Material Design 指南建议显示一个包含访问价值解释的屏幕,而不仅仅是一个 “打开设置” 按钮。

kotlin
private fun openAppSettings() {
    Intent(
        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", packageName, null)
    ).also { intent ->
        startActivity(intent)
    }
}

private fun showPermissionSettings() {
    AlertDialog.Builder(this)
        .setTitle("相机访问权限")
        .setMessage("请在设置中允许相机访问权限,"
            + "以便拍摄个人资料照片")
        .setPositiveButton("打开设置") { _, _ ->
            openAppSettings()
        }
        .setNegativeButton("取消", null)
        .show()
}

在 AndroidManifest.xml 中声明权限

AndroidManifest.xml 文件包含应用使用的每个权限的 <uses-permission> 元素。权限在 <manifest> 级别、<application> 元素之前声明。

声明语法

每个权限都声明为一个单独的 <uses-permission> 元素,带有 android:name 属性,指示权限的完整名称。对于在特定 Android 版本中出现的权限,使用 maxSdkVersion 属性将声明限制为仅需要的版本 — 这提高了兼容性。

例如,WRITE_EXTERNAL_STORAGE 权限在 Android 10+(Scoped Storage)上不需要,因此指定 maxSdkVersion=“28”(Android 9)。这可以防止在新版本上来自用户的不必要问题。Android Studio 通过 Lint 警告推荐的 maxSdkVersion。

xml
<!-- AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Normal permissions (install-time) -->
    <uses-permission
        android:name="android.permission.INTERNET" />
    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- Dangerous permissions (runtime) -->
    <uses-permission
        android:name="android.permission.CAMERA" />
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!-- Legacy storage permission limited to API 28 and below -->
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28" />

    <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />

    <application>
        <!-- ... -->
    </application>
</manifest>

使用 <uses-feature> 进行过滤

<uses-feature> 元素指定应用需要特定的硬件(相机、GPS、NFC)。android:required=“false” 属性允许在没有此硬件的设备上安装应用 — 可用性检查在代码中执行。如果 required=“true”,Google Play 会过滤应用,使其不适用于不合适的设备。

建议对所有硬件功能设置 required=“false”,并通过 PackageManager.hasSystemFeature() 以编程方式检查可用性。这可以扩展应用的受众。唯一的例外是当功能对应用运行至关重要时(没有 GPS 的出租车订车应用没有意义)。

最佳实践和常见错误

正确处理权限是 Android 应用质量的关键方面。让我们看看主要建议和典型错误。

最小化请求的权限

仅请求应用运行真正需要的权限。每个额外的权限都会降低安装转化率并增加拒绝数量。Google Play Console 显示有多少用户因权限集而放弃安装。根据 AppBrain(2024) 的数据,具有 10+ dangerous 权限的应用的安装量少 35%。

定期审查权限列表。删除未使用的权限,尤其是在过渡到某些权限变为可选的较新 Android 版本时。例如,随着 Android 13+ 中照片选择器(ActivityResultContracts.PickVisualMedia)的出现,无需 dangerous 权限 READ_MEDIA_IMAGES 即可访问媒体库。

在请求前显示解释

在请求 dangerous 权限之前,向用户显示一个屏幕,解释为什么需要此权限及其提供的价值。Material Design 建议使用带有图标、简短文字和 “继续” 按钮的底部导航栏或对话框。与直接请求相比,解释可将同意率提高 20–30%。

在调用 launch() 之前检查 shouldShowRequestPermissionRationale()。如果为 true — 显示解释。如果为 false — 要么权限已授予,要么用户已永久拒绝(never ask again)。在后一种情况下,显示 “打开设置” 按钮,不要重复请求。

测试所有权限场景

测试所有可能的场景:授予权限、拒绝、永久拒绝、在设置中撤销权限、重置权限(Android 11+ 自动重置)。每个场景都必须处理,不会崩溃且不会丢失数据。Android 测试指南建议使用 TestPermission 库来自动化测试。

特别注意用户在应用运行时撤销权限的场景(最小化应用 → 设置 → 撤销)。返回应用时,通过 onResume() 重新检查所有权限。不要依赖权限状态的缓存 — 用户可以随时更改它们。

典型错误

  • 未事先检查 checkSelfPermission 就请求权限 — 会导致不必要的对话框
  • 忽略 shouldShowRequestPermissionRationale — 在第一次拒绝后恶化用户体验
  • 没有上下文的权限请求(仅 “允许访问?”) — 降低同意率
  • 在 Android 10+ 上使用 WRITE_EXTERNAL_STORAGE 而没有 maxSdkVersion — 不必要的请求
  • 在 onResume 中缺少权限检查 — 错过在设置中撤销权限

常见问题

如果 SDK 请求权限,是否需要声明?

是的,如果 SDK 在其清单中包含权限,则在构建时会合并到应用的清单中。您可以使用 AndroidManifest.xml 中的 tools:node=“remove” 禁用 SDK 的不必要权限。

如果不处理权限拒绝会发生什么?

在没有权限的情况下调用 API 会导致 SecurityException,从而导致应用崩溃。在使用相应 API 之前始终检查权限状态,并正确处理拒绝。

如何在开发过程中重置权限?

在设备设置中:设置 → 应用 → [您的应用] → 权限。要重置所有权限,请使用 adb 命令:adb shell pm reset-permissions

可以在没有 Activity 的情况下请求权限吗?

可以,使用 Fragment 或 Service 中的 ActivityResultLauncher。但是,请求对话框始终需要 Activity 的 UI 上下文。对于 Service,您可以显示带有 Intent 的通知,该 Intent 打开包含请求的 Activity。

为什么权限需要 maxSdkVersion?

例如,WRITE_EXTERNAL_STORAGE 在 Android 10+(Scoped Storage)上不需要。通过指定 android:maxSdkVersion=“28”,您排除了在新版本上的权限声明,这提高了兼容性并减少了请求的权限列表。

总结

  • AndroidManifest Permissions — Android 中对系统资源的强制访问声明
  • 4 个保护级别 — normal、dangerous、signature、special,具有不同的授予机制
  • Runtime Permissions — dangerous 权限需要在运行时请求(Android 6+)
  • 权限组 — 同意组中的一个权限即可访问组中的所有权限
  • 解释说明 — 在请求前显示解释可将同意率提高 20–30%
  • 最小化 — 仅请求必要的权限并使用 maxSdkVersion
  • 在调用 API 之前始终检查权限状态,并处理所有拒绝场景

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读