Cuando una aplicación Android necesita acceder a componentes del hardware (como la cámara o el GPS) o a datos sensibles del usuario (contactos, archivos multimedia o notificaciones), el sistema operativo exige solicitar su consentimiento expreso. Este modelo de seguridad basado en permisos en tiempo de ejecución (runtime permissions) garantiza la privacidad y el control total por parte del usuario.
INTERNET o ACCESS_NETWORK_STATE) se conceden automáticamente al instalar la app. Los permisos peligrosos (como CAMERA, ACCESS_FINE_LOCATION o POST_NOTIFICATIONS) deben solicitarse dinámicamente en tiempo de ejecución.
Flujo Lógico: Cómo solicitar permisos correctamente
Para cumplir correctamente con las directrices de Google y no frustrar al usuario, sigue este flujo estándar:
1. Declarar el permiso en AndroidManifest.xml
Todo permiso que vaya a utilizarse debe figurar obligatoriamente en el archivo manifest antes de la etiqueta application.
2. Comprobar si ya está concedido
Mediante ContextCompat.checkSelfPermission verificamos el estado antes de invocar la funcionalidad.
3. Explicar el motivo si es necesario (Rationale)
Si el usuario ya lo rechazó una vez, shouldShowRequestPermissionRationale nos indica que debemos mostrar un mensaje contextual explicando por qué lo necesitamos.
4. Lanzar la petición con Activity Result API
Utilizamos el contrato oficial registerForActivityResult de AndroidX para escuchar la respuesta de forma limpia y desacoplada.

Implementación Moderna en Kotlin con Activity Result API
El método tradicional onRequestPermissionsResult ha quedado en desuso. La forma estándar y recomendada por Google en AndroidX es registrar un contrato mediante registerForActivityResult:
Paso 1: Declaración en AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Paso 2: Registrar el Launcher en tu Activity o Fragment
class MainActivity : AppCompatActivity() {
// Registramos el contrato de petición de permiso individual
private val requestCameraPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// El usuario concedió el permiso: abrir la cámara
abrirCamara()
} else {
// Permiso denegado: mostrar aviso amigable o guiar a ajustes
Toast.makeText(this, "Se necesita permiso de cámara para continuar", Toast.LENGTH_SHORT).show()
}
}
private fun verificarYSolicitarPermisoCamara() {
when {
// 1. ¿Ya tenemos el permiso concedido?
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED -> {
abrirCamara()
}
// 2. ¿Debemos mostrar una explicación previa al usuario?
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) -> {
// Mostrar un diálogo explicativo antes de solicitarlo de nuevo
mostrarDialogoExplicativo()
}
// 3. Solicitar directamente el permiso
else -> {
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
private fun abrirCamara() {
// Código para lanzar el Intent de captura o iniciar CameraX
}
}
Vídeo Tutorial Práctico: Cámara y GPS en Acción
En el siguiente vídeo de mi curso de Android te muestro cómo gestionar permisos tanto de cámara como de geolocalización GPS en un proyecto real:
Puedes clonar y revisar el código fuente completo en mi repositorio de GitHub: AndroidPermissions en GitHub.