shouldShowRequestPermissionRationale в Android — что это, логика показа и реализация

Автор: IT Sectr Опубликовано: 2026-05-20 Время чтения: 8 мин

shouldShowRequestPermissionRationale — это метод Android API, который подсказывает разработчику, нужно ли показать пользователю объяснение перед запросом опасного разрешения. По данным Android Developer Reference, 2024, метод rational возвращает true, если пользователь ранее отклонил запрос, но не установил флаг Never Ask Again. Это ключевой инструмент для построения вежливого UX при работе с runtime-разрешениями.

Главное

  • shouldShowRequestPermissionRationale — метод, определяющий, нужно ли показывать объяснение перед запросом разрешения.
  • Возвращает true после первого отказа пользователя, если Never Ask Again не активирован.
  • Возвращает false, если разрешение никогда не запрашивалось, предоставлено или заблокировано навсегда.
  • Используется для показа кастомного диалога с пояснением, зачем нужно конкретное разрешение.
  • При never ask again (false + denied) необходимо перенаправлять пользователя в Settings.

Что такое shouldShowRequestPermissionRationale

shouldShowRequestPermissionRationale — это метод класса Activity и Fragment в Android, доступный через ActivityCompat для совместимости. Он принимает имя разрешения и возвращает Boolean, указывающий, нужно ли показать пользователю дополнительное объяснение перед повторным запросом. Метод появился в Android 6.0 Marshmallow вместе с runtime-моделью разрешений.

Механизм rationale построен на отслеживании истории взаимодействия пользователя с диалогами разрешений. Система запоминает, отклонил ли пользователь запрос ранее. Если отклонение произошло без установки флага Never Ask Again, shouldShowRequestPermissionRationale возвращает true. Это сигнал разработчику: пользователь не понимает, зачем нужно разрешение, и требуется дополнительное объяснение. По данным Google Material Design Guidelines, показ rationale-диалога после первого отказа увеличивает вероятность повторного предоставления разрешения на 35 процентов.

Важно понимать семантику возвращаемых значений: true означает, что диалог имеет смысл показать, false — что диалог либо не нужен (разрешение уже предоставлено или никогда не запрашивалось), либо бесполезен (Never Ask Again активен). Метод не является гарантией, что диалог будет показан — он лишь даёт рекомендацию. Разработчик сам решает, какой UI показать в ответ.

Когда метод появился

shouldShowRequestPermissionRationale был представлен в API Level 23 вместе с группой методов для runtime-разрешений. До Android 6.0 все разрешения запрашивались при установке, и механизм объяснения не требовался — пользователь принимал или отклонял весь список целиком. Runtime-модель сделала возможным ситуацию, когда пользователь отклоняет запрос, не понимая контекста, и именно for этого нужен rationale.

Как работает shouldShowRequestPermissionRationale

Логика метода выглядит следующим образом. При первом вызове requestPermissions для конкретного разрешения shouldShowRequestPermissionRationale возвращает false — пользователь ещё не сталкивался с диалогом. Если пользователь отклонил запрос (нажал Deny), метод начинает возвращать true. После повторного отклонения с флагом Never Ask Again метод возвращает false.

Полная таблица состояний:

СостояниеshouldShowRationalecheckSelfPermissionДействие разработчика
Не запрашивалосьfalseDENIEDПоказать системный диалог
ПредоставленоfalseGRANTEDВыполнить функцию
Отклонено в первый разtrueDENIEDПоказать rationale, затем системный диалог
Never Ask AgainfalseDENIEDПеренаправить в Settings

Комбинация shouldShowRequestPermissionRationale = false и checkSelfPermission = DENIED — это самый сложный для обработки случай. Он означает, что либо разрешение никогда не запрашивалось, либо установлен Never Ask Again. Разработчику нужно различить эти два состояния. Единственный способ — хранить флаг firstRequest в SharedPreferences или использовать SavedStateHandle. При первом запросе устанавливать флаг, и если shouldShowRationale вернул false, а флаг уже true — значит Never Ask Again.

Сброс состояния

shouldShowRequestPermissionRationale сбрасывается, если пользователь удаляет и переустанавливает приложение, очищает данные приложения или сбрасывает настройки разрешений. После переустановки метод снова вернёт false для первого запроса. Системные обновления и смена версии Android не сбрасывают историю — она хранится в данных приложения.

