Dangerous Permission — это категория разрешений в Android, которые требуют явного согласия пользователя через runtime-диалог во время работы приложения. По данным Android Developer Guide, 2024, опасные разрешения имеют ProtectionLevel dangerous и дают доступ к конфиденциальным данным: камере, микрофону, геолокации и контактам. Без явного согласия пользователя приложение не может использовать эти функции.
Главное
Dangerous Permission — это категория системных разрешений Android, предоставляющих доступ к конфиденциальным данным пользователя. В отличие от нормальных, опасные разрешения не выдаются автоматически при установке — приложение должно явно запросить их во время выполнения через runtime-механизм, представленный в Android 6.0 Marshmallow (API 23).
Необходимость явного запроса обусловлена характером данных, которые защищают эти разрешения: геолокация пользователя, личные контакты, содержимое камеры и микрофона, история звонков и SMS. Android рассматривает эти данные как чувствительные и требует, чтобы пользователь осознанно предоставил доступ. По данным Android Privacy Sandbox (2024), пользователи отклоняют около 30 процентов runtime-запросов в среднем.
Ключевая особенность Dangerous Permission — возможность отзыва в любой момент. Пользователь может зайти в Настройки — Приложения — Разрешения и переключить тумблер для любого опасного разрешения. Приложение должно быть готово к тому, что разрешение, которое было предоставлено, может быть отозвано в любой момент без перезапуска.
Уровень защиты dangerous задаётся в системных дефинициях разрешений на уровне ОС. Когда приложение объявляет uses-permission с таким protectionLevel, система помечает разрешение как требующее runtime-запроса. В отличие от normal, dangerous-разрешения всегда отображаются в системном UI управления разрешениями и могут быть отозваны.
Все опасные разрешения сгруппированы в Permission Group по функциональному признаку. Например, CAMERA и CAMERA2 находятся в группе CAMERA, ACCESS_FINE_LOCATION и ACCESS_COARSE_LOCATION — в группе LOCATION. Если пользователь предоставил одно разрешение из группы, остальные разрешения той же группы предоставляются автоматически без дополнительного диалога.
Runtime-запрос — это механизм, при котором приложение вызывает системный API для отображения диалога с запросом разрешения. Пользователь видит модальное окно с названием разрешения и кнопками Allow и Deny. После ответа система вызывает колбэк onRequestPermissionsResult с результатом.
Полный цикл включает три шага: проверка статуса через checkSelfPermission, вызов requestPermissions при отсутствии разрешения и обработка результата в onRequestPermissionsResult. Проверка статуса обязательна, так как пользователь мог отозвать разрешение в любой момент через настройки, и вызов функции без проверки приведёт к 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
)
}
}
}
Обработка результата происходит в ActivityResultLauncher или onRequestPermissionsResult. Рекомендуемый современный подход — использование ActivityResultContracts.RequestPermission, который предоставляет более чистый API без явных кодов запросов. Этот контракт возвращает Boolean — предоставлено разрешение или нет.
Запрашивайте опасные разрешения строго в контексте использования функции, а не при старте приложения. Если пользователь нажал кнопку камеры — запрашивайте CAMERA. Если открыл карту — запрашивайте LOCATION. Контекстный запрос даёт в два раза больше предоставлений, чем запрос всех разрешений при первом запуске. Также рекомендуется запрашивать не более одного разрешения за раз, чтобы пользователь понимал, какая функция требует доступа.
Android определяет несколько групп опасных разрешений, каждая из которых включает от одной до нескольких констант. Наиболее полный список представлен в классе Manifest.permission. Ниже приведены основные группы и разрешения, используемые в разработке.
| Группа Permission Group | Разрешения | API доступа |
|---|---|---|
| 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 |
Начиная с Android 12, Google ужесточил требования к некоторым разрешениям. Например, BLUETOOTH_CONNECT и BLUETOOTH_SCAN стали опасными и требуют runtime-запроса. Также появилось разречение BODY_SENSORS_BACKGROUND для фонового доступа к датчикам. Разработчикам необходимо обновлять targetSdkVersion и тестировать запросы на актуальных версиях ОС.
Android 13 (API 33) ввёл новые разрешения для уведомлений (POST_NOTIFICATIONS) и для медиа-файлов (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO), заменившие общее READ_EXTERNAL_STORAGE. Теперь доступ к фото, видео и аудио запрашивается отдельно через специализированные разрешения без единого диалога.
Dangerous и Normal Permission принципиально различаются по способу предоставления, возможности отзыва и UX. Normal выдаётся автоматически при установке, Dangerous требует явного runtime-диалога. Normal нельзя отозвать через настройки, Dangerous можно отключить в любой момент. Эта асимметрия закладывает разные паттерны разработки.
С точки зрения кода, опасные разрешения требуют больше работы: checkSelfPermission, requestPermissions, обработка отказа. Для нормальных достаточно одной строки в AndroidManifest.xml. При этом Dangerous Permission даёт пользователю контроль, что повышает доверие, особенно для чувствительных функций вроде камеры или геолокации.
Выбор между категориями не стоит перед разработчиком — он определяется системой. Разработчик лишь объявляет uses-permission, а система на основе protectionLevel определяет категорию. Однако стратегия запроса опасных разрешений влияет на пользовательский опыт: частые или неуместные диалоги снижают рейтинг приложения.
Современный способ запроса разрешений в Kotlin — использование ActivityResultContracts.RequestMultiplePermissions или RequestPermission. Эти контракты входят в библиотеку androidx.activity и предоставляют чистый API на основе лямбд, без необходимости переопределять 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
)
}
}
}
Когда приложению нужно несколько опасных разрешений одновременно, используйте RequestMultiplePermissions. Контракт возвращает Map<String, Boolean>, где ключ — имя разрешения, значение — результат. Это удобно при первом запуске, когда нужно запросить CAMERA и RECORD_AUDIO для видеозаписи.
Если пользователь отклонил запрос, метод shouldShowRequestPermissionRationale возвращает true. Это сигнал показать объяснение, зачем разрешение нужно. Лучшая практика — показывать кастомный диалог с пояснением и кнопкой Повторить. Если пользователь повторно отклонил запрос с галочкой Never Ask Again, shouldShowRequestPermissionRationale вернёт false, и нужно перенаправлять в Settings.
Never Ask Again — это флаг, который пользователь может установить при повторном отклонении runtime-диалога. После этого стандартное диалоговое окно больше не показывается для данного разрешения. Единственный способ предоставить доступ — перенаправить пользователя в системные настройки приложений.
Разработчику нужно различать два сценария отказа: первый — когда shouldShowRequestPermissionRationale возвращает true (пользователь отклонил, но диалог ещё можно показать), и второй — когда метод возвращает false (Never Ask Again активен, или разрешение заблокировано политикой). Во втором случае следует показывать кнопку Открыть настройки.
fun handlePermissionDenied(permission: String) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
)) {
showRationaleDialog(permission)
} else {
showSettingsRedirectDialog(permission)
}
}
private fun showSettingsRedirectDialog(permission: String) {
AlertDialog.Builder(this)
.setTitle("Доступ запрещён")
.setMessage(
"Разрешение заблокировано. Откройте настройки."
)
.setPositiveButton("Настройки") { _, _ ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package", packageName, null
)
)
startActivity(intent)
}
.show()
}
Важно не запрашивать разрешение повторно, если shouldShowRequestPermissionRationale вернул false. Повторный вызов requestPermissions в этом случае не покажет диалог — результат придёт мгновенно с DENIED без объяснения. Пользователь столкнётся с непонятным поведением, что негативно скажется на опыте использования приложения.
Часто задаваемые вопросы
К Dangerous Permission относятся разрешения с ProtectionLevel dangerous: CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, READ_CONTACTS, READ_SMS, READ_CALENDAR и другие. Полный список доступен в классе Manifest.permission.
Используйте ContextCompat.checkSelfPermission, передав контекст и имя разрешения. Метод возвращает PERMISSION_GRANTED или PERMISSION_DENIED. Проверку нужно выполнять перед каждым вызовом API, требующего опасного разрешения.
Permission Group объединяет связанные опасные разрешения. Если пользователь предоставил одно разрешение из группы, остальные предоставляются автоматически. Например, LOCATION включает ACCESS_FINE_LOCATION и ACCESS_COARSE_LOCATION.
Проверьте shouldShowRequestPermissionRationale после отказа. Если метод вернул false и разрешение всё ещё не предоставлено — значит активирован Never Ask Again. Перенаправьте пользователя в Settings через Intent с ACTION_APPLICATION_DETAILS_SETTINGS.
Да, они остаются обязательными. На Android 13+ изменились некоторые разрешения: POST_NOTIFICATIONS стало отдельным runtime-разрешением, а READ_EXTERNAL_STORAGE заменено на READ_MEDIA_IMAGES для точечного доступа к медиа-файлам.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также