Info.plist Usage Description — это обязательные ключи в файле Info.plist приложения iOS, которые содержат текст, отображаемый пользователю при запросе доступа к системным функциям: камере, микрофону, геолокации, фотоальбому и другим. Каждый такой ключ имеет префикс NS*UsageDescription и предоставляет строку, объясняющую причину запроса доступа. Согласно Apple Information Property List Guide, отсутствие ключа для запрашиваемого ресурса приводит к немедленному крашу приложения.
Главное
Info.plist Usage Description — это строковые значения ключей с префиксом NS*UsageDescription, которые определяют текст системного диалога при запросе доступа к защищённым ресурсам iOS. Когда приложение впервые вызывает API, требующее разрешения пользователя (например, AVCaptureDevice для камеры), iOS показывает диалог с этим текстом и кнопками разрешения или отказа.
Текст описания — единственное, что разработчик может контролировать в системном диалоге. Заголовок диалога «Приложение хочет получить доступ к [ресурсу]» генерируется iOS автоматически на основе типа запрашиваемого ресурса. Разработчик не может изменить заголовок, кнопки или внешний вид — только текст объяснения.
Usage Description тесно связан с моделью runtime permissions в iOS. Пользователь предоставляет разрешение на один запрос, которое может быть отозвано позже через Настройки. При повторном запросе диалог не показывается — приложение должно проверять статус разрешения и реагировать соответствующим образом.
Apple настоятельно рекомендует указывать в описании конкретную причину запроса доступа. Например, «Для съёмки фотографий профиля» лучше, чем «Для доступа к камере». Конкретные тексты повышают доверие пользователя и процент предоставленных разрешений. По данным Localytics (2023), кастомные описания увеличивают согласие на 15-25% по сравнению с общими формулировками.
Не путайте NS*UsageDescription с ATT (App Tracking Transparency). Usage Description — это запрос доступа к системным ресурсам (камера, геолокация, фото), а ATT — запрос на отслеживание (доступ к IDFA). ATT использует отдельный фреймворк AppTrackingTransparency и ключ NSUserTrackingUsageDescription, который не относится к NS*UsageDescription.
Общее между ними — оба используют системный диалог с текстом, который приложение не может модифицировать. Разница в том, что Usage Description работает на уровне ресурсов, а ATT — на уровне идентификатора устройства. Ключи NS*UsageDescription были введены с iOS 6, ATT — с iOS 14.5.
С каждым выпуском iOS Apple добавляла новые защищённые ресурсы и соответствующие ключи. iOS 6: контакты, календарь, напоминания, фото. iOS 7: микрофон. iOS 8: HomeKit, Health,. iOS 10: медиатека, Siri. iOS 11: NFC. iOS 14: отслеживание (ATT). iOS 17: доступ к буферу обмена (требует дополнительного подтверждения).
Важно: если приложение использует API, появившееся в определённой версии iOS, но минимальная поддерживаемая версия ниже, ключ всё равно обязателен. iOS проверяет наличие ключа перед первым вызовом API, независимо от версии, на которой запущено приложение.
Полный список ключей зависит от того, какие функции использует приложение. Рассмотрим 14 основных ключей, которые чаще всего требуются в мобильных приложениях.
Ключ NSCameraUsageDescription — обязателен при доступе к камере через AVCaptureDevice или UIImagePickerController с источником .camera. Ключ NSMicrophoneUsageDescription — при записи аудио через AVAudioRecorder или при съёмке видео со звуком. Оба ключа часто требуются вместе, если приложение снимает видео.
Ключ NSPhotoLibraryUsageDescription — при чтении фото и видео из пользовательской медиатеки через PHPicker или UIImagePickerController. Ключ NSPhotoLibraryAddUsageDescription — если приложение только сохраняет фото, но не читает их. Первый запрашивает доступ на чтение, второй — только на запись.
Ключ NSLocationWhenInUseUsageDescription — доступ к геолокации, когда приложение активно (на экране). NSLocationAlwaysAndWhenInUseUsageDescription — доступ всегда (включая фоновый режим). iOS требует оба ключа, если нужен всегдашний доступ: сначала WhenInUse, потом Always.
Ключи NSLocationTemporaryUsageDescription и NSLocationPreciseUsageDescription — дополнительные ключи для запроса временного доступа или точной геолокации. Точная локация требует отдельного разрешения, и пользователь может включить только приблизительную.
| Ключ | Ресурс | Доступен с iOS |
|---|---|---|
| NSCameraUsageDescription | Камера | 6.0 |
| NSMicrophoneUsageDescription | Микрофон | 7.0 |
| NSPhotoLibraryUsageDescription | Медиатека (чтение) | 6.0 |
| NSPhotoLibraryAddUsageDescription | Медиатека (запись) | 11.0 |
| NFCReaderUsageDescription | NFC | 11.0 |
Ключ NSContactsUsageDescription — доступ к контактам пользователя через CNContactStore. NSCalendarsUsageDescription — доступ к календарю для чтения и создания событий. NSRemindersUsageDescription — доступ к напоминаниям. NSBluetoothAlwaysUsageDescription — доступ к Bluetooth в фоне (например, для BLE-устройств).
Ключ NSHealthShareUsageDescription — доступ к чтению данных HealthKit. NSHealthUpdateUsageDescription — доступ к записи данных в HealthKit. Оба обязательны, если приложение работает со здоровьем. Apple тщательно проверяет приложения, использующие HealthKit, и может отклонить, если описание использования не соответствует функционалу.
Текст в Usage Description должен быть конкретным, правдивым и лаконичным. Apple даёт рекомендации по формулировкам, а модераторы проверяют их соответствие функциональности.
Хорошее описание состоит из трёх частей: что именно делает приложение с ресурсом, зачем это нужно пользователю, и какая выгода пользователю от предоставления доступа. Пример: «Для съёмки фотографий профиля и их загрузки в анкету». Избегайте общих фраз: «Для улучшения работы приложения» не объясняет, зачем нужна камера.
Apple запрещает вводящие в заблуждение описания. Если написано «Для съёмки фото», но приложение также записывает видео, это может быть расценено как обман. Модератор может отклонить приложение или запросить разъяснения. В iOS 17 Apple добавила автоматическую проверку: описание должно содержать ключевые слова, соответствующие запрашиваемому ресурсу.
Локализация: описание должно быть переведено на все языки, которые поддерживает приложение. Если приложение доступно на 10 языках, каждый ключ Usage Description должен иметь переводы в файлах Localizable.strings или в InfoPlist.strings. Apple рекомендует использовать InfoPlist.strings для локализации ключей Info.plist.
Для локализации Usage Description не нужно дублировать Info.plist на каждый язык. Создайте файл InfoPlist.strings в каждом языковом каталоге и укажите значения ключей. iOS автоматически подставит нужный язык в диалог. Xcode поддерживает базовую локализацию для Info.plist начиная с версии 14.
<!-- InfoPlist.strings (Russian) -->
"NSCameraUsageDescription" =
"Для сканирования QR-кодов";
"NSPhotoLibraryUsageDescription" =
"Для загрузки изображений в профиль";
"NSLocationWhenInUseUsageDescription" =
"Для отображения ближайших магазинов на карте";
Правильная реализация Usage Description включает добавление ключей в Info.plist, проверку статуса разрешения в коде и обработку отказа.
В Xcode откройте Info.plist, наведите на строку и нажмите «+». Введите название ключа (например, NSCameraUsageDescription) и укажите строку описания. Xcode автодополняет имена ключей, что снижает риск опечаток. После добавления пересоберите проект и проверьте, что ключ отображается в итоговом бинарнике.
Важно: ключи регистрозависимы. NSCameraUsageDescription — верно, NSCamerausagedescription — ошибка. Неверный ключ игнорируется, и приложение упадёт при вызове API. Используйте копирование из документации Apple или автодополнение Xcode для исключения опечаток.
import AVFoundation
import Photos
final class PermissionManager {
static func checkCameraPermission() {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
print("Camera access: \(granted)")
}
case .denied:
print("Camera access denied")
case .authorized:
print("Camera access authorized")
@unknown default:
break
}
}
static func requestPhotoLibraryAccess() {
PHPhotoLibrary.requestAuthorization { status in
print("Photo library status: \(status.rawValue)")
}
}
}
Если пользователь отказал в доступе, приложение не должно повторно вызывать системный диалог — это невозможно. Вместо этого покажите информационный экран с объяснением, как включить доступ через Настройки, и кнопку «Открыть настройки» (UIApplicationOpenSettingsURLString). Такая практика повышает user experience и вероятность того, что пользователь включит доступ.
Не показывайте алерт с просьбой включить доступ сразу после отказа — дайте пользователю возможность понять, почему ему может понадобиться эта функция. Лучше показать объяснение при попытке использования функциональности, которая требует данного разрешения. UX Movement (2023) рекомендует показывать экран объяснения через 2-3 сессии после отказа.
func showSettingsAlert(for feature: String) {
let alert = UIAlertController(
title: "Доступ к \(feature)",
message: "Разрешите доступ в Настройках, "
+ "чтобы использовать эту функцию",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(
title: "Открыть Настройки",
style: .default
) { _ in
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
})
alert.addAction(UIAlertAction(
title: "Не сейчас", style: .cancel
))
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true)
}
Отсутствие обязательного ключа Usage Description приводит к немедленному крашу приложения при первом вызове соответствующего API. Это не предупреждение Xcode, а runtime crash с исключениемNSInvalidArgumentException с сообщением в консоль: «This app has crashed because it attempted to access privacy-sensitive data without a usage description».
iOS проверяет наличие ключа NS*UsageDescription в Info.plist при первом вызове API для защищённого ресурса. Если ключ отсутствует, ОС немедленно завершает приложение с сигналом SIGABRT. Это происходит даже на устройствах с отладкой — Xcode показывает exception в логе, но отладчик его не ловит как точку останова.
Краш воспроизводится на реальных устройствах и симуляторе. Единственный способ избежать — добавить ключ до вызова API. Статический анализатор Xcode не всегда предупреждает об отсутствии ключа, особенно если API вызывается через сторонние SDK. TestFlight тестеры также увидят краш, что может привести к негативным отзывам.
Особая ситуация с iOS 17+: Apple ввела дополнительную проверку для доступа к буферу обмена (UIPasteboard). Если приложение читает буфер обмена без явного действия пользователя, iOS показывает баннер с предупреждением, даже если ключ Usage Description присутствует. Для буфера обмена отдельный ключ не требуется, но Apple рекомендует минимизировать автоматическое чтение.
Помимо runtime-краша, отсутствие ключа может стать причиной отклонения приложения при модерации. Apple проверяет Info.plist на этапе ревью и может отклонить сборку, если обнаружит вызовы API без соответствующих ключей. Xcode не блокирует архивацию, но App Store Connect может вернуть ошибку при обработке бинарника.
Если приложение не использует ресурс напрямую, но сторонний SDK делает это (например, SDK аналитики запрашивает IDFA), разработчик всё равно должен добавить соответствующий ключ. Apple проверяет все вызовы API в бинарнике, включая код из статических и динамических библиотек. Ошибка «Missing Info.plist key» — одна из самых частых причин отклонения обновлений.
Часто задаваемые вопросы
Да, если сторонний SDK вызывает API доступа к ресурсу (камера, геолокация, фото), ключ обязателен. iOS проверяет бинарник целиком, включая зависимости, и крашит приложение при отсутствии ключа.
Нет, каждый защищённый ресурс требует отдельного ключа. Например, NSCameraUsageDescription не заменяет NSMicrophoneUsageDescription. Система ищет конкретный ключ по имени при вызове каждого API.
Покажите экран с объяснением, как включить доступ через Настройки → Приложение, и предложите кнопку для открытия настроек приложения. Системный диалог не может быть вызван повторно программно.
Создайте файл InfoPlist.strings для каждого языка и укажите переводы. iOS автоматически использует язык устройства при показе диалога. Xcode также поддерживает базовую локализацию Info.plist.
iOS симулятор полностью воспроизводит поведение устройства, включая проверку Usage Description. Если ключ отсутствует, симулятор также завершит приложение с exception. Это ожидаемое поведение для отладки.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также