Как правильно запрашивать разрешения на iOS и Android
Практика3 минРедакция Innovialabs
Коротко
Просите разрешение в момент, когда пользователь сам делает действие, которому оно нужно, и объясняйте зачем. При отказе приложение должно продолжать работать, а частичный доступ к фото и геолокации — поддерживаться как нормальный сценарий.
Главное правило
Системное окно разрешения на iOS показывается один раз, а на Android после повторных отказов система перестаёт его показывать. Поэтому каждый запрос — это попытка, которую легко потратить впустую.
Работает простая схема:
- просить в контексте — когда пользователь нажал «Сканировать QR», а не при первом запуске;
- просить только нужное — не запрашивать геолокацию «на будущее»;
- объяснять пользу понятным языком;
- не ломать приложение при отказе.
Как устроены runtime-разрешения
iOS. Для каждого защищённого ресурса в Info.plist указывается purpose string — текст, который система покажет в диалоге. Без него приложение упадёт при обращении к ресурсу, а ревью Apple отклонит размытые формулировки.
<key>NSCameraUsageDescription</key>
<string>Камера нужна, чтобы отсканировать QR-код на чеке.</string>
Хороший purpose string отвечает на вопрос «что я получу», а не «приложению нужен доступ».
Android. Опасные разрешения объявляются в манифесте и запрашиваются во время работы:
val requestCamera = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) openScanner() else showScannerFallback()
}
requestCamera.launch(Manifest.permission.CAMERA)
Метод shouldShowRequestPermissionRationale подсказывает, что пользователь уже отказывал и стоит сначала объяснить причину. Отдельные разрешения появились в новых версиях Android — например, на показ уведомлений, — поэтому проверяйте требования для целевого API.
Предварительный экран (pre-permission)
Перед системным диалогом можно показать свой экран: иллюстрация, одно предложение о пользе и кнопка, которая вызывает системный запрос.
- Кнопки — «Продолжить» и «Не сейчас». Не имитируйте системный диалог и не пишите «Разрешить» на кнопке, которая ничего не разрешает.
- «Не сейчас» должно реально пропускать шаг, без блокировки.
- Если пользователь отказался на своём экране, системный диалог не тратится — можно спросить позже, в подходящий момент.
Отказ и частичный доступ
Отказ. Предложите альтернативу: ввести адрес вручную вместо геолокации, выбрать файл вместо камеры. Если без разрешения функция невозможна, объясните это и дайте кнопку перехода в настройки приложения.
Фото. Пользователь может дать доступ только к выбранным фотографиям, и на iOS, и на новых версиях Android. Это нормальный сценарий: показывайте доступные фото и давайте возможность выбрать ещё. А если нужно просто загрузить аватар, используйте системный фото-пикер — он вообще не требует разрешения.
Геолокация. Есть точная и приблизительная локация, а также доступ «при использовании» и «всегда». Для погоды или ближайшего города хватит приблизительной. Фоновую геолокацию запрашивайте отдельно и только если без неё функция действительно не работает.
Уведомления. Не просите при первом запуске. Лучше после действия, где польза очевидна: «Сообщить, когда заказ будет в пути?». На iOS есть provisional-уведомления — они приходят тихо без запроса, и пользователь сам решает, оставить ли их.
Чего ждут магазины
- App Store: purpose strings должны конкретно объяснять использование данных. Нельзя принуждать к согласию, блокировать приложение из-за отказа без необходимости или вводить в заблуждение предварительными экранами.
- Google Play: для чувствительных разрешений (фоновая геолокация, доступ ко всем файлам, SMS и журнал звонков и другие) нужно заполнить декларацию в Play Console и доказать, что функция — ключевая. Иначе обновление отклонят.
- Список разрешений должен совпадать с ответами в Privacy-метках и Data Safety.
Частые ошибки
- Серия запросов при первом запуске.
- Лишние разрешения, оставшиеся от SDK или старых функций.
- Шаблонные purpose strings вроде «Приложению нужен доступ к камере».
- Пустой экран после отказа вместо альтернативы.