Info.plist Usage Description 是 iOS 应用 Info.plist 文件中的必需键,包含在请求访问系统功能(相机、麦克风、地理位置、相册等)时显示给用户的文本。每个此类键都以 NS*UsageDescription 为前缀,并提供解释请求访问原因的字符串。根据 Apple Information Property List Guide,缺少所请求资源的键将导致应用立即崩溃。
要点
Info.plist Usage Description 是带有 NS*UsageDescription 前缀的键的字符串值,用于定义在请求访问 iOS 受保护资源时系统对话框显示的文本。当应用首次调用需要用户权限的 API(例如用于相机的 AVCaptureDevice)时,iOS 会显示包含此文本以及允许或拒绝按钮的对话框。
描述文本是开发者在系统对话框中唯一可以控制的内容。对话框标题“应用想要访问[资源]”由 iOS 根据所请求的资源类型自动生成。开发者无法更改标题、按钮或外观 —— 只能更改解释文本。
Usage Description 与 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:访问剪贴板(需要额外确认)。
重要提示:如果应用使用了在特定 iOS 版本中引入的 API,但最低支持版本更低,该键仍然是必需的。iOS 会在 首次调用 API 之前检查键是否存在,无论应用运行在哪个版本上。
完整的键列表取决于应用使用了哪些功能。让我们来看看移动应用中最常需要的 14 个主要键。
NSCameraUsageDescription 键 —— 通过 AVCaptureDevice 或使用 .camera 源的 UIImagePickerController 访问相机时必需。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 —— 在后台访问蓝牙(例如用于 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 从版本 14 开始支持 Info.plist 的 基本本地化。
<!-- InfoPlist.strings (Russian) -->
"NSCameraUsageDescription" =
"用于扫描二维码";
"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)。这种做法可以改善 用户体验,并增加用户启用访问的可能性。
不要在拒绝后立即显示要求启用访问的弹窗 —— 让用户有机会理解为什么他们可能需要此功能。最好在尝试使用需要该权限的功能时显示解释。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 警告,而是 运行时崩溃,伴有 NSInvalidArgumentException 异常和控制台消息:“This app has crashed because it attempted to access privacy-sensitive data without a usage description”。
iOS 在首次调用受保护资源的 API 时会检查 Info.plist 中是否存在 NS*UsageDescription 键。如果缺少该键,系统会立即使用 SIGABRT 信号终止应用。即使在调试设备上也会发生这种情况 —— Xcode 会在日志中显示异常,但调试器不会将其捕获为断点。
崩溃会出现在真实设备和模拟器上。避免崩溃的唯一方法是在调用 API 之前添加键。Xcode 的静态分析器并不总是警告键的缺失,特别是当 API 通过第三方 SDK 调用时。TestFlight 测试员也会看到崩溃,这可能导致负面评论。
iOS 17+ 的特殊情况:Apple 增加了对剪贴板(UIPasteboard)访问的额外检查。如果应用在没有用户明确操作的情况下读取剪贴板,即使 Usage Description 键存在,iOS 也会显示警告横幅。剪贴板不需要单独的键,但 Apple 建议 尽量减少自动读取。
除了运行时崩溃外,缺少键也可能是应用在审核过程中被拒绝的原因。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 检查。如果键缺失,模拟器也会以异常终止应用。这是调试时预期的行为。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。