Lekce 1 - Android - Úvod do oprávnění aplikací
Vítejte v Android kurzu, ve kterém si vysvětlíme problematiku
udělování oprávnění (permissions) našim aplikacím. Budeme se věnovat
zejména těm pro zařízení s verzí API 23 a vyšší, kde je nutné
oprávnění udělovat při běhu aplikace a již nejsou udělena automaticky
systémem při instalaci. Máme tedy novou problematiku, kterou se musíme jako
Android vývojáři zabývat, aby naše aplikace uživatelům nepadaly na
výjimku SecurityException
.
Oprávnění
Účelem oprávnění je ochrana soukromí uživatele. Žádná aplikace ve výchozím nastavení nemá oprávnění provádět žádné operace, které mohou potenciálně nepříznivě ovlivnit jiné aplikace, operační systém nebo uživatele. Systém některá oprávnění uděluje automaticky a jiná až po souhlasu uživatele v závislosti na závažnosti daného oprávnění.
Kategorie oprávnění
Android dělí oprávnění do dvou kategorií dle závažnosti:
- Normální oprávnění - Nepředstavují velké riziko pro soukromí uživatele nebo pro provoz zařízení.
- Nebezpečná oprávnění - Musí udělit aplikaci uživatel a mohla by potenciálně ohrozit soukromí uživatele nebo normální provoz zařízení. Dokud uživatel oprávnění neudělí, aplikace nemůže poskytovat funkce, které na tomto oprávnění závisí.
Deklarace oprávnění
Každá aplikace musí požadovaná oprávnění (normální i
nebezpečná společně) deklarovat v úvodní části souboru
AndroidManifest.xml
.
Příklad deklarace požadovaných oprávnění v manifestu by vypadal např. takto:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Uvedený příklad vyžaduje tato oprávnění:
- Přístup k fotoaparátu (kameře)
- Oprávnění k přímému vytáčení telefonních hovorů
- Přístup k přesné poloze zařízení
Udělení normálních oprávnění
Ta oprávnění z deklarace v manifestu, která patří do kategorie normálních oprávnění, aplikace od systému získá během instalace do zařízení bez interakce s uživatelem. Zde tedy není moc co řešit
Udělení nebezpečných oprávnění
Nebezpečná deklarovaná oprávnění jsou udělována až na základě souhlasu uživatele. Způsob, jakým systém Android tento souhlas získá, závisí na verzi systému Android konkrétního zařízení:
- Android 6.0 Marshmallow (API úroveň 23) a vyšší - Uživatel není v době instalace upozorněn na žádná požadovaná oprávnění. Požádán bude až za běhu aplikace ve chvíli, kdy aplikace bude chtít provádět činnost, která dané oprávnění vyžaduje.
- Android 5.1.1 Lollipop (API úroveň 22) nebo nižší - Systém Android automaticky požádá uživatele o udělení všech deklarovaných nebezpečných oprávnění již při instalaci aplikace do zařízení. Pokud uživatel klikne na tlačítko Přijmout, všechna oprávnění jsou udělena v jednom okamžiku. Pokud uživatel žádost o oprávnění zamítne, je instalace aplikace ukončena. Pokud aktualizace aplikace vyžaduje další oprávnění, je uživatel vyzván k přijetí těchto nových oprávnění.
My se samozřejmě budeme zabývat tím novým způsobem, tedy od API
úrovně 23. V kurzu budeme používat ukázkovou aplikaci
Permissions
, kterou si představíme později. Obrázky zde budou
právě z ní.
Příklad - Základní postup pro udělení oprávnění
Nyní si popíšeme to nejnutnější povinné minimum, které musíme znát, abychom s oprávněními mohli pracovat. Tento postup také ale zároveň obsahuje úplné minimum informací pro uživatele. Jako příklad nám poslouží žádost o udělení oprávnění k přístupu ke kameře zařízení.
Krok 1 - Máme již oprávnění?
Prvním krokem je test, zda již nemá aplikace potřebné oprávnění uděleno. Tato kontrola musí proběhnout ještě před tím, než se aplikace pokusí o přístup ke kameře. Samotný obslužný kód kontroly oprávnění vypadá takto:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { // Oprávnění již bylo uděleno // Práce s kamerou zařízení } else { ActivityCompat.requestPermissions( MainActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_MINIMAL_REQUEST); } }
Celý proces začíná testem, zda aplikace běží na verzi API 23 nebo
vyšší. Pokud je verze API nižší než 23, není provedeno nic (protože
uživatel oprávnění již udělil při instalaci). V opačném případě je
volána metoda checkSelfPermission()
, která otestuje, zda aplikace
disponuje oprávněním, jehož název přijímá v parametru. Výsledkem bude
vrácená hodnota typu int
, která může nabývat hodnoty
konstant:
PERMISSION_GRANTED
(oprávnění uděleno) - Je-li oprávnění uděleno (podmínka je splněna), může být proveden kód přistupující ke kameře zařízení.PERMISSION_DENIED
(oprávnění odepřeno). Při zjištění, že oprávnění uděleno není, je volána metodarequestPermissions()
.
Krok 2 - Zažádání o oprávnění
Pokud oprávnění nemáme, tak o něj zažádáme. Metoda
requestPermissions()
má 3 parametry:
- aktuální kontext
- pole s názvy požadovaných oprávnění, můžeme tedy žádat o více najednou
- hodnota typu
int
, sloužící jako poznávací značka pro pozdější zpracování odpovědi v přepsané metoděonRequestPermissionsResult()
- podobně jakorequestCode
při otevírání dalších aktivit.
Voláním requestPermissions()
požádáme o
zobrazení systémového dialogového okna s žádostí o udělení
konkrétního oprávnění:
Krok 3 - Reakce na volbu uživatele
Jakmile uživatel zareaguje, systém nám zavolá metodu
onRequestPermissionsResult()
, kde zjistíme, zda nám uživatel
oprávnění udělil či nikoli. Na základě toho tedy potenciálně
nebezpečnou funkčnost v aplikaci buď budeme používat, nebo ji nesmíme
spustit, jinak by naše aplikace spadla, viz dále.
Pokud uživatel udělení oprávnění v minulosti
definitivně zamítl, dialog mu již znovu zobrazen nebude. V tomto
případě zavolání metody requestPermissions()
povede jen k
automatickému přijetí odpovědi PERMISSION_DENIED
v přepsané
metodě onRequestPermissionsResult()
.
Přepsaná metoda pro zpracování odpovědi může vypadat takto:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Uživatel oprávnění udělil // Provedení akce, vyžadující udělené oprávnění } }
S voláním uvedené metody získáme tři parametry:
requestCode
- Toto je ona hodnota parametrurequestCode
metodyrequestPermissions()
, kterou jsme si sem poslali při požadavku o udělení oprávnění. Díky této hodnotě poznáme, ze které části kódu tento požadavek pochází.permissions
- Pole textových řetězců s oprávněními, o jejichž udělení bylo požádáno. Jejich pořadí v poli odpovídá tomu pořadí, v jakém byly uvedeny při volání metodyrequestPermissions()
.grantResults
- Pole s odpověďmi na žádosti o udělení oprávnění, jejichž pořadí odpovídá pořadí pole v proměnnépermissions
.
Pokud uživatel v zobrazeném dialogovém okně stiskne tlačítko Odmítnout, bude okno zavřeno a požadovaná akce s fotoaparátem nebude provedena.
Definitivní zamítnutí
Dojde-li k dalšímu vyzvání uživatele k udělení oprávnění, bude zobrazeno takovéto okno:
Oproti prvnímu dialogovému oknu navíc obsahuje zaškrtávací políčko Příště se neptat. Je-li toto políčko zaškrtnuto při dalším odmítnutí udělení oprávnění, bere systém na vědomí, že si již uživatel nepřeje být dotazován, zda toto konkrétní oprávnění udělí - a to ani v případě dalšího pokusu aplikace toto oprávnění získat. Nebude tedy dostupná ta funkce aplikace, která zamítnutá oprávnění vyžaduje.
Zrušení zamítnutí
Pokud by si své rozhodnutí uživatel rozmyslel a oprávnění chtěl dodatečně udělit, musí tak učinit poměrně komplikovanou cestou. V nastavení telefonu v seznamu nainstalovaných aplikací zobrazí detail konkrétní aplikace:
Zobrazí položku Oprávnění:
A zde nalezne seznam všech nebezpečných oprávnění, která aplikace požaduje v souboru manifestu. Jednotlivá oprávnění lze udělit nebo odepřít nastavením přepínače.
Jak je vidět, i když uživatel udělí aplikaci
požadovaná oprávnění, nemůžeme se nikdy spolehnout na to, že toto
oprávnění bude aplikace mít na vždy a je nutné, před
každým přístupem k funkci zařízení, vyžadující oprávnění,
za běhu aplikace kontrolovat, zda je oprávnění stále uděleno. Jinak by
naše aplikace spadla na výjimku SecurityException
.
Ošetření žádosti o udělení oprávnění od uživatele je povinné pro verze API 23 a vyšší a Android Studio se nás na tuto skutečnost snaží v kódu upozornit. To se děje, když se snažíme v kódu přistupovat k těm funkcím, které vyžadují udělení nebezpečných oprávnění.
Nevýhody základního postupu pro získání oprávnění
Popsaný postup dodatečného udělení oprávnění v nastavení zařízení nemusí běžný uživatel znát. Může se stát, že požadovaná oprávnění definitivně zamítne, aniž by si v tu chvíli plně uvědomoval následky, co se funkčnosti aplikace týče. Když již nebude žádost o udělení oprávnění zobrazována, daná funkce nebude dostupná a uživatel získá dojem, že aplikace nefunguje, na Google Play vaší aplikaci negativně ohodnotí a nakonec jí ze svého zařízení odinstaluje.
Proto je více než dobré popsaný základní postup získání oprávnění rozšířit tak, aby byl uživatel dostatečně informován. S tímto rozšířeným postupem se seznámíme dále v kurzu.
V příští lekci, Android - Spolehlivější postup pro získání oprávnění, se naučíme, jak přimět uživatele dát naší Android aplikaci potřebná oprávnění s mnohem vyšší pravděpodobností, než jen s normální žádostí.