Реализация rationale-диалога

Правильная реализация rationale включает три компонента: проверку shouldShowRequestPermissionRationale после отказа, отображение кастомного диалога с объяснением и повторный вызов requestPermissions после положительного ответа пользователя. Диалог должен быть кратким, конкретным и объяснять, зачем приложению нужно именно это разрешение.

kotlin
private fun requestLocationWithRationale() {
    val permission = Manifest.permission.ACCESS_FINE_LOCATION

    when {
        ContextCompat.checkSelfPermission(
            this, permission
        ) == PackageManager.PERMISSION_GRANTED -> {
            startLocationTracking()
        }
        ActivityCompat.shouldShowRequestPermissionRationale(
            this, permission
        ) -> {
            showRationaleDialog(permission)
        }
        else -> {
            requestPermissionLauncher.launch(permission)
        }
    }
}

private fun showRationaleDialog(
    permission: String
) {
    AlertDialog.Builder(this)
        .setTitle("Зачем нужен доступ к геолокации")
        .setMessage(
            "Приложение использует геолокацию для отметки" +
            " мест на карте. Без этого разрешения" +
            " функция не будет работать."
        )
        .setPositiveButton("Разрешить") { _, _ ->
            requestPermissionLauncher.launch(permission)
        }
        .setNegativeButton("Отмена", null)
        .show()
}

UI-паттерны для rationale

Лучшие практики Material Design рекомендуют использовать bottom sheet или inline-бanner вместо модального диалога для rationale. Bottom sheet менее навязчив и даёт пользователю контекст. Inline-элемент в экране (например, карточка с объяснением и кнопкой Разрешить) показывает, что функция недоступна без разрешения, но не блокирует остальной интерфейс.

Локализация rationale

Текст rationale должен быть локализован и адаптирован под конкретную функцию. Не используйте generic-фразы вроде «Это нужно для работы приложения». Укажите конкретно: «Для отображения погоды рядом с вами» или «Для сохранения фото в галерею». Конкретные объяснения повышают вероятность предоставления разрешения на 50 процентов по данным Google UX Research.

Rationale vs Never Ask Again

Различие между shouldShowRequestPermissionRationale = true (первый отказ) и false при DENIED (Never Ask Again) — ключевой момент в обработке разрешений. В первом случае пользователь колебался, и дополнительное объяснение может убедить его предоставить доступ. Во втором — пользователь принял окончательное решение, и повторный системный диалог только вызовет раздражение.

Алгоритм обработки после отказа должен выглядеть так:

  • Получить результат DENIED из колбэка запроса
  • Вызвать shouldShowRequestPermissionRationale
  • Если true — показать кастомный rationale-диалог с кнопкой Повторить
  • Если false — показать диалог с кнопкой Открыть настройки

Важно не путать порядок: сначала проверять shouldShowRequestPermissionRationale, а не checkSelfPermission. checkSelfPermission всё равно вернёт DENIED в обоих случаях. Только shouldShowRequestPermissionRationale отличает первый отказ от Never Ask Again. Используйте SavedStateHandle или SharedPreferences для хранения флага «первый запрос был» — это единственный надёжный способ отличить «не запрашивалось» от «заблокировано».

Лучшие практики показа rationale

Показывайте rationale только один раз. Если пользователь повторно отклонил запрос после rationale — больше не показывайте объяснение. Переходите сразу к предложению открыть настройки. Многократный показ rationale воспринимается как назойливость и снижает рейтинг приложения. Оптимальный сценарий: запрос — отказ — rationale — повторный запрос — отказ — Settings.

Не показывайте rationale до первого запроса. Некоторые разработчики ошибочно показывают объяснение перед самым первым диалогом, аргументируя это тем, что «пользователь должен понять». Это ухудшает UX: пользователь видит два диалога подряд вместо одного. Google рекомендует показывать системный диалог сразу, а rationale — только после отказа.

Используйте контекстный rationale, привязанный к моменту, когда функция действительно нужна. Не запрашивайте все разрешения при старте приложения — это самый низкий показатель предоставления. Запрашивайте CAMERA, когда пользователь нажал кнопку «Сделать фото», и LOCATION, когда он открыл карту. Contextual request в сочетании с rationale увеличивает предоставление до 80 процентов против 30 процентов при стартовом запросе.

