Android中的Dangerous Permission:本质、权限列表和运行时请求

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

Dangerous Permission是Android中的一种权限类别,需要在应用程序运行期间通过运行时对话框获得用户的明确同意。根据Android Developer Guide, 2024危险权限具有ProtectionLevel dangerous,可以访问敏感数据:摄像头、麦克风、地理位置和联系人。未经用户明确同意,应用程序无法使用这些功能。

要点

  • Dangerous Permission — 具有ProtectionLevel dangerous的Android权限,需要运行时请求。
  • 请求通过ActivityCompat.requestPermissions执行,在onRequestPermissionsResult中处理。
  • 用户可以随时通过应用程序的设置撤销危险权限。
  • 在请求之前,需要通过ContextCompat.checkSelfPermission检查状态。
  • 列表包括CAMERA、RECORD_AUDIO、ACCESS_FINE_LOCATION、READ_CONTACTS等。

Android中的Dangerous Permission是什么

Dangerous Permission是Android系统权限的一个类别,提供对用户敏感数据的访问。与普通权限不同,危险权限不会在安装时自动授予——应用程序必须通过Android 6.0 Marshmallow(API 23)引入的运行时机制在运行时明确请求它们。

明确请求的必要性源于这些权限所保护的数据的性质:用户的地理位置、个人联系人、摄像头和麦克风内容、通话记录和短信。Android将这些数据视为敏感数据,并需要用户的知情同意。根据Android Privacy Sandbox(2024),用户平均拒绝约30%的运行时请求。

Dangerous Permission的关键特性——随时撤销的可能性。用户可以进入设置——应用程序——权限,切换任何危险权限的开关。应用程序必须准备好,已授予的权限可能随时被撤销而无需重启。

ProtectionLevel dangerous

dangerous保护级别在操作系统级别的系统权限定义中设置。当应用程序使用此类protectionLevel声明uses-permission时,系统将权限标记为需要运行时请求。与normal不同,dangerous权限始终显示在系统权限管理UI中,并且可以撤销。

Permission Group和Dangerous

所有危险权限根据功能特征分组到Permission Group中。例如,CAMERA和CAMERA2在CAMERA组中,ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION——在LOCATION组中。如果用户授予了组中的一个权限,同一组的其他权限将自动授予,无需额外对话框。

运行时请求如何工作

运行时请求是应用程序调用系统API以显示权限请求对话框的机制。用户看到一个包含权限名称和Allow和Deny按钮的模态窗口。响应后,系统使用结果调用onRequestPermissionsResult回调。

完整周期包括三个步骤:通过checkSelfPermission检查状态,在权限不存在时调用requestPermissions,以及在onRequestPermissionsResult中处理结果。状态检查是强制性的,因为用户可以随时通过设置撤销权限,未经检查调用函数将导致SecurityException

kotlin
fun checkAndRequestCameraPermission() {
    when {
        ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED -> {
            openCamera()
        }
        else -> {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.CAMERA),
                REQUEST_CAMERA_CODE
            )
        }
    }
}

结果处理在ActivityResultLauncher或onRequestPermissionsResult中进行。推荐的现代方法是使用ActivityResultContracts.RequestPermission,它提供了更干净的API,无需显式的请求代码。此合约返回Boolean——权限是否已授予。

最佳请求实践

严格在功能使用的上下文中请求危险权限,而不是在应用程序启动时。如果用户按下了摄像头按钮——请求CAMERA。如果打开了地图——请求LOCATION。上下文请求比首次启动时请求所有权限多获得两倍的授权。还建议一次不要请求超过一个权限,以便用户了解哪个功能需要访问。

Android中的危险权限列表

Android定义了几个危险权限组,每个组包含一到多个常量。最完整的列表在Manifest.permission类中。以下是开发中使用的主要组和权限。

Permission Group组权限访问API
CAMERACAMERACamera API, CameraX
LOCATIONACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATIONFusedLocationProvider, Geofence
MICROPHONERECORD_AUDIOMediaRecorder, AudioRecord
PHONEREAD_PHONE_STATE, CALL_PHONE, READ_CALL_LOGTelephonyManager
CONTACTSREAD_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTSContactsContract
SMSREAD_SMS, SEND_SMS, RECEIVE_SMSSmsManager
STORAGEREAD_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGEMediaStore, File API
CALENDARREAD_CALENDAR, WRITE_CALENDARCalendarContract

Android 12+中的新权限

从Android 12开始,谷歌加强了对某些权限的要求。例如,BLUETOOTH_CONNECT和BLUETOOTH_SCAN已变为危险权限,需要运行时请求。还出现了用于后台访问传感器的BODY_SENSORS_BACKGROUND权限。开发人员必须更新targetSdkVersion并在当前操作系统版本上测试请求。

Android 13+的权限

Android 13(API 33)为通知(POST_NOTIFICATIONS)和媒体文件(READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO)引入了新权限,取代了通用的READ_EXTERNAL_STORAGE。现在对照片、视频和音频的访问通过专门的权限单独请求,无需单一对话框。

Dangerous vs Normal Permission

