Dangerous Permission — to kategoria uprawnień w Android, które wymagają jawnej zgody użytkownika poprzez okno dialogowe w czasie wykonania aplikacji. Według Android Developer Guide, 2024, niebezpieczne uprawnienia mają ProtectionLevel dangerous i dają dostęp do poufnych danych: kamery, mikrofonu, geolokalizacji i kontaktów. Bez jawnej zgody użytkownika aplikacja nie może korzystać z tych funkcji.
Najważniejsze
Dangerous Permission — to kategoria systemowych uprawnień Android, zapewniających dostęp do poufnych danych użytkownika. W przeciwieństwie do normalnych, niebezpieczne uprawnienia nie są wydawane automatycznie podczas instalacji — aplikacja musi jawnie o nie poprosić w czasie wykonania za pomocą mechanizmu runtime, wprowadzonego w Android 6.0 Marshmallow (API 23).
Konieczność jawnego żądania wynika z charakteru danych, które chronią te uprawnienia: geolokalizacja użytkownika, kontakty osobiste, zawartość kamery i mikrofonu, historia połączeń i SMS. Android traktuje te dane jako wrażliwe i wymaga świadomej zgody użytkownika. Według Android Privacy Sandbox (2024), użytkownicy odrzucają około 30 procent żądań runtime średnio.
Kluczową cechą Dangerous Permission jest możliwość cofnięcia w dowolnym momencie. Użytkownik może przejść do Ustawienia — Aplikacje — Uprawnienia i przełączyć przełącznik dla dowolnego niebezpiecznego uprawnienia. Aplikacja musi być gotowa na to, że uprawnienie, które zostało przyznane, może zostać cofnięte w dowolnym momencie bez restartu.
Poziom ochrony dangerous jest ustawiany w systemowych definicjach uprawnień na poziomie OS. Gdy aplikacja deklaruje uses-permission z takim protectionLevel, system oznacza uprawnienie jako wymagające żądania runtime. W przeciwieństwie do normal, uprawnienia dangerous są zawsze wyświetlane w systemowym UI zarządzania uprawnieniami i mogą być cofnięte.
Wszystkie niebezpieczne uprawnienia są pogrupowane w Permission Group według funkcjonalności. Na przykład CAMERA i CAMERA2 znajdują się w grupie CAMERA, ACCESS_FINE_LOCATION i ACCESS_COARSE_LOCATION — w grupie LOCATION. Jeśli użytkownik przyznał jedno uprawnienie z grupy, pozostałe uprawnienia tej samej grupy są przyznawane automatycznie bez dodatkowego okna dialogowego.
Żądanie runtime — to mechanizm, w którym aplikacja wywołuje systemowe API do wyświetlenia okna dialogowego z prośbą o uprawnienie. Użytkownik widzi modalne okno z nazwą uprawnienia i przyciskami Allow i Deny. Po odpowiedzi system wywołuje callback onRequestPermissionsResult z wynikiem.
Pełny cykl obejmuje trzy kroki: sprawdzenie statusu przez checkSelfPermission, wywołanie requestPermissions w przypadku braku uprawnienia i obsługa wyniku w onRequestPermissionsResult. Sprawdzenie statusu jest obowiązkowe, ponieważ użytkownik mógł cofnąć uprawnienie w dowolnym momencie przez ustawienia, a wywołanie funkcji bez sprawdzenia doprowadzi do SecurityException.
fun checkAndRequestCameraPermission() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else -> {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_CODE
)
}
}
}
Obsługa wyniku odbywa się w ActivityResultLauncher lub onRequestPermissionsResult. Zalecanym nowoczesnym podejściem jest użycie ActivityResultContracts.RequestPermission, który zapewnia czystsze API bez jawnych kodów żądań. Ten kontrakt zwraca Boolean — czy uprawnienie zostało przyznane.
Żądaj niebezpiecznych uprawnień ściśle w kontekście użycia funkcji, a nie podczas uruchamiania aplikacji. Jeśli użytkownik nacisnął przycisk kamery — żądaj CAMERA. Jeśli otworzył mapę — żądaj LOCATION. Żądanie kontekstowe daje dwa razy więcej przyznań niż żądanie wszystkich uprawnień przy pierwszym uruchomieniu. Zaleca się również żądanie nie więcej niż jednego uprawnienia na raz, aby użytkownik rozumiał, która funkcja wymaga dostępu.
Android definiuje kilka grup niebezpiecznych uprawnień, z których każda zawiera od jednej do kilku stałych. Najbardziej pełna lista znajduje się w klasie Manifest.permission. Poniżej przedstawiono główne grupy i uprawnienia używane w programowaniu.
| Grupa Permission Group | Uprawnienia | API dostępu |
|---|---|---|
| CAMERA | CAMERA | Camera API, CameraX |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | FusedLocationProvider, Geofence |
| MICROPHONE | RECORD_AUDIO | MediaRecorder, AudioRecord |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | TelephonyManager |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | ContactsContract |
| SMS | READ_SMS, SEND_SMS, RECEIVE_SMS | SmsManager |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | MediaStore, File API |
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | CalendarContract |
Począwszy od Android 12, Google zaostrzył wymagania dla niektórych uprawnień. Na przykład BLUETOOTH_CONNECT i BLUETOOTH_SCAN stały się niebezpieczne i wymagają żądania runtime. Pojawiło się również uprawnienie BODY_SENSORS_BACKGROUND do tławego dostępu do czujników. Programiści muszą aktualizować targetSdkVersion i testować żądania na bieżących wersjach OS.
Android 13 (API 33) wprowadził nowe uprawnienia dla powiadomień (POST_NOTIFICATIONS) i dla plików medialnych (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO), zastępując ogólne READ_EXTERNAL_STORAGE. Teraz dostęp do zdjęć, wideo i audio jest żądany osobno przez wyspecjalizowane uprawnienia bez jednego okna dialogowego.
Dangerous i Normal Permission zasadniczo różnią się sposobem przyznawania, możliwością cofnięcia i UX. Normal jest wydawane automatycznie podczas instalacji, Dangerous wymaga jawnego okna dialogowego runtime. Normal nie można cofnąć przez ustawienia, Dangerous można wyłączyć w dowolnym momencie. Ta asymetria narzuca różne wzorce programowania.
Z punktu widzenia kodu, niebezpieczne uprawnienia wymagają więcej pracy: checkSelfPermission, requestPermissions, obsługa odmowy. Dla normalnych wystarczy jeden wiersz w AndroidManifest.xml. Jednocześnie Dangerous Permission daje użytkownikowi kontrolę, co zwiększa zaufanie, szczególnie w przypadku wrażliwych funkcji takich jak kamera czy geolokalizacja.
Wybór między kategoriami nie stoi przed programistą — jest określany przez system. Programista jedynie deklaruje uses-permission, a system na podstawie protectionLevel określa kategorię. Jednak strategia żądania niebezpiecznych uprawnień wpływa na doświadczenie użytkownika: częste lub nieodpowiednie okna dialogowe obniżają ocenę aplikacji.
Nowoczesny sposób żądania uprawnień w Kotlin — użycie ActivityResultContracts.RequestMultiplePermissions lub RequestPermission. Te kontrakty wchodzą w skład biblioteki androidx.activity i zapewniają czyste API oparte na lambdach, bez potrzeby nadpisywania onRequestPermissionsResult.
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
showPermissionDeniedMessage()
}
}
fun requestCamera() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED ->
openCamera()
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) ->
showRationaleDialog()
else ->
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
Gdy aplikacja potrzebuje kilka niebezpiecznych uprawnień jednocześnie, użyj RequestMultiplePermissions. Kontrakt zwraca Map<String, Boolean>, gdzie klucz to nazwa uprawnienia, wartość to wynik. Jest to wygodne przy pierwszym uruchomieniu, gdy trzeba poprosić o CAMERA i RECORD_AUDIO do nagrywania wideo.
Jeśli użytkownik odrzucił żądanie, metoda shouldShowRequestPermissionRationale zwraca true. To sygnał, aby pokazać wyjaśnienie, po co uprawnienie jest potrzebne. Najlepszą praktyką jest pokazanie niestandardowego okna dialogowego z wyjaśnieniem i przyciskiem Ponów. Jeśli użytkownik ponownie odrzucił żądanie z zaznaczeniem Never Ask Again, shouldShowRequestPermissionRationale zwróci false i należy przekierować do Ustawień.
Never Ask Again — to flaga, którą użytkownik może ustawić przy ponownym odrzuceniu okna dialogowego runtime. Po tym standardowe okno dialogowe nie pojawia się już dla tego uprawnienia. Jedynym sposobem na przyznanie dostępu jest przekierowanie użytkownika do systemowych ustawień aplikacji.
Programista musi rozróżniać dwa scenariusze odmowy: pierwszy — gdy shouldShowRequestPermissionRationale zwraca true (użytkownik odrzucił, ale okno dialogowe można jeszcze pokazać), i drugi — gdy metoda zwraca false (Never Ask Again jest aktywny lub uprawnienie jest zablokowane przez politykę). W drugim przypadku należy pokazać przycisk Otwórz ustawienia.
fun handlePermissionDenied(permission: String) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
)) {
showRationaleDialog(permission)
} else {
showSettingsRedirectDialog(permission)
}
}
private fun showSettingsRedirectDialog(permission: String) {
AlertDialog.Builder(this)
.setTitle("Odmowa dostępu")
.setMessage(
"Uprawnienie zablokowane. Otwórz ustawienia."
)
.setPositiveButton("Ustawienia") { _, _ ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package", packageName, null
)
)
startActivity(intent)
}
.show()
}
Ważne, aby nie żądać uprawnienia ponownie, jeśli shouldShowRequestPermissionRationale zwróciło false. Ponowne wywołanie requestPermissions w tym przypadku nie pokaże okna dialogowego — wynik przyjdzie natychmiast z DENIED bez wyjaśnienia. Użytkownik napotka niezrozumiałe zachowanie, co negatywnie wpłynie na doświadczenie korzystania z aplikacji.
Często zadawane pytania
Do Dangerous Permission należą uprawnienia z ProtectionLevel dangerous: CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, READ_CONTACTS, READ_SMS, READ_CALENDAR i inne. Pełna lista znajduje się w klasie Manifest.permission.
Użyj ContextCompat.checkSelfPermission, przekazując kontekst i nazwę uprawnienia. Metoda zwraca PERMISSION_GRANTED lub PERMISSION_DENIED. Sprawdzenie należy wykonać przed każdym wywołaniem API wymagającego niebezpiecznego uprawnienia.
Permission Group łączy powiązane niebezpieczne uprawnienia. Jeśli użytkownik przyznał jedno uprawnienie z grupy, pozostałe są przyznawane automatycznie. Na przykład LOCATION obejmuje ACCESS_FINE_LOCATION i ACCESS_COARSE_LOCATION.
Sprawdź shouldShowRequestPermissionRationale po odmowie. Jeśli metoda zwróciła false, a uprawnienie nadal nie jest przyznane — oznacza to, że aktywowano Never Ask Again. Przekieruj użytkownika do Ustawień przez Intent z ACTION_APPLICATION_DETAILS_SETTINGS.
Tak, pozostają obowiązkowe. Na Android 13+ zmieniły się niektóre uprawnienia: POST_NOTIFICATIONS stało się oddzielnym uprawnieniem runtime, a READ_EXTERNAL_STORAGE zostało zastąpione przez READ_MEDIA_IMAGES dla ukierunkowanego dostępu do plików medialnych.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również