shouldShowRequestPermissionRationale — je metoda Android API, která vývojáři napovídá, zda má uživateli zobrazit vysvětlení před žádostí o nebezpečné oprávnění. Podle Android Developer Reference, 2024, metoda rational vrátí true, pokud uživatel dříve odmítl žádost, ale nenastavil příznak Never Ask Again. Je to klíčový nástroj pro budování zdvořilého UX při práci s runtime oprávněními.
Hlavní body
shouldShowRequestPermissionRationale — je metoda tříd Activity a Fragment v Androidu, dostupná prostřednictvím ActivityCompat pro kompatibilitu. Přijímá název oprávnění a vrací Boolean, který indikuje, zda je třeba zobrazit uživateli další vysvětlení před opakovanou žádostí. Metoda se objevila v Android 6.0 Marshmallow spolu s modelem runtime oprávnění.
Mechanismus rationale je postaven na sledování historie interakce uživatele s dialogy oprávnění. Systém si pamatuje, zda uživatel dříve odmítl žádost. Pokud odmítnutí proběhlo bez nastavení příznaku Never Ask Again, shouldShowRequestPermissionRationale vrátí true. To je signál pro vývojáře: uživatel nerozumí, proč je oprávnění potřeba, a je vyžadováno další vysvětlení. Podle Google Material Design Guidelines zvyšuje zobrazení rationale dialogu po prvním odmítnutí pravděpodobnost opětovného udělení oprávnění o 35 procent.
Je důležité porozumět sémantice vracených hodnot: true znamená, že má smysl dialog zobrazit, false — dialog buď není potřeba (oprávnění je již uděleno nebo nikdy nebylo požadováno), nebo je zbytečný (Never Ask Again je aktivní). Metoda není zárukou, že dialog bude zobrazen — pouze dává doporučení. Vývojář sám rozhoduje, jaké UI zobrazí jako odpověď.
shouldShowRequestPermissionRationale byl představen v API Level 23 spolu se skupinou metod pro runtime oprávnění. Před Androidem 6.0 byla všechna oprávnění požadována při instalaci a mechanizmus vysvětlení nebyl potřeba — uživatel přijal nebo odmítl celý seznam najednou. Runtime model umožnil situaci, kdy uživatel odmítá žádost bez pochopení kontextu, a právě proto je rationale potřeba.
Logika metody je následující. Při prvním volání requestPermissions pro konkrétní oprávnění shouldShowRequestPermissionRationale vrátí false — uživatel se ještě nesetkal s dialogem. Pokud uživatel odmítl žádost (stiskl Deny), metoda začne vracet true. Po opakovaném odmítnutí s příznakem Never Ask Again metoda vrátí false.
Kompletní tabulka stavů:
| Stav | shouldShowRationale | checkSelfPermission | Akce vývojáře |
|---|---|---|---|
| Nebylo požadováno | false | DENIED | Zobrazit systémový dialog |
| Uděleno | false | GRANTED | Provést funkci |
| Odmítnuto poprvé | true | DENIED | Zobrazit rationale, poté systémový dialog |
| Never Ask Again | false | DENIED | Přesměrovat do Nastavení |
Kombinace shouldShowRequestPermissionRationale = false a checkSelfPermission = DENIED — je nejobtížněji zpracovatelný případ. Znamená, že buď oprávnění nebylo nikdy požadováno, nebo bylo nastaveno Never Ask Again. Vývojář musí tyto dva stavy rozlišit. Jediný způsob — uložení příznaku firstRequest v SharedPreferences nebo použití SavedStateHandle. Při první žádosti nastavte příznak, a pokud shouldShowRationale vrátil false a příznak je již true — znamená to Never Ask Again.
shouldShowRequestPermissionRationale se resetuje, pokud uživatel odstraní a znovu nainstaluje aplikaci, vymaže data aplikace nebo resetuje nastavení oprávnění. Po přeinstalaci metoda opět vrátí false pro první žádost. Systémové aktualizace a změna verze Androidu neresetují historii — je uložena v datech aplikace.
Správná implementace rationale zahrnuje tři komponenty: kontrolu shouldShowRequestPermissionRationale po odmítnutí, zobrazení vlastního dialogu s vysvětlením a opětovné volání requestPermissions po pozitivní odpovědi uživatele. Dialog by měl být stručný, konkrétní a vysvětlovat, proč aplikace potřebuje právě toto oprávnění.
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("Proč je potřeba přístup k geolokaci")
.setMessage(
"Aplikace používá geolokaci k označení míst na mapě" +
". Bez tohoto oprávnění" +
" funkce nebude fungovat."
)
.setPositiveButton("Povolit") { _, _ ->
requestPermissionLauncher.launch(permission)
}
.setNegativeButton("Zrušit", null)
.show()
}
Nejlepší postupy Material Design doporučují používat bottom sheet nebo inline banner místo modálního dialogu pro rationale. Bottom sheet je méně rušivý a dává uživateli kontext. Inline prvek na obrazovce (například karta s vysvětlením a tlačítkem Povolit) ukazuje, že funkce není dostupná bez oprávnění, ale neblokuje zbytek rozhraní.
Text rationale by měl být lokalizován a přizpůsoben konkrétní funkci. Nepoužívejte obecné fráze jako „To je potřeba pro chod aplikace”. Uveďte konkrétně: „Pro zobrazení počasí ve vašem okolí” nebo „Pro ukládání fotografií do galerie”. Podle Google UX Research zvyšují konkrétní vysvětlení pravděpodobnost udělení oprávnění o 50 procent.
Rozdíl mezi shouldShowRequestPermissionRationale = true (první odmítnutí) a false při DENIED (Never Ask Again) — je klíčovým bodem při zpracování oprávnění. V prvním případě uživatel váhal a další vysvětlení ho může přesvědčit k udělení přístupu. Ve druhém — uživatel učinil konečné rozhodnutí a opakovaný systémový dialog způsobí jen podráždění.
Algoritmus zpracování po odmítnutí by měl vypadat takto:
Je důležité neplést pořadí: nejprve zkontrolovat shouldShowRequestPermissionRationale, ne checkSelfPermission. checkSelfPermission stejně vrátí DENIED v obou případech. Pouze shouldShowRequestPermissionRationale rozlišuje první odmítnutí od Never Ask Again. Použijte SavedStateHandle nebo SharedPreferences pro uložení příznaku „první žádost proběhla” — to je jediný spolehlivý způsob, jak rozlišit „nebylo požadováno” od „blokováno”.
Zobrazujte rationale pouze jednou. Pokud uživatel opětovně odmítl žádost po rationale — už nezobrazujte vysvětlení. Přejděte rovnou k návrhu otevřít nastavení. Opakované zobrazování rationale je vnímáno jako vlezlost a snižuje hodnocení aplikace. Optimální scénář: žádost — odmítnutí — rationale — opakovaná žádost — odmítnutí — Nastavení.
Nezobrazujte rationale před první žádostí. Někteří vývojáři chybně zobrazují vysvětlení před prvním dialogem s argumentem, že „uživatel by měl rozumět”. To zhoršuje UX: uživatel vidí dva dialogy za sebou místo jednoho. Google doporučuje zobrazit systémový dialog okamžitě a rationale až po odmítnutí.
Používejte kontextové rationale, vázané na okamžik, kdy je funkce skutečně potřeba. Nežádejte všechna oprávnění při spuštění aplikace — to je nejnižší míra udělení. Žežejte CAMERA, když uživatel stiskl tlačítko „Vyfotit”, a LOCATION, když otevřel mapu. Kontextová žádost v kombinaci s rationale zvyšuje udělení na 80 procent oproti 30 procentům při počáteční žádosti.
Testování shouldShowRequestPermissionRationale vyžaduje kontrolu čtyř stavů z tabulky: nebylo požadováno, uděleno, odmítnuto, Never Ask Again. V jednotkových testech se používá FakePermissionHandler s konfigurovatelným chováním shouldShowRationale. V instrumentálních testech — UiAutomator nebo Espresso s emulací odpovědí na systémové dialogy.
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
)
}
}
Klíčový scénář pro instrumentální test — kontrola, že se rationale dialog skutečně zobrazí po prvním odmítnutí. Použijte Espresso s idling resources pro čekání na systémový dialog, poté stiskněte Deny, zkontrolujte objevení vlastního dialogu s textem vysvětlení a stiskněte Allow — zkontrolujte udělení. UIAutomator umožňuje interakci se systémovým dialogem pomocí textu tlačítka, což činí test stabilnějším.
Také stojí za to otestovat scénář odmítnutí uvnitř rationale dialogu. Pokud uživatel stiskl Deny ve vlastním vysvětlení, shouldShowRequestPermissionRationale by měla znovu vrátit true, protože Never Ask Again ještě nebylo aktivováno. Nejlepší praxí je po dvou po sobě jdoucích odmítnutích přesměrovat přímo do Nastavení, aby nedošlo k obtěžování uživatele opakovanými vysvětleními a snížení hodnocení aplikace.
Často kladené otázky
true — pokud byla žádost dříve odmítnuta a Never Ask Again nebylo nastaveno. false — pokud oprávnění nebylo požadováno, bylo uděleno nebo je natrvalo blokováno. Kombinace false + DENIED vyžaduje kontrolu pomocí dalšího příznaku.
Zobrazujte rationale pouze po prvním odmítnutí uživatele, když shouldShowRequestPermissionRationale vrátilo true. Před první žádostí rationale není potřeba — to zhoršuje UX a vytváří zbytečné dialogy.
Uložte příznak isFirstRequest do SharedPreferences nebo SavedStateHandle. Pokud shouldShowRationale = false, checkSelfPermission = DENIED a příznak = true — znamená to, že Never Ask Again bylo aktivováno. Pokud příznak = false — toto je první žádost.
Zobrazte dialog s tlačítkem „Otevřít nastavení”, který přesměruje uživatele na ACTION_APPLICATION_DETAILS_SETTINGS. Nevolajte znovu requestPermissions — dialog se neobjeví a výsledek přijde s DENIED bez zprávy.
V jednotkových testech použijte FakePermissionHandler s konfigurovatelným polem shouldShowRationale. V instrumentálních testech — Espresso nebo UIAutomator s emulací systémového dialogu. Zkontrolujte všechny 4 stavy z tabulky.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také