Dangerous和Normal Permission在授予方式、撤销可能性和用户体验方面有根本区别。Normal在安装时自动授予,Dangerous需要显式的运行时对话框。Normal不能通过设置撤销,Dangerous可以随时关闭。这种不对称性导致了不同的开发模式。

从代码角度来看,危险权限需要更多工作:checkSelfPermission、requestPermissions、拒绝处理。对于Normal来说,AndroidManifest.xml中的一行就足够了。同时,Dangerous Permission给用户控制权,这增加了信任,特别是对于摄像头或地理位置等敏感功能。

类别之间的选择不在开发人员面前——由系统决定。开发人员仅声明uses-permission,系统根据protectionLevel确定类别。然而,危险权限的请求策略会影响用户体验:频繁或不适当的对话框会降低应用程序的评级。

如何在Kotlin中请求权限

现代方法在Kotlin中请求权限——使用ActivityResultContracts.RequestMultiplePermissions或RequestPermission。这些合约属于androidx.activity库,提供基于lambda的干净API,无需覆盖onRequestPermissionsResult。

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

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

同时请求多个权限

当应用程序需要同时多个危险权限时,使用RequestMultiplePermissions。合约返回Map<String, Boolean>,其中键是权限名称,值是结果。这在首次启动时需要请求CAMERA和RECORD_AUDIO进行视频录制时很方便。

首次拒绝的处理

如果用户拒绝了请求,shouldShowRequestPermissionRationale方法返回true。这是显示解释为何需要权限的信号。最佳实践——显示带有解释和重试按钮的自定义对话框。如果用户勾选了Never Ask Again并再次拒绝了请求,shouldShowRequestPermissionRationale将返回false,需要重定向到设置。

拒绝处理和Never Ask Again

Never Ask Again是用户在再次拒绝运行时对话框时可以设置的标志。之后,标准对话框窗口不再为此权限显示。提供访问的唯一方法——将用户重定向到系统应用程序设置。

开发人员需要区分两种拒绝场景:第一种——当shouldShowRequestPermissionRationale返回true时(用户拒绝了,但对话框仍然可以显示);第二种——当方法返回false时(Never Ask Again已激活或权限被策略阻止)。在第二种情况下,应显示打开设置按钮。

kotlin
fun handlePermissionDenied(permission: String) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(
            this, permission
    )) {
        showRationaleDialog(permission)
    } else {
        showSettingsRedirectDialog(permission)
    }
}

private fun showSettingsRedirectDialog(permission: String) {
    AlertDialog.Builder(this)
        .setTitle("访问被拒绝")
        .setMessage(
            "权限已被阻止。请打开设置。"
        )
        .setPositiveButton("设置") { _, _ ->
            val intent = Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                Uri.fromParts(
                    "package", packageName, null
                )
            )
            startActivity(intent)
        }
        .show()
}

重要的是,如果shouldShowRequestPermissionRationale返回了false,不要再次请求权限。在这种情况下重复调用requestPermissions不会显示对话框——结果会立即返回DENIED,没有解释。用户将遇到不可理解的行为,这将对应用程序的使用体验产生负面影响。

常见问题

Android中哪些权限被认为是危险的?

Dangerous Permission包括具有ProtectionLevel dangerous的权限:CAMERA、RECORD_AUDIO、ACCESS_FINE_LOCATION、READ_CONTACTS、READ_SMS、READ_CALENDAR等。完整列表在Manifest.permission类中。

如何检查危险权限是否已授予?

使用ContextCompat.checkSelfPermission,传递上下文和权限名称。该方法返回PERMISSION_GRANTED或PERMISSION_DENIED。每次调用需要危险权限的API之前都应进行检查。

危险权限的Permission Group是什么?

Permission Group将相关的危险权限分组。如果用户授予了组中的一个权限,其他权限将自动授予。例如,LOCATION包括ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION。

如何处理Never Ask Again?

拒绝后检查shouldShowRequestPermissionRationale。如果该方法返回false且权限仍未授予——表示Never Ask Again已激活。通过带有ACTION_APPLICATION_DETAILS_SETTINGS的Intent将用户重定向到设置。

Android 13+上需要危险权限吗?

是的,它们仍然是必需的。在Android 13+上,一些权限发生了变化:POST_NOTIFICATIONS成为了单独的运行时权限,READ_EXTERNAL_STORAGE被READ_MEDIA_IMAGES取代,用于精确访问媒体文件。

总结

  • Dangerous Permission — 具有ProtectionLevel dangerous的Android权限,需要用户的显式运行时请求。
  • 机制包括三个步骤:checkSelfPermission、requestPermissions和onRequestPermissionsResult。
  • 用户可以随时通过系统设置撤销危险权限。
  • 主要组:CAMERA、LOCATION、MICROPHONE、PHONE、CONTACTS、SMS、STORAGE、CALENDAR。
  • ActivityResultContracts.RequestPermission — 在Kotlin中无需请求代码的现代请求API。
  • ShouldShowRequestPermissionRationale有助于区分首次拒绝和Never Ask Again。
  • 在Android 13+上出现了新权限:POST_NOTIFICATIONS和READ_MEDIA_IMAGES取代STORAGE。

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

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

讨论项目

另请阅读