iOS Info.plist与项目结构入门
Info.plist是iOS应用的配置核心,定义了应用标识、权限、界面方向等关键信息,理解其结构是iOS开发的基础。
一句话概括(面试开口第一句)
Info.plist是iOS应用的”配置中枢”,通过键值对定义应用唯一标识、版本号、权限需求、界面方向等关键信息,是Xcode项目结构的核心配置文件。
背景:为什么这个知识点重要
- 应用身份标识:
CFBundleIdentifier是App Store和系统识别应用的唯一ID,不可重复 - 版本管理:
CFBundleShortVersionString(营销版本)和CFBundleVersion(构建版本)共同决定应用更新逻辑 - 权限声明:访问相机、相册、位置等敏感资源必须在Info.plist中声明使用目的
- 设备兼容性:通过
UIRequiredDeviceCapabilities等键控制应用支持的设备范围 - 启动配置:启动图、主界面、支持的方向等影响用户体验的第一印象
- 安全策略:ATS(App Transport Security)等安全配置在此定义
概念与定义
Info.plist(Information Property List)是iOS/macOS等Apple平台应用的核心配置文件,位于应用Bundle的根目录(iOS)或Contents目录(macOS)。它是一个属性列表(Property List)文件,采用XML或二进制格式,包含描述应用基本特征和行为的键值对。
Xcode项目结构中,Info.plist通常位于项目名/Supporting Files/目录下,文件名通常为项目名-Info.plist。在构建过程中,Xcode会将其编译并复制到最终应用的Bundle中。
属性列表(Property List)是Apple平台用于存储结构化数据的标准格式,支持String、Number、Boolean、Array、Dictionary等数据类型,可通过XML或二进制序列化。
最小示例(10秒看懂)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 应用标识 -->
<key>CFBundleIdentifier</key>
<string>com.example.MyApp</string>
<!-- 版本信息 -->
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<!-- 应用名称 -->
<key>CFBundleDisplayName</key>
<string>我的应用</string>
<!-- 主界面 -->
<key>UIMainStoryboardFile</key>
<string>Main</string>
<!-- 支持的方向 -->
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<!-- 隐私权限声明 -->
<key>NSCameraUsageDescription</key>
<string>需要相机功能来拍摄照片</string>
</dict>
</plist>
核心知识点拆解(面试时能结构化输出)
1. 应用基本信息类键
- CFBundleIdentifier:应用唯一标识,反向域名格式(如
com.company.appname) - CFBundleName:应用内部名称,默认与目标名称相同
- CFBundleDisplayName:用户可见的应用名称(显示在Springboard)
- CFBundleShortVersionString:营销版本号,用户可见(如
"1.0.0") - CFBundleVersion:构建版本号,用于内部追踪(每次提交递增)
2. 界面与启动配置类键
- UIMainStoryboardFile / UIMainStoryboardFile~ipad:主故事板文件
- UILaunchStoryboardName:启动故事板(替代Launch Images)
- UISupportedInterfaceOrientations:支持的界面方向
UIInterfaceOrientationPortrait(竖屏,Home键在下)UIInterfaceOrientationLandscapeLeft(横屏,Home键在左)UIInterfaceOrientationLandscapeRight(横屏,Home键在右)UIInterfaceOrientationPortraitUpsideDown(竖屏倒置)
3. 隐私权限描述类键(iOS 10+强制)
- NSCameraUsageDescription:相机使用描述
- NSPhotoLibraryUsageDescription:相册使用描述
- NSLocationWhenInUseUsageDescription:使用时定位描述
- NSMicrophoneUsageDescription:麦克风使用描述
- NSContactsUsageDescription:通讯录使用描述
4. 设备兼容性与特性类键
- UIRequiredDeviceCapabilities:必需设备能力(如
armv7、opengles-2) - UISupportedInterfaceOrientations~ipad:iPad专用方向配置
- UISupportedInterfaceOrientations~iphone:iPhone专用方向配置
5. 安全与网络类键
- NSAppTransportSecurity:应用传输安全配置(ATS)
- NSExceptionDomains:ATS例外域名配置
- NSAllowsArbitraryLoads:允许任意HTTP加载(慎用)
实战案例(2-3个)
案例1:完整的多平台应用配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- ========== 应用基本信息 ========== -->
<key>CFBundleIdentifier</key>
<string>com.yourcompany.PhotoApp</string>
<key>CFBundleName</key>
<string>PhotoApp</string>
<key>CFBundleDisplayName</key>
<string>美图秀</string>
<key>CFBundleShortVersionString</key>
<string>2.3.1</string>
<key>CFBundleVersion</key>
<string>2026031501</string> <!-- 年月日+构建号 -->
<!-- ========== 启动配置 ========== -->
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<!-- ========== 界面方向(iOS 16+推荐配置) ========== -->
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<!-- ========== 隐私权限描述(必须提供) ========== -->
<key>NSCameraUsageDescription</key>
<string>需要使用相机拍摄照片和视频</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择照片进行编辑</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要将编辑后的照片保存到相册</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取当前位置以添加地理标签</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要录制视频时的音频</string>
<!-- ========== 设备兼容性 ========== -->
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string> <!-- 支持ARMv7指令集 -->
</array>
<key>UISupportsPictureInPicture</key>
<true/> <!-- 支持画中画功能 -->
<!-- ========== 网络与安全 ========== -->
<key>NSAppTransportSecurity</key>
<dict>
<!-- 允许加载HTTP资源(仅调试使用,上架需移除) -->
<key>NSAllowsArbitraryLoads</key>
<false/>
<!-- 特定域名例外 -->
<key>NSExceptionDomains</key>
<dict>
<key>insecure-api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
<!-- ========== 应用服务 ========== -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>photoapp</string> <!-- 自定义URL Scheme -->
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
<string>weixin</string> <!-- 声明可查询的URL Scheme -->
</array>
<!-- ========== 国际化 ========== -->
<key>CFBundleDevelopmentRegion</key>
<string>en</string> <!-- 默认开发语言区域 -->
</dict>
</plist>
案例2:适配不同iOS版本的权限配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- 相机权限(所有iOS版本) -->
<key>NSCameraUsageDescription</key>
<string>需要相机拍摄照片</string>
<!-- 相册权限(iOS 14+ 细化) -->
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册选择照片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要保存照片到相册</string>
<!-- 定位权限(按使用场景) -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要在应用使用时获取位置</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>需要始终获取位置(后台定位)</string>
<!-- 通知权限(iOS 12+ 细化) -->
<key>UNAuthorizationOptions</key>
<array>
<string>alert</string>
<string>sound</string>
<string>badge</string>
</array>
<!-- 本地网络权限(iOS 14+) -->
<key>NSLocalNetworkUsageDescription</key>
<string>需要发现本地网络设备</string>
<key>NSBonjourServices</key>
<array>
<string>_http._tcp</string>
<string>_https._tcp</string>
</array>
案例3:网络安全配置(ATS)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<key>NSAppTransportSecurity</key>
<dict>
<!-- 推荐配置:严格安全策略 -->
<key>NSAllowsArbitraryLoads</key>
<false/> <!-- 禁止任意HTTP加载 -->
<!-- 例外域名配置(必须明确理由) -->
<key>NSExceptionDomains</key>
<dict>
<!-- 旧版API域名,无法升级HTTPS -->
<key>legacy-api.example.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
</dict>
<!-- 第三方服务(如广告) -->
<key>ads.thirdparty.com</key>
<dict>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
<!-- 全局TLS版本要求 -->
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.3</string>
</dict>
底层原理(精简、但关键)
1. Info.plist在应用Bundle中的位置与加载
1
2
3
4
5
6
应用Bundle结构:
MyApp.app/
├── Info.plist ← 配置文件
├── MyApp ← 可执行文件
├── Base.lproj/ ← 基础资源
└── ……
加载时机:
- 安装时:系统验证Info.plist格式和必需键
- 启动时:系统读取
CFBundleIdentifier、CFBundleExecutable等键定位应用 - 运行时:通过
[NSBundle mainBundle]的infoDictionary访问配置
2. 隐私权限描述的系统级检查
1
应用请求权限 → 系统检查Info.plist对应描述 → 弹出系统对话框
- iOS 10+强制要求:访问受保护资源必须在Info.plist提供
UsageDescription - 缺失描述的后果:应用会立即崩溃(crash with missing description)
- 描述内容要求:必须具体、真实,App Store审核会验证合理性
3. 版本号更新逻辑
1
2
CFBundleShortVersionString:用户可见,可回滚
CFBundleVersion:内部追踪,必须单调递增
- App Store更新判断:两个版本号任意一个增加即视为新版本
- TestFlight限制:
CFBundleVersion必须递增才能上传新构建 - 回滚场景:可降低
CFBundleShortVersionString(如2.0→1.9),但CFBundleVersion仍需增加
4. 多设备方向支持的实现机制
1
2
3
4
5
6
7
8
9
// 系统读取UISupportedInterfaceOrientations数组
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
// 根据设备类型返回对应配置
if (iPad) {
return [infoDict[@"UISupportedInterfaceOrientations~ipad"] convertToMask];
} else {
return [infoDict[@"UISupportedInterfaceOrientations"] convertToMask];
}
}
- 优先级:设备专用配置 > 通用配置
- 默认值:如果未指定,iPhone默认为
UIInterfaceOrientationMaskAllButUpsideDown - 运行时变化:可通过代码动态修改支持方向
5. 属性列表的二进制格式优化
1
XML格式(可读) → 编译时转换为二进制格式(高效)
- 存储效率:二进制格式比XML小30-50%
- 解析速度:二进制解析速度比XML快5-10倍
- 可逆转换:通过
plutil命令可在XML/二进制间转换
💡 人话总结:Info.plist就像应用的”简历+说明书”,系统用它来确认你是谁(Bundle ID)、能做什么(权限)、擅长什么(设备兼容性)。隐私权限描述就像”申请理由”,必须充分合理才能通过系统审核。版本号管理如同”年级+学号”,营销版本可以回滚,但内部构建号必须一直增加。
高频面试题 + 回答模板
💬 面试回答话术:
问:Info.plist是什么?包含哪些关键配置项?
答:Info.plist是iOS应用的配置文件,位于应用Bundle中,采用属性列表格式存储应用的元数据。关键配置项包括:
- 标识类:
CFBundleIdentifier(唯一包名)、CFBundleDisplayName(显示名称)- 版本类:
CFBundleShortVersionString(营销版本)、CFBundleVersion(构建版本)- 界面类:
UIMainStoryboardFile(主故事板)、UISupportedInterfaceOrientations(支持方向)- 权限类:
NSCameraUsageDescription等使用目的描述(iOS 10+强制)- 设备类:
UIRequiredDeviceCapabilities(必需硬件能力)这些配置影响应用安装、启动、权限申请和App Store审核。
问:CFBundleShortVersionString和CFBundleVersion有什么区别?
答:这两个都是版本号,但用途不同:
- CFBundleShortVersionString:用户可见的营销版本号,格式如
"1.0.0"。用于App Store展示,可以回滚(如2.0→1.9)- CFBundleVersion:内部构建版本号,格式为字符串但通常用数字,如
"123"。用于TestFlight、系统更新判断,必须单调递增关键规则:
- App Store将两个版本号都视为更新依据:任意一个增加即视为新版本
- TestFlight要求
CFBundleVersion必须递增才能上传新构建- 回滚场景:可降低
CFBundleShortVersionString,但CFBundleVersion仍需增加问:iOS隐私权限描述(UsageDescription)有什么要求?缺失会怎样?
答:iOS 10+强制要求应用在访问受保护资源前,必须在Info.plist提供对应的
UsageDescription键值对。具体要求:
- 内容必须具体真实:描述为什么需要此权限,用户利益是什么
- 禁止模板化描述:如”需要此功能”会被App Store拒绝
- 明确场景:如”需要使用相机扫描二维码登录”
缺失的后果:
- 应用会立即崩溃(crash with missing description)
- App Store审核拒绝(必须修复才能上架)
示例:
<key>NSCameraUsageDescription</key><string>需要相机扫描二维码登录</string>
进阶与易错点
易错点1:隐私权限描述缺失导致崩溃
1
2
3
4
5
6
7
8
9
<!-- ❌ 错误:iOS 10+会崩溃 -->
<!-- 代码中调用相机,但Info.plist缺少描述 -->
<!-- ✅ 正确:必须提供具体描述 -->
<key>NSCameraUsageDescription</key>
<string>需要使用相机拍摄照片上传</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册选择头像图片</string>
易错点2:版本号管理混乱导致无法上传
1
2
3
4
5
6
7
8
9
10
11
<!-- ❌ 错误:CFBundleVersion未递增,TestFlight上传失败 -->
<key>CFBundleShortVersionString</key>
<string>1.2.0</string> <!-- 增加 -->
<key>CFBundleVersion</key>
<string>20260301</string> <!-- 未变,错误 -->
<!-- ✅ 正确:CFBundleVersion必须递增 -->
<key>CFBundleShortVersionString</key>
<string>1.2.0</string> <!-- 可以增加 -->
<key>CFBundleVersion</key>
<string>2026031501</string> <!-- 必须增加 -->
进阶技巧1:条件化配置(多Target)
1
2
3
4
5
6
<!-- 在主Info.plist中定义变量 -->
<key>APP_BUNDLE_ID</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<!-- 在Target的Build Settings中覆盖 -->
PRODUCT_BUNDLE_IDENTIFIER = com.company.app.debug
进阶技巧2:动态读取配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 运行时读取Info.plist配置
class AppConfig {
static var bundleIdentifier: String {
return Bundle.main.bundleIdentifier ?? ""
}
static var versionString: String {
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
}
static func value<T>(forKey key: String) -> T? {
return Bundle.main.infoDictionary?[key] as? T
}
}
// 使用示例
let apiKey: String? = AppConfig.value(forKey: "API_KEY")
总结与记忆锚点
核心要点回顾
- 一个核心:Info.plist是iOS应用配置核心,定义身份、权限、兼容性
- 两个版本:CFBundleShortVersionString(用户可见) vs CFBundleVersion(内部递增)
- 三个必须:Bundle Identifier、版本信息、隐私权限描述(iOS 10+)
- 四个方向:Portrait、LandscapeLeft、LandscapeRight、PortraitUpsideDown
- 五类权限:相机、相册、定位、麦克风、通讯录等使用描述
一句话记忆类比
Info.plist是应用的”身份证+说明书+安全声明”:身份证(Bundle ID)证明身份,说明书(版本、方向)指导使用,安全声明(权限描述)告知风险与目的。
📋 快速自测(检验是否掌握)
- 用一句话解释Info.plist的作用
- 写出包含Bundle ID、版本号和相机权限描述的Info.plist片段
- 解释CFBundleShortVersionString和CFBundleVersion的区别及使用规则
- 描述缺失隐私权限描述(UsageDescription)的后果及正确做法
| *文档生成时间:2026-04-02 | 适配iOS 14+ (Xcode 15+) 规范 | 基于Apple官方文档及上架审核要求整理* |