Runtime Permission:实质、类型及在Android中的工作原理

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

Runtime Permission — 一种在应用程序运行时请求权限的机制,于 Android 6.0(API 23)中引入。与在安装时设置权限不同,runtime permissions 允许用户随时授予或撤销对敏感数据(相机、地理位置、联系人)的访问权限。根据 Android Developers (2026),Google Play 中超过 85% 的应用至少使用一个 runtime permission。

要点

  • Runtime Permission — Android 机制,要求用户明确同意才能访问敏感数据。
  • Dangerous permissions — 需要运行时请求的权限组(相机、麦克风、地理位置、联系人)。
  • Normal permissions — 由系统自动批准,无需运行时请求(INTERNET、ACCESS_NETWORK_STATE)。
  • One-time permissions — 一次性会话权限,在 Android 11 中引入,应用关闭时自动撤销。
  • shouldShowRequestPermissionRationale — 标志,指示在请求前是否应向用户显示解释。

什么是 Runtime Permission?

Runtime Permission(运行时权限)是一种 Android 安全模型,应用在用户真正需要某项功能时才请求访问敏感数据。在 Android 6.0 之前,所有权限在安装应用时提供,用户无法在不完全卸载应用的情况下撤销权限。

Android 权限模型的演变

Android 6.0 之前,用户在安装时会看到所有权限列表,可以选择全部同意或拒绝安装。2015 年的一项研究表明,87% 的用户在安装时不会阅读权限列表。Android 6.0 引入了 runtime permissions,将权限分为 normal(自动)和 dangerous(需要请求)。Android 11 增加了 one-time permissions — 应用关闭后自动撤销。Android 13 引入了 Photo Picker 并将推送通知作为独立的 runtime permissions。

iOS 从 iOS 10 开始使用类似的模型,在首次访问相机、麦克风和地理位置时请求权限。然而,iOS 没有「normal permissions」的概念 — 每个权限都明确请求,拒绝后保留,直到开发者通过系统设置再次请求。

Runtime Permission 在 Android 中如何工作?

Runtime Permission 通过系统对话框工作,由 requestPermissions() 方法(AndroidX 中为 ActivityResultLauncher)调用。系统显示带有解释的标准对话框,用户选择「允许」或「拒绝」。用户响应后,回调结果,应用处理用户的决定。

通过 ActivityResultLauncher 请求权限

kotlin
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>

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

    requestPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
            if (isGranted) {
                startCamera()
            } else {
                showPermissionDeniedDialog()
            }
        }
}

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

shouldShowRequestPermissionRationale 方法在用户已拒绝过一次请求时返回 true。在这种情况下,建议显示一个解释对话框,说明应用为何需要该权限,然后再次请求。这可将用户同意概率提高 30–40%(根据 Google I/O 2024 数据)。

Android 中的权限类型

Android 将所有权限分类为几个保护级别:normal、dangerous、signature 和 special。Normal permissions 在安装时自动授予。Dangerous permissions 需要运行时请求。Signature permissions 仅对使用相同证书签名的应用可用。

危险权限组

权限API Level
CAMERACAMERAAPI 23+
LOCATIONACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATIONAPI 23+ (background — API 29+)
STORAGEREAD_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, READ_MEDIA_IMAGES (API 33+)API 23+ (API 33 中的变更)
PHONEREAD_PHONE_STATE, CALL_PHONE, READ_CALL_LOGAPI 23+
MICROPHONERECORD_AUDIOAPI 23+
CONTACTSREAD_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTSAPI 23+
NOTIFICATIONSPOST_NOTIFICATIONSAPI 33+

Special permissions(SYSTEM_ALERT_WINDOW、WRITE_SETTINGS、MANAGE_EXTERNAL_STORAGE)需要通过 Settings.ACTION_MANAGE_OVERLAY_PERMISSION 额外跳转到系统设置。这些权限无法通过标准系统对话框请求,需要用户明确转到设置屏幕。

Android 12+ 中的权限请求

Android 12 引入了 runtime permissions 模型的重大变化。One-time permissions 允许仅在一次会话中授予对相机、麦克风或地理位置的访问权限。用户关闭应用后,权限自动撤销。Privacy indicators — 状态栏中的绿色指示器,显示应用何时使用相机或麦克风。

处理一次性权限

kotlin
// Android 12+ — 处理一次性地理位置权限
private fun checkLocationPermission() {
    val permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->

        val fineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION]
        val coarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION]

        if (fineLocationGranted == true) {
            showUserLocation()
        } else {
            showLocationDisabledDialog()
        }
    }

    permissionLauncher.launch(
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
}

// 检查权限是否被系统撤销(Android 12+)
class PermissionReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == Intent.ACTION_PERMISSION_REVOCATION) {
            handleRevokedPermission(intent.getStringExtra(Intent.EXTRA_REVOKED_PERMISSION))
        }
    }
}

Android 13POST_NOTIFICATIONS 权限添加到 dangerous 组,要求明确请求才能发送推送通知。Android 14 引入了后台地理位置限制:应用每次请求 background location 时必须获得用户的明确批准。Photo Picker(API 33+)取代了选择图片时对 READ_EXTERNAL_STORAGE 的需求。

