Запрос runtime‑permissions и обработка отказа

В первых 200 символах: проверяйте permission через ContextCompat.checkSelfPermission, запрашивайте через ActivityResultLauncher (или ActivityCompat.requestPermissions), показывайте rationale при необходимости и, при постоянном отказе, переводите пользователя в настройки через Settings.ACTION_APPLICATION_DETAILS_SETTINGS.

Как запрашивать permission — кратко и практично

  1. Добавьте разрешение в AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
  1. Перед операцией проверьте текущее состояние:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
    != PackageManager.PERMISSION_GRANTED) {
    // нужно запросить
}
  1. Используйте Activity Result API (рекомендуется) вместо устаревшего onRequestPermissionsResult:
private val requestCameraLauncher =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
        if (granted) openCamera() else handleCameraDenied()
    }

// Запрос
requestCameraLauncher.launch(Manifest.permission.CAMERA)
  1. Если нужен набор разрешений (камера + запись), используйте 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 .

Соблюдая эти правила, вы уменьшите число отказов, избежите сбоев и сделаете поведение приложения предсказуемым и дружелюбным для пользователя.