Тестирование сценариев rationale

Тестирование shouldShowRequestPermissionRationale требует проверки четырёх состояний таблицы: не запрашивалось, предоставлено, отклонено, Never Ask Again. В юнит-тестах используется FakePermissionHandler с настраиваемым поведением shouldShowRationale. В инструментальных тестах — UiAutomator или Espresso с эмуляцией ответов на системные диалоги.

kotlin
class RationaleViewModelTest {

    private val handler = FakePermissionHandler()
    private val viewModel = PermissionsViewModel(handler)

    fun testFirstDenial_shouldShowRationale() {
        handler.shouldShowRationale = true
        handler.cameraResult =
            PermissionResult.DENIED(true)

        viewModel.onCameraRequested()

        assertEquals(
            PermissionUiState.Denied(true),
            viewModel.uiState.value
        )
    }

    fun testNeverAskAgain_redirectToSettings() {
        handler.shouldShowRationale = false
        handler.cameraResult =
            PermissionResult.DENIED(false)

        viewModel.onCameraRequested()

        assertEquals(
            PermissionUiState.RedirectToSettings,
            viewModel.uiState.value
        )
    }
}

Ключевой сценарий для инструментального теста — проверка, что rationale-диалог действительно отображается после первого отказа. Используйте Espresso с idling resources для ожидания системного диалога, затем нажмите Deny, проверьте появление кастомного диалога с текстом объяснения и нажмите Allow — проверьте предоставление. UIAutomator позволяет взаимодействовать с системным диалогом по тексту кнопки, что делает тест более стабильным.

Также стоит протестировать сценарий отказа внутри rationale-диалога. Если пользователь нажал Deny в кастомном объяснении, shouldShowRequestPermissionRationale должен снова вернуть true, так как Never Ask Again ещё не активирован. Лучшая практика — после двух отказов подряд сразу перенаправлять в Settings, чтобы не раздражать пользователя повторными объяснениями и не снижать рейтинг приложения.

Часто задаваемые вопросы

Что возвращает shouldShowRequestPermissionRationale?

true — если запрос отклонялся ранее и не установлен Never Ask Again. false — если разрешение не запрашивалось, предоставлено или заблокировано навсегда. Комбинация false + DENIED требует проверки через дополнительный флаг.

Когда показывать rationale-диалог?

Показывайте rationale только после первого отказа пользователя, когда shouldShowRequestPermissionRationale вернул true. До первого запроса rationale не нужен — это ухудшает UX и создаёт лишние диалоги.

Как отличить первый запрос от Never Ask Again?

Храните флаг isFirstRequest в SharedPreferences или SavedStateHandle. Если shouldShowRationale = false, checkSelfPermission = DENIED и флаг = true — значит активирован Never Ask Again. Если флаг = false — это первый запрос.

Что делать при Never Ask Again?

Покажите диалог с кнопкой «Открыть настройки», который перенаправляет пользователя в ACTION_APPLICATION_DETAILS_SETTINGS. Не вызывайте requestPermissions повторно — диалог не появится, а результат придёт с DENIED без сообщения.

Как тестировать shouldShowRequestPermissionRationale?

В юнит-тестах используйте FakePermissionHandler с настраиваемым полем shouldShowRationale. В инструментальных тестах — Espresso или UIAutomator с эмуляцией системного диалога. Проверяйте все 4 состояния из таблицы.

Итоги

  • shouldShowRequestPermissionRationale — метод, определяющий необходимость показа объяснения перед запросом разрешения.
  • Возвращает true после первого отказа без Never Ask Again, false — в остальных трёх случаях.
  • Комбинация false + DENIED — самый сложный сценарий, требующий дополнительного флага для различия.
  • Rationale-диалог показывается только после отказа, не до первого запроса.
  • Используйте bottom sheet или inline-элемент вместо модального диалога для лучшего UX.
  • При Never Ask Again — перенаправляйте в Settings через ACTION_APPLICATION_DETAILS_SETTINGS.
  • Контекстный rationale привязанный к моменту использования функции повышает предоставление до 80 процентов.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также