shouldShowRequestPermissionRationale — este o metodă Android API care îi sugerează dezvoltatorului dacă trebuie să arate o explicație utilizatorului înainte de a solicita o permisiune periculoasă. Conform Android Developer Reference, 2024, metoda rational returnează true dacă utilizatorul a respins anterior cererea, dar nu a setat flag-ul Never Ask Again. Este un instrument cheie pentru construirea unui UX politicos atunci când lucrați cu permisiuni runtime.
Principalul
shouldShowRequestPermissionRationale — este o metodă a claselor Activity și Fragment în Android, disponibilă prin ActivityCompat pentru compatibilitate. Primește numele permisiunii și returnează un Boolean care indică dacă trebuie arătată utilizatorului o explicație suplimentară înainte de o solicitare repetată. Metoda a apărut în Android 6.0 Marshmallow odată cu modelul de permisiuni runtime.
Mecanismul rationale este construit pe urmărirea istoricului interacțiunii utilizatorului cu dialogurile de permisiuni. Sistemul îți amintește dacă utilizatorul a respins cererea anterior. Dacă respingerea a avut loc fără setarea flag-ului Never Ask Again, shouldShowRequestPermissionRationale returnează true. Acesta este un semnal pentru dezvoltator: utilizatorul nu înțelege de ce este necesară permisiunea și este necesară o explicație suplimentară. Conform Google Material Design Guidelines, afișarea dialogului rationale după primul refuz crește probabilitatea acordării repetate a permisiunii cu 35 de procente.
Este important să înțelegeți semantica valorilor returnate: true înseamnă că are sens să afișați dialogul, false — dialogul fie nu este necesar (permisiunea este deja acordată sau nu a fost niciodată solicitată), fie este inutil (Never Ask Again este activ). Metoda nu este o garanție că dialogul va fi afișat — ea oferă doar o recomandare. Dezvoltatorul decide singur ce UI să arate ca răspuns.
shouldShowRequestPermissionRationale a fost introdus în API Level 23 împreună cu un grup de metode pentru permisiuni runtime. Înainte de Android 6.0, toate permisiunile erau solicitate la instalare și mecanismul de explicare nu era necesar — utilizatorul accepta sau respingea întreaga listă odată. Modelul runtime a făcut posibilă situația în care utilizatorul respinge cererea fără a înțelege contextul și exact de aceea este necesar rationale.
Logica metodei este următoarea. La prima apelare a requestPermissions pentru o permisiune specifică, shouldShowRequestPermissionRationale returnează false — utilizatorul nu s-a confruntat încă cu dialogul. Dacă utilizatorul a respins cererea (a apăsat Deny), metoda începe să returneze true. După respingerea repetată cu flag-ul Never Ask Again, metoda returnează false.
Tabelul complet al stărilor:
| Stare | shouldShowRationale | checkSelfPermission | Acțiunea dezvoltatorului |
|---|---|---|---|
| Nesolicitat | false | DENIED | Afișați dialogul de sistem |
| Acordat | false | GRANTED | Executați funcția |
| Respins prima dată | true | DENIED | Afișați rationale, apoi dialogul de sistem |
| Never Ask Again | false | DENIED | Redirecționați la Setări |
Combinația shouldShowRequestPermissionRationale = false și checkSelfPermission = DENIED — este cel mai dificil caz de procesat. Însemnă că fie permisiunea nu a fost niciodată solicitată, fie Never Ask Again a fost setat. Dezvoltatorul trebuie să distingă aceste două stări. Singura modalitate — stocarea flag-ului firstRequest în SharedPreferences sau utilizarea SavedStateHandle. La prima solicitare setați flag-ul, iar dacă shouldShowRationale a returnat false iar flag-ul este deja true — înseamnă Never Ask Again.
shouldShowRequestPermissionRationale se resetează dacă utilizatorul șterge și reinstalează aplicația, șterge datele aplicației sau resetează setările de permisiuni. După reinstalare, metoda va returna din nou false pentru prima solicitare. Actualizările de sistem și schimbarea versiunii Android nu resetează istoricul — acesta este stocat în datele aplicației.
Implementarea corectă a rationale include trei componente: verificarea shouldShowRequestPermissionRationale după refuz, afișarea unui dialog personalizat cu explicația și apelarea repetată a requestPermissions după răspunsul pozitiv al utilizatorului. Dialogul trebuie să fie concis, specific și să explice de ce aplicația are nevoie exact de această permisiune.
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("De ce este necesar accesul la geolocație")
.setMessage(
"Aplicația folosește geolocația pentru a marca" +
" locurile pe hartă. Fără această permisiune" +
" funcția nu va funcționa."
)
.setPositiveButton("Permite") { _, _ ->
requestPermissionLauncher.launch(permission)
}
.setNegativeButton("Anulare", null)
.show()
}
Cele mai bune practici Material Design recomandă utilizarea bottom sheet sau a bannerului inline în locul dialogului modal pentru rationale. Bottom sheet este mai puțin intruziv și oferă utilizatorului context. Elementul inline în ecran (de exemplu, o carte cu explicație și butonul Permite) arată că funcția nu este disponibilă fără permisiune, dar nu blochează restul interfeței.
Textul rationale trebuie localizat și adaptat pentru funcția specifică. Nu utilizați fraze generice precum „Este necesar pentru funcționarea aplicației”. Indicați concret: „Pentru afișarea vremii din apropierea dvs.” sau „Pentru salvarea fotografiilor în galerie”. Conform Google UX Research, explicațiile concrete cresc probabilitatea acordării permisiunii cu 50 de procente.
Diferența dintre shouldShowRequestPermissionRationale = true (primul refuz) și false în cazul DENIED (Never Ask Again) — este punctul cheie în procesarea permisiunilor. În primul caz, utilizatorul a ezitat și o explicație suplimentară poate să-l convingă să acorde accesul. În al doilea — utilizatorul a luat o decizie finală și dialogul de sistem repetat va provoca doar iritare.
Algoritmul de procesare după refuz ar trebui să arate astfel:
Este important să nu confundați ordinea: mai întâi verificați shouldShowRequestPermissionRationale, nu checkSelfPermission. checkSelfPermission va returna oricum DENIED în ambele cazuri. Doar shouldShowRequestPermissionRationale distinge primul refuz de Never Ask Again. Utilizați SavedStateHandle sau SharedPreferences pentru stocarea flag-ului „prima cerere a fost” — aceasta este singura modalitate sigură de a distinge „nesolicitat” de „blocat”.
Afișați rationale doar o dată. Dacă utilizatorul a respins din nou cererea după rationale — nu mai afișați explicația. Treceți direct la propunerea de a deschide setările. Afișarea repetată a rationale este percepută ca intruzivă și scade ratingul aplicației. Scenariul optim: cerere — refuz — rationale — cerere repetată — refuz — Setări.
Nu afișați rationale înainte de prima cerere. Unii dezvoltatori afișează din greșeală explicația înainte de primul dialog, argumentând că „utilizatorul trebuie să înțeleagă”. Acest lucru înrăutățește UX: utilizatorul vede două dialoguri consecutive în loc de unul. Google recomandă afișarea dialogului de sistem imediat, iar rationale — doar după refuz.
Utilizați rationale contextual, legat de momentul când funcția este cu adevărat necesară. Nu solicitați toate permisiunile la pornirea aplicației — aceasta este cea mai scăzută rată de acordare. Solicitați CAMERA când utilizatorul a apăsat butonul „Faceți o fotografie” și LOCATION când a deschis harta. Cererea contextuală în combinație cu rationale crește acordarea la 80 de procente față de 30 de procente la cererea inițială.
Testarea shouldShowRequestPermissionRationale necesită verificarea celor patru stări din tabel: nesolicitat, acordat, respins, Never Ask Again. În testele unitare se utilizează FakePermissionHandler cu comportament configurabil al shouldShowRationale. În testele instrumentale — UiAutomator sau Espresso cu emularea răspunsurilor la dialogurile de sistem.
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
)
}
}
Scenariul cheie pentru testul instrumental — verificarea că dialogul rationale se afișează într-adevăr după primul refuz. Utilizați Espresso cu idling resources pentru a aștepta dialogul de sistem, apoi apăsați Deny, verificați apariția dialogului personalizat cu textul explicației și apăsați Allow — verificați acordarea. UIAutomator permite interacțiunea cu dialogul de sistem prin textul butonului, ceea ce face testul mai stabil.
De asemenea, merită să testați scenariul de refuz în interiorul dialogului rationale. Dacă utilizatorul a apăsat Deny în explicația personalizată, shouldShowRequestPermissionRationale ar trebui să returneze din nou true, deoarece Never Ask Again nu a fost încă activat. Cea mai bună practică — după două refuzuri consecutive să redirecționați direct la Setări pentru a nu irita utilizatorul cu explicații repetate și a nu scădea ratingul aplicației.
Întrebări frecvente
true — dacă cererea a fost respinsă anterior și Never Ask Again nu a fost setat. false — dacă permisiunea nu a fost solicitată, a fost acordată sau este blocată permanent. Combinația false + DENIED necesită verificare printr-un flag suplimentar.
Afișați rationale doar după primul refuz al utilizatorului, când shouldShowRequestPermissionRationale a returnat true. Înainte de prima cerere, rationale nu este necesar — acest lucru înrăutățește UX și creează dialoguri inutile.
Stocați flag-ul isFirstRequest în SharedPreferences sau SavedStateHandle. Dacă shouldShowRationale = false, checkSelfPermission = DENIED și flag-ul = true — înseamnă că Never Ask Again este activat. Dacă flag-ul = false — aceasta este prima cerere.
Afișați un dialog cu butonul „Deschideți setările” care redirecționează utilizatorul la ACTION_APPLICATION_DETAILS_SETTINGS. Nu apelați din nou requestPermissions — dialogul nu va apărea, iar rezultatul va veni cu DENIED fără mesaj.
În testele unitare, utilizați FakePermissionHandler cu câmpul configurabil shouldShowRationale. În testele instrumentale — Espresso sau UIAutomator cu emularea dialogului de sistem. Verificați toate cele 4 stări din tabel.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și