处理用户拒绝

用户拒绝授予权限是正常情况,需要正确处理。有两种类型的拒绝:一次性(用户点击了「拒绝」)和永久性(用户选择了「不再询问」)。在第二种情况下,系统对话框不再显示,应用必须将用户重定向到系统设置。

拒绝处理策略

第一次拒绝后,应用应显示一个 rationale dialog — 自行解释为何需要该权限。如果用户再次拒绝,应通过 Settings.ACTION_APPLICATION_DETAILS_SETTINGS 将用户重定向到应用设置界面。Material 3 建议使用 PermissionRequestBottomSheet 以获得更自然的用户体验。

重要的是不要在拒绝时完全阻止应用功能。例如,如果用户拒绝了地理位置,应用应提供手动输入地址的方式。对于相机 — 允许从图库加载图片。Google 建议始终为所有 runtime permissions 提供备用机制。

安全建议

Runtime permissions 不仅是技术机制,也是用户对应用信任的要素。在不合适的时机请求权限(例如,首次启动时)会显著降低同意概率。Google Play Store 分析权限请求的频率和上下文:激进请求的应用在搜索结果中排名较低。

权限请求规则

上下文 — 在执行需要权限的操作之前立即请求。最小化 — 仅请求功能真正需要的权限。透明 — 在系统对话框之前向用户解释为何需要该权限。撤销 — 订阅 ACTION_PERMISSION_REVOCATION 以正确处理运行时的权限撤销。

要测试 runtime permissions,请使用 adb 命令:adb shell pm revoke <package> android.permission.CAMERA 可以在不重新安装应用的情况下模拟权限撤销。EspressoUiAutomator 通过 GrantPermissionRule 支持测试权限对话框。将这些工具集成到 CI/CD 流水线中对于包含 runtime permissions 的应用是必需的。

Google Play Console 中的权限审计

Google Play Console 提供 Permission auditing(权限审计)部分,开发者可以查看权限请求的频率、提供访问权限的用户百分比以及哪些权限被撤销。分析这些数据有助于识别低效的请求并优化用户体验。例如,如果不到 40% 的用户提供地理位置,则需要重新考虑请求时机并添加更具说服力的 rationale。

使用 Android Vitals 监控与权限相关的 ANR(Application Not Responding)也至关重要。如果权限请求在主线程上执行或系统对话框阻塞了 UI,可能会在慢速设备上导致 ANR。将权限检查和请求移到单独的线程或使用 Kotlin 协程进行异步处理,以避免阻塞用户界面。

常见问题

如何区分一次性拒绝和永久性拒绝?

shouldShowRequestPermissionRationale 在永久性拒绝时返回 false(当用户选择了「不再询问」时)。该方法在一次性拒绝时返回 true,允许显示 rationale 对话框。如果方法返回了 false,唯一的办法是将用户重定向到应用的系统设置。

可以同时请求多个权限吗?

可以,ActivityResultContracts.RequestMultiplePermissions 允许一次调用请求一组权限。系统将依次为每个权限显示对话框。建议将逻辑相关的权限分组(例如,CAMERARECORD_AUDIO 用于视频录制),但一次不要请求超过 2–3 个。

Runtime permissions 在 Android TV 和 Wear OS 上如何工作?

Android TV 使用相同的 runtime permissions 模型,对话框显示在电视屏幕上。Wear OS 3+ 版本支持 runtime permissions,但对话框显示在手表上。对于 Android Auto,所有权限在手机上请求,车载系统通过 bridge 连接获取已批准的权限。

Android 16 中权限方面有哪些预期变化?

根据初步信息,Android 16 将引入一次性权限的「权限过期」机制,24 小时后自动撤销。同时预计将收紧对 background location 的要求,并扩展 dangerous permissions 列表以涵盖新类别(环境传感器、Wi-Fi 扫描)。具体细节将在 2027 年 Q3 公布。

Android 的 runtime permission 与 iOS 有何不同?

iOS 不支持「normal permissions」— 每个权限通过系统对话框明确请求。用户可以随时通过设置撤销权限。主要区别在于 iOS 不会通过类似 checkSelfPermission 的方式预先检查权限状态:系统在首次访问受保护 API 时自动显示对话框。

总结

  • Runtime Permission — 在实际使用敏感数据时请求访问的机制,于 Android 6.0 中引入。
  • Dangerous permissions 需要明确的系统对话框,normal permissions 自动批准。
  • One-time permissions(Android 12+)在应用关闭时撤销,提高用户隐私。
  • shouldShowRequestPermissionRationale 确定之前是否有拒绝,帮助选择请求策略。
  • Android 13POST_NOTIFICATIONS 添加为 runtime permission,Android 14 加强了对后台地理位置的要求。
  • Photo Picker(API 33+)取代了选择图片时对 READ_EXTERNAL_STORAGE 的需求。
  • 始终在用户拒绝时提供备用方案 — 替代输入数据的方式或手动选择。

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

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

讨论项目

另请阅读