Dangerous Permission es una categoría de permisos en Android que requieren el consentimiento explícito del usuario a través de un diálogo en tiempo de ejecución mientras la aplicación se está ejecutando. Según la Guía para desarrolladores de Android, 2024, los permisos peligrosos tienen ProtectionLevel dangerous y otorgan acceso a datos confidenciales: cámara, micrófono, ubicación y contactos. Sin el consentimiento explícito del usuario, la aplicación no puede usar estas funciones.
Puntos clave
Dangerous Permission es una categoría de permisos del sistema Android que otorgan acceso a datos confidenciales del usuario. A diferencia de los permisos normales, los permisos peligrosos no se otorgan automáticamente durante la instalación: la aplicación debe solicitarlos explícitamente en tiempo de ejecución mediante el mecanismo introducido en Android 6.0 Marshmallow (API 23).
La necesidad de una solicitud explícita se debe a la naturaleza de los datos que protegen estos permisos: ubicación del usuario, contactos personales, contenido de la cámara y el micrófono, historial de llamadas y SMS. Android considera estos datos como sensibles y exige que el usuario otorgue el acceso de forma consciente. Según Android Privacy Sandbox (2024), los usuarios rechazan aproximadamente el 30 por ciento de las solicitudes en tiempo de ejecución en promedio.
Una característica clave de Dangerous Permission es la posibilidad de revocarlo en cualquier momento. El usuario puede ir a Configuración — Aplicaciones — Permisos y desactivar cualquier permiso peligroso. La aplicación debe estar preparada para que un permiso que fue otorgado pueda ser revocado en cualquier momento sin reinicio.
El nivel de protección dangerous se define en las definiciones del sistema de permisos a nivel del SO. Cuando una aplicación declara uses-permission con este protectionLevel, el sistema marca el permiso como que requiere una solicitud en tiempo de ejecución. A diferencia de normal, los permisos dangerous siempre se muestran en la interfaz de gestión de permisos del sistema y pueden ser revocados.
Todos los permisos peligrosos se agrupan en Permission Groups por categoría funcional. Por ejemplo, CAMERA y CAMERA2 están en el grupo CAMERA, ACCESS_FINE_LOCATION y ACCESS_COARSE_LOCATION están en el grupo LOCATION. Si un usuario ha otorgado un permiso de un grupo, los permisos restantes del mismo grupo se otorgan automáticamente sin un diálogo adicional.
La solicitud en tiempo de ejecución es un mecanismo mediante el cual la aplicación llama a una API del sistema para mostrar un diálogo de solicitud de permiso. El usuario ve una ventana modal con el nombre del permiso y los botones Permitir y Denegar. Después de la respuesta, el sistema llama al callback onRequestPermissionsResult con el resultado.
El ciclo completo incluye tres pasos: verificar el estado mediante checkSelfPermission, llamar a requestPermissions si el permiso no está otorgado y manejar el resultado en onRequestPermissionsResult. La verificación del estado es obligatoria porque el usuario puede haber revocado el permiso en cualquier momento a través de la configuración, y llamar a una función sin verificar provocará una SecurityException.
fun checkAndRequestCameraPermission() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else -> {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_CODE
)
}
}
}
El manejo del resultado ocurre en ActivityResultLauncher u onRequestPermissionsResult. El enfoque moderno recomendado es usar ActivityResultContracts.RequestPermission, que proporciona una API más limpia sin códigos de solicitud explícitos. Este contrato devuelve un Boolean — si el permiso fue otorgado o no.
Solicite permisos peligrosos estrictamente en el contexto del uso de la función, no al iniciar la aplicación. Si el usuario presionó el botón de la cámara — solicite CAMERA. Si abrió un mapa — solicite LOCATION. Las solicitudes contextuales generan el doble de concesiones que solicitar todos los permisos al primer inicio. También se recomienda no solicitar más de un permiso a la vez para que el usuario entienda qué función requiere acceso.
Android define varios grupos de permisos peligrosos, cada uno contiene una o más constantes. La lista más completa está disponible en la clase Manifest.permission. A continuación se presentan los principales grupos y permisos utilizados en el desarrollo.
| Grupo Permission Group | Permisos | API de acceso |
|---|---|---|
| CAMERA | CAMERA | Camera API, CameraX |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | FusedLocationProvider, Geofence |
| MICROPHONE | RECORD_AUDIO | MediaRecorder, AudioRecord |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | TelephonyManager |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | ContactsContract |
| SMS | READ_SMS, SEND_SMS, RECEIVE_SMS | SmsManager |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | MediaStore, File API |
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | CalendarContract |
A partir de Android 12, Google ha endurecido los requisitos para algunos permisos. Por ejemplo, BLUETOOTH_CONNECT y BLUETOOTH_SCAN se han vuelto peligrosos y requieren una solicitud en tiempo de ejecución. También se agregó el permiso BODY_SENSORS_BACKGROUND para acceso en segundo plano a sensores. Los desarrolladores deben actualizar targetSdkVersion y probar las solicitudes en las versiones actuales del SO.
Android 13 (API 33) introdujo nuevos permisos para notificaciones (POST_NOTIFICATIONS) y archivos multimedia (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO), reemplazando el READ_EXTERNAL_STORAGE general. Ahora el acceso a fotos, videos y audio se solicita por separado mediante permisos especializados sin un diálogo único.
Los permisos Dangerous y Normal difieren fundamentalmente en la forma de concesión, la posibilidad de revocación y su UX. Normal se otorga automáticamente durante la instalación, Dangerous requiere un diálogo explícito en tiempo de ejecución. Normal no se puede revocar a través de la configuración, Dangerous se puede desactivar en cualquier momento. Esta asimetría crea diferentes patrones de desarrollo.
Desde la perspectiva del código, los permisos peligrosos requieren más trabajo: checkSelfPermission, requestPermissions, manejo de denegación. Para los normales, basta con una línea en AndroidManifest.xml. Sin embargo, Dangerous Permission le da control al usuario, lo que aumenta la confianza, especialmente para funciones sensibles como la cámara o la ubicación.
La elección entre categorías no depende del desarrollador — la determina el sistema. El desarrollador solo declara uses-permission, y el sistema determina la categoría según protectionLevel. Sin embargo, la estrategia de solicitud de permisos peligrosos afecta la experiencia del usuario: los diálogos frecuentes o inapropiados reducen la calificación de la aplicación.
La forma moderna de solicitar permisos en Kotlin es usar ActivityResultContracts.RequestMultiplePermissions o RequestPermission. Estos contratos forman parte de la biblioteca androidx.activity y proporcionan una API limpia basada en lambdas, sin necesidad de sobrescribir onRequestPermissionsResult.
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
)
}
}
}
Cuando una aplicación necesita varios permisos peligrosos simultáneamente, use RequestMultiplePermissions. El contrato devuelve Map<String, Boolean> donde la clave es el nombre del permiso y el valor es el resultado. Esto es útil en el primer inicio cuando necesita solicitar CAMERA y RECORD_AUDIO para grabación de video.
Si el usuario deniega la solicitud, el método shouldShowRequestPermissionRationale devuelve true. Esto indica que debe mostrar una explicación de por qué se necesita el permiso. La mejor práctica es mostrar un diálogo personalizado con una explicación y un botón Reintentar. Si el usuario vuelve a denegar la solicitud con la casilla Never Ask Again marcada, shouldShowRequestPermissionRationale devolverá false, y debe redirigir a Configuración.
Never Ask Again es una bandera que el usuario puede activar al rechazar el diálogo de tiempo de ejecución por segunda vez. Después de esto, el diálogo estándar ya no se muestra para ese permiso. La única forma de otorgar acceso es redirigir al usuario a la configuración del sistema de aplicaciones.
El desarrollador debe distinguir entre dos escenarios de denegación: primero, cuando shouldShowRequestPermissionRationale devuelve true (el usuario rechazó pero el diálogo aún se puede mostrar), y segundo, cuando el método devuelve false (Never Ask Again está activo o el permiso está bloqueado por política). En el segundo caso, debe mostrar un botón Abrir Configuración.
fun handlePermissionDenied(permission: String) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
)) {
showRationaleDialog(permission)
} else {
showSettingsRedirectDialog(permission)
}
}
private fun showSettingsRedirectDialog(permission: String) {
AlertDialog.Builder(this)
.setTitle("Acceso denegado")
.setMessage(
"Permiso bloqueado. Abra Configuración."
)
.setPositiveButton("Configuración") { _, _ ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package", packageName, null
)
)
startActivity(intent)
}
.show()
}
Es importante no solicitar el permiso nuevamente si shouldShowRequestPermissionRationale devolvió false. Una llamada repetida a requestPermissions en este caso no mostrará un diálogo — el resultado llegará inmediatamente con DENIED sin explicación. El usuario se encontrará con un comportamiento confuso, lo que afecta negativamente la experiencia de uso de la aplicación.
Preguntas frecuentes
Los Dangerous Permission incluyen permisos con ProtectionLevel dangerous: CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, READ_CONTACTS, READ_SMS, READ_CALENDAR y otros. La lista completa está disponible en la clase Manifest.permission.
Use ContextCompat.checkSelfPermission, pasando el contexto y el nombre del permiso. El método devuelve PERMISSION_GRANTED o PERMISSION_DENIED. La verificación debe realizarse antes de cada llamada a la API que requiera un permiso peligroso.
Un Permission Group agrupa permisos peligrosos relacionados. Si un usuario otorga un permiso de un grupo, los demás se otorgan automáticamente. Por ejemplo, LOCATION incluye ACCESS_FINE_LOCATION y ACCESS_COARSE_LOCATION.
Verifique shouldShowRequestPermissionRationale después de la denegación. Si el método devuelve false y el permiso aún no está otorgado — Never Ask Again está activo. Redirija al usuario a Configuración mediante Intent con ACTION_APPLICATION_DETAILS_SETTINGS.
Sí, siguen siendo obligatorios. En Android 13+, algunos permisos cambiaron: POST_NOTIFICATIONS se convirtió en un permiso de tiempo de ejecución separado, y READ_EXTERNAL_STORAGE fue reemplazado por READ_MEDIA_IMAGES para acceso granular a archivos multimedia.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también