shouldShowRequestPermissionRationale es un método de la API de Android que indica al desarrollador si debe mostrar una explicación al usuario antes de solicitar un permiso peligroso. Según la Referencia para Desarrolladores de Android, 2024, el método devuelve true si el usuario rechazó previamente la solicitud pero no marcó la opción Never Ask Again. Es una herramienta clave para crear una experiencia de usuario respetuosa al trabajar con permisos en tiempo de ejecución.
Puntos Clave
shouldShowRequestPermissionRationale es un método de las clases Activity y Fragment en Android, disponible a través de ActivityCompat para compatibilidad. Recibe un nombre de permiso y devuelve un Boolean indicando si se debe mostrar al usuario una explicación adicional antes de volver a solicitarlo. El método apareció en Android 6.0 Marshmallow junto con el modelo de permisos en tiempo de ejecución.
El mecanismo de explicación se basa en el seguimiento del historial de interacción del usuario con los diálogos de permisos. El sistema recuerda si el usuario rechazó la solicitud anteriormente. Si el rechazo ocurrió sin marcar Never Ask Again, shouldShowRequestPermissionRationale devuelve true. Esto es una señal para el desarrollador: el usuario no entiende por qué se necesita el permiso y se requiere una explicación adicional. Según las Guías de Diseño Material de Google, mostrar un diálogo explicativo después de la primera denegación aumenta la probabilidad de conceder el permiso nuevamente en un 35 por ciento.
Es importante entender la semántica de los valores devueltos: true significa que tiene sentido mostrar el diálogo, false significa que el diálogo no es necesario (el permiso ya fue concedido o nunca se solicitó) o es inútil (Never Ask Again activo). El método no es una garantía de que se mostrará el diálogo — solo da una recomendación. El desarrollador decide qué interfaz mostrar en respuesta.
shouldShowRequestPermissionRationale se introdujo en el Nivel de API 23 junto con un grupo de métodos para permisos en tiempo de ejecución. Antes de Android 6.0, todos los permisos se solicitaban al instalar y no se necesitaba ningún mecanismo de explicación — el usuario aceptaba o rechazaba la lista completa de una vez. El modelo de ejecución hizo posible que un usuario denegara una solicitud sin entender el contexto, y es precisamente por eso que se necesita la explicación.
La lógica del método funciona de la siguiente manera. En la primera llamada a requestPermissions para un permiso específico, shouldShowRequestPermissionRationale devuelve false — el usuario aún no ha visto el diálogo. Si el usuario rechaza la solicitud (presiona Denegar), el método comienza a devolver true. Después de una denegación repetida con la bandera Never Ask Again, el método devuelve false.
Tabla completa de estados:
| Estado | shouldShowRationale | checkSelfPermission | Acción del desarrollador |
|---|---|---|---|
| No solicitado | false | DENIED | Mostrar diálogo del sistema |
| Concedido | false | GRANTED | Ejecutar función |
| Denegado primera vez | true | DENIED | Mostrar explicación, luego diálogo del sistema |
| Never Ask Again | false | DENIED | Redirigir a Configuración |
La combinación shouldShowRequestPermissionRationale = false y checkSelfPermission = DENIED es el caso más difícil de manejar. Significa que el permiso nunca se solicitó o que Never Ask Again está activado. El desarrollador debe distinguir entre estos dos estados. La única forma es almacenar una bandera isFirstRequest en SharedPreferences o usando SavedStateHandle. Establecer la bandera en la primera solicitud, y si shouldShowRationale devuelve false mientras la bandera ya es true — significa Never Ask Again.
shouldShowRequestPermissionRationale se restablece si el usuario desinstala y reinstala la aplicación, borra los datos de la aplicación o restablece la configuración de permisos. Después de la reinstalación, el método volverá a devolver false para la primera solicitud. Las actualizaciones del sistema y los cambios de versión de Android no restablecen el historial — se almacena en los datos de la aplicación.
Una implementación adecuada de la explicación incluye tres componentes: verificar shouldShowRequestPermissionRationale después de la denegación, mostrar un diálogo personalizado con una explicación y volver a llamar a requestPermissions después de una respuesta positiva del usuario. El diálogo debe ser breve, específico y explicar por qué la aplicación necesita este permiso en particular.
private fun requestLocationWithRationale() {
val permission = Manifest.permission.ACCESS_FINE_LOCATION
when {
ContextCompat.checkSelfPermission(
this, permission
) == PackageManager.PERMISSION_GRANTED -> {
startLocationTracking()
}
ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
) -> {
showRationaleDialog(permission)
}
else -> {
requestPermissionLauncher.launch(permission)
}
}
}
private fun showRationaleDialog(
permission: String
) {
AlertDialog.Builder(this)
.setTitle("Por qué se necesita acceso a la ubicación")
.setMessage(
"La aplicación usa la ubicación para marcar" +
" lugares en el mapa. Sin este permiso," +
" la función no funcionará."
)
.setPositiveButton("Permitir") { _, _ ->
requestPermissionLauncher.launch(permission)
}
.setNegativeButton("Cancelar", null)
.show()
}
Las mejores prácticas de Material Design recomiendan usar una hoja inferior o un banner en línea en lugar de un diálogo modal para la explicación. Una hoja inferior es menos intrusiva y le da contexto al usuario. Un elemento en línea en la pantalla (por ejemplo, una tarjeta con una explicación y un botón Permitir) muestra que la función no está disponible sin el permiso, pero no bloquea el resto de la interfaz.
El texto de la explicación debe estar localizado y adaptado a la función específica. No use frases genéricas como “Esto es necesario para que la aplicación funcione.” Especifique concretamente: “Para mostrar el clima cerca de usted” o “Para guardar fotos en la galería.” Las explicaciones específicas aumentan la probabilidad de conceder el permiso en un 50 por ciento según la Investigación de UX de Google.
La diferencia entre shouldShowRequestPermissionRationale = true (primera denegación) y false con DENIED (Never Ask Again) es un punto clave en el manejo de permisos. En el primer caso, el usuario dudó y una explicación adicional puede convencerlo de conceder el acceso. En el segundo, el usuario tomó una decisión final y repetir el diálogo del sistema solo causará irritación.
El algoritmo de manejo después de la denegación debe ser el siguiente:
Es importante no confundir el orden: verificar shouldShowRequestPermissionRationale primero, no checkSelfPermission. checkSelfPermission seguirá devolviendo DENIED en ambos casos. Solo shouldShowRequestPermissionRationale distingue la primera denegación de Never Ask Again. Use SavedStateHandle o SharedPreferences para almacenar la bandera “primera solicitud realizada” — esta es la única forma confiable de distinguir “nunca solicitado” de “bloqueado.”
Muestre la explicación solo una vez. Si el usuario vuelve a denegar la solicitud después de ver la explicación, no muestre la explicación nuevamente. Vaya directamente a ofrecer abrir Configuración. Mostrar la explicación repetidamente se percibe como molesto y reduce la calificación de la aplicación. El escenario óptimo: solicitud — denegación — explicación — solicitud repetida — denegación — Configuración.
No muestre la explicación antes de la primera solicitud. Algunos desarrolladores muestran erróneamente una explicación antes del primer diálogo, argumentando que “el usuario debe entender.” Esto perjudica la experiencia de usuario: el usuario ve dos diálogos seguidos en lugar de uno. Google recomienda mostrar el diálogo del sistema inmediatamente y la explicación solo después de la denegación.
Use una explicación contextual vinculada al momento en que la función realmente se necesita. No solicite todos los permisos al iniciar la aplicación — esta tiene la tasa de concesión más baja. Solicite CÁMARA cuando el usuario toque “Tomar Foto” y UBICACIÓN cuando abra el mapa. La solicitud contextual combinada con la explicación aumenta las concesiones al 80 por ciento frente al 30 por ciento cuando se solicita al inicio.
Probar shouldShowRequestPermissionRationale requiere verificar los cuatro estados de la tabla: no solicitado, concedido, denegado, Never Ask Again. En pruebas unitarias, use FakePermissionHandler con comportamiento configurable de shouldShowRationale. En pruebas de instrumentación, use UiAutomator o Espresso con emulación de respuestas de diálogos.
class RationaleViewModelTest {
private val handler = FakePermissionHandler()
private val viewModel = PermissionsViewModel(handler)
fun testFirstDenial_shouldShowRationale() {
handler.shouldShowRationale = true
handler.cameraResult =
PermissionResult.DENIED(true)
viewModel.onCameraRequested()
assertEquals(
PermissionUiState.Denied(true),
viewModel.uiState.value
)
}
fun testNeverAskAgain_redirectToSettings() {
handler.shouldShowRationale = false
handler.cameraResult =
PermissionResult.DENIED(false)
viewModel.onCameraRequested()
assertEquals(
PermissionUiState.RedirectToSettings,
viewModel.uiState.value
)
}
}
El escenario clave para una prueba de instrumentación es verificar que el diálogo de explicación realmente aparezca después de la primera denegación. Use Espresso con recursos de espera para esperar el diálogo del sistema, luego presione Denegar, verifique la aparición del diálogo de explicación personalizado y presione Permitir — verifique la concesión. UIAutomator permite interactuar con el diálogo del sistema mediante el texto del botón, lo que hace que la prueba sea más estable.
También debe probar el escenario de denegación dentro del diálogo de explicación. Si el usuario presiona Denegar en la explicación personalizada, shouldShowRequestPermissionRationale debe devolver true nuevamente, ya que Never Ask Again aún no está activado. La mejor práctica es redirigir a Configuración después de dos denegaciones consecutivas para evitar molestar al usuario con explicaciones repetidas y reducir la calificación de la aplicación.
Preguntas Frecuentes
true — si la solicitud fue denegada anteriormente y Never Ask Again no está activado. false — si el permiso nunca se solicitó, fue concedido o está bloqueado permanentemente. La combinación false + DENIED requiere verificación mediante una bandera adicional.
Muestre la explicación solo después de la primera denegación del usuario, cuando shouldShowRequestPermissionRationale devolvió true. Antes de la primera solicitud, la explicación no es necesaria — empeora la experiencia de usuario y crea diálogos innecesarios.
Almacene una bandera isFirstRequest en SharedPreferences o SavedStateHandle. Si shouldShowRationale = false, checkSelfPermission = DENIED y la bandera es true — Never Ask Again está activo. Si la bandera es false — es la primera solicitud.
Muestre un diálogo con un botón “Abrir Configuración” que redirija al usuario a ACTION_APPLICATION_DETAILS_SETTINGS. No llame a requestPermissions nuevamente — el diálogo no aparecerá y el resultado llegará como DENIED sin mensaje.
En pruebas unitarias, use FakePermissionHandler con un campo shouldShowRationale configurable. En pruebas de instrumentación, use Espresso o UIAutomator con emulación de diálogo del sistema. Verifique los 4 estados de la tabla.
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