Запрос runtime‑permissions и обработка отказа
В первых 200 символах: проверяйте permission через ContextCompat.checkSelfPermission, запрашивайте через ActivityResultLauncher (или ActivityCompat.requestPermissions), показывайте rationale при необходимости и, при постоянном отказе, переводите пользователя в настройки через Settings.ACTION_APPLICATION_DETAILS_SETTINGS.
Как запрашивать permission — кратко и практично
- Добавьте разрешение в AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
- Перед операцией проверьте текущее состояние:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// нужно запросить
}
- Используйте Activity Result API (рекомендуется) вместо устаревшего onRequestPermissionsResult:
private val requestCameraLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) openCamera() else handleCameraDenied()
}
// Запрос
requestCameraLauncher.launch(Manifest.permission.CAMERA)
- Если нужен набор разрешений (камера + запись), используйте ActivityResultContracts.RequestMultiplePermissions.
Обязательное UX: rationale и обработка отказа
- Покажите пользователю короткое объяснение (rationale) перед запросом, если действие не очевидно: "Камера нужна для фото профиля".
Запрашивайте разрешение в контексте действия пользователя (lazy request): при клике на кнопку «Сделать фото», а не при старте приложения.
- После отказа проверяйте shouldShowRequestPermissionRationale():
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
// показать диалог с объяснением и повторить запрос
} else {
// вероятно отмечено "Не спрашивать снова" — предложить открыть настройки
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}
- Если функция не критична — отключите её и объясните пользователю альтернативу ("Фото недоступно без разрешения").
Не полагайтесь на onRequestPermissionsResult без проверки grantResults — это частая причина ошибок. Используйте Activity Result API, он проще и надёжнее.
Практические рекомендации и сценарии
- Минимизируйте набор запросов: просите только то, что нужно сейчас.
- Группируйте логично (камера + микрофон — для видео).
- Тестируйте на разных версиях Android: поведение и набор разрешений меняются (например, Android 11+ — Scoped Storage; Android 13 — разграничение уведомлений).
- Для специальных разрешений (SYSTEM_ALERT_WINDOW, MANAGE_EXTERNAL_STORAGE) направляйте пользователя в системные настройки — они не запрашиваются обычным диалогом.
Сравнение подходов к обработке отказа
| Сценарий | Рекомендация | Почему |
|---|---|---|
| Первый отказ | Показать rationale и повторить запрос | Около 40% меняют решение после объяснения |
| Отмечено "Не спрашивать снова" | Предложить открыть настройки приложения | Единственный способ вернуть разрешение пользователем |
| Частичный грант (несколько permissions) | Проверять все grantResults | Избежите NPE и некорректной логики |
Частые ошибки
- Запросы при старте приложения без объяснения.
- Игнорирование shouldShowRequestPermissionRationale().
- Необработка всех возможных grantResults при множественных разрешениях.
- Использование устаревших API вместо Activity Result API.
FAQ
- Нужно ли указывать разрешение в манифесте и запрашивать в runtime?
- Да. Для dangerous‑permissions требуется и декларация в манифесте, и runtime‑запрос.
- Что делать, если пользователь постоянно отказывает?
- Отключайте функциональность с понятным объяснением и предлагайте альтернативы или путь в настройки.
- Как тестировать запросы?
- На эмуляторе и реальных устройствах; через ADB можно давать/отзывать разрешения: adb shell pm grant|revoke
.
- На эмуляторе и реальных устройствах; через ADB можно давать/отзывать разрешения: adb shell pm grant|revoke
Соблюдая эти правила, вы уменьшите число отказов, избежите сбоев и сделаете поведение приложения предсказуемым и дружелюбным для пользователя.