自 2024年5月1日 起,Apple 对 iOS 应用的上架隐私要求进行了强制性的重大升级。
现在的 iOS 隐私配置主要分为三个部分:
- 传统的权限申请 (Info.plist 中的 Usage Description)。
- App Store Connect 隐私标签 (在网页后台填写的"隐私数据")。
- 隐私清单文件 (PrivacyInfo.xcprivacy) (这是最新的、最核心的代码级配置)。
下面我将分模块详细介绍。
第一部分:基础隐私权限配置 (Info.plist)
这是最基础的,当 App 需要访问用户敏感数据(相机、相册、定位、麦克风等)时,必须在 Info.plist 中添加对应的键值对(Key-Value),并填写**"用途说明"**。
常见场景与配置:
| 功能 | Key (Info.plist) | 说明示例 (Value) |
|---|---|---|
| 相机 | NSCameraUsageDescription | "我们需要访问您的相机以拍摄头像。" |
| 相册(写入) | NSPhotoLibraryAddUsageDescription | "我们需要保存图片到您的相册。" |
| 相册(读取) | NSPhotoLibraryUsageDescription | "我们需要访问相册以选择图片上传。" |
| 定位(使用期间) | NSLocationWhenInUseUsageDescription | "我们需要您的位置以推荐附近的店铺。" |
| 定位(始终) | NSLocationAlwaysAndWhenInUseUsageDescription | "我们需要后台定位以记录运动轨迹。" |
| 麦克风 | NSMicrophoneUsageDescription | "我们需要访问麦克风以发送语音消息。" |
| 跟踪(IDFA) | NSUserTrackingUsageDescription | "我们需要您的许可来提供个性化的广告服务。" |
注意: 如果代码中引用了相关 API 但未配置 Key,App 会在触发该功能时直接崩溃 (Crash),审核也会被拒。
第二部分: App Store Connect 隐私标签配置
1. App Store Connect配置
-
步骤1:登录App Store Connect → 选择目标应用 → 侧边栏点击"App隐私"
-
步骤2:勾选应用涉及的数据类型(如位置、诊断数据等)→ 填写收集目的(如功能必需、个性化广告)
-
步骤3:填写隐私政策URL(需HTTPS协议)→ 提交后关联到应用版本
2. 应用内配置
在应用内设置页面或首次启动页添加隐私政策入口
swift
let privacyURL = URL(string: "https://yourdomain.com/privacy")!
UIApplication.shared.open(privacyURL)
// Flutter实现类似跳转也行
第三部分:隐私清单文件 (PrivacyInfo.xcprivacy)
这是 Apple 新引入的机制。App 和第三方 SDK 都需要包含一个名为 PrivacyInfo.xcprivacy 的文件。Xcode 会在打包(Archive)时将所有 SDK 的隐私清单聚合,生成一份隐私报告。
你需要创建一个新文件,类型选择 App Privacy (文件名默认为 PrivacyInfo.xcprivacy),并放入主工程目录(Target 勾选主 App)。
该文件主要包含以下四大类配置:
1. NSPrivacyAccessedAPITypes (受频繁访问的 API 类型)
Apple 规定了四类"高危"API,如果你的 App 或 SDK 使用了它们,必须声明使用的原因。
- 文件时间戳 API (File Timestamp)
- 场景:读取文件的创建/修改时间 (fstat, getattrlist 等)。
- 常用原因代码: C617.1 (仅在 App 容器内使用)。
- 系统启动时间 API (System Boot Time)
- 场景:计算设备运行时间 (systemUptime, mach_absolute_time 等)。
- 常用原因代码: 35F9.1 (用于计算相对时间事件)。
- 磁盘空间 API (Disk Space)
- 场景:检查手机剩余存储空间 (statfs, statvfs 等)。
- 常用原因代码: E174.1 (检查是否有足够空间写入文件)。
- 用户偏好设置 API (User Defaults)
- 场景:使用 UserDefaults 读写数据。
- 常用原因代码: CA92.1 (仅在 App 容器内访问 App 自身的数据)。
2. NSPrivacyCollectedDataTypes (收集的数据类型)
这里对应 App Store Connect 后台填写的隐私标签。你需要声明 App 收集了哪些数据(如:Name, Email, Phone Number, Device ID, Product Interaction 等)。
- 场景:如果你的 App 包含登录功能,通常需要声明收集 Contact Info。
3. NSPrivacyTracking (是否追踪)
- Boolean:YES 或 NO。
- 定义:是否将用户数据与第三方数据关联以用于广告定位(通常指是否获取 IDFA)。
4. NSPrivacyTrackingDomains (追踪域名)
- 如果开启了追踪,需要列出用于追踪的网络请求域名。如果用户拒绝追踪,iOS 会自动阻断对这些域名的请求。
第四部分:第三方库 (SDK) 如何配置
第三方库分为两种情况:Apple 指定签名的 SDK 和 普通 SDK。
1. Apple 指定的常用 SDK (Privacy-Impacting SDKs)
Apple 列出了一份名单(包括 Alamofire, Facebook SDK, Google Utilities, SDWebImage, Realm 等)。
- 强制要求 :这些 SDK 的厂商必须在其 SDK 内部包含签名的 PrivacyInfo.xcprivacy 文件。
- 你的工作:你需要将这些库升级到最新版本。例如,Alamofire 必须升级到 5.9.0+,SDWebImage 必须升级到 5.19.0+。如果旧版本没有签名文件,上传 App Store 会收到警告甚至被拒。
2. 普通第三方库
- 情况 A:库作者已经添加了隐私清单(最佳情况)。Xcode 会自动合并。
- 情况 B:库作者未维护或未添加。
- 做法 :你需要在你自己 App 的 PrivacyInfo.xcprivacy 中,代为声明该库所使用的"受访问 API"类型。
- 例如:某个旧的日志库使用了 statfs 查磁盘空间,你需要在你自己的清单里加上 Disk Space 的声明。
第五部分:Flutter 中的配置详解
Flutter 项目本质上是一个 iOS 工程壳子,因此规则完全一致,但配置路径略有不同。
1. 权限配置 (Info.plist)
在 Flutter 项目中,找到 ios/Runner/Info.plist,直接编辑 XML 或用 Xcode 打开添加权限描述。
- 注意:Flutter 的很多插件(如 image_picker)在 pubspec.yaml 引入后,你必须在 Info.plist 添加对应的 Key,否则一调用就崩。
2. 隐私清单配置 (PrivacyInfo.xcprivacy)
步骤 A:创建文件
- 使用 Xcode 打开 ios/Runner.xcworkspace。
- 右键 Runner 文件夹 -> New File -> 搜索 "App Privacy" -> 创建 PrivacyInfo.xcprivacy。
- 确保 Target 勾选了 Runner。
步骤 B:处理 Flutter 自身和插件的 API 使用 Flutter 引擎和常用插件(如 shared_preferences)使用了部分受限 API,你必须在你的 PrivacyInfo.xcprivacy 中声明,否则会有风险。
建议的通用 Flutter 隐私清单配置(供参考):
打开 PrivacyInfo.xcprivacy 的源码模式(Open As -> Source Code),可以粘贴以下基础配置(覆盖常见 Flutter 场景):
xml
<?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>NSPrivacyAccessedAPITypes</key>
<array>
<!-- UserDefaults: Flutter 的 shared_preferences 插件必用 -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPITypeUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<!-- File Timestamp: Flutter 引擎在处理文件时可能用到 -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPITypeFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<!-- Boot Time: 部分性能监控或工具类插件可能用到 -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPITypeSystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<!-- 根据实际情况填写,如果只是纯本地工具,这里可以为空 -->
</array>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
</dict>
</plist>
3. 处理 Flutter 的"远程插件" (Remote Plugins / Packages)
你提到的"远程插件"通常指通过 pubspec.yaml 引入的第三方包。
- 升级插件:运行 flutter pub upgrade。很多热门插件(如 dio, firebase_core)的新版本已经包含了 iOS 隐私清单。
- CocoaPods 合并:当运行 pod install 时,CocoaPods 会自动识别插件 iOS 文件夹下的 PrivacyInfo.xcprivacy。
- 如果插件没更新:
- 你需要去该插件的 GitHub 仓库查看 Issue,确认它是否使用了受限 API。
- 如果使用了(例如某个插件用了 UserDefaults 但没声明),你必须在你自己的 ios/Runner/PrivacyInfo.xcprivacy 中补充声明。
第六部分:最终验证方法 (生成隐私报告)
配置完成后,如何确认是否合规?
- 在 Xcode 中,选择顶部菜单 Product -> Archive。
- 打包完成后,在 Organizer 窗口中,选中刚刚的归档记录。
- 右键点击该记录,选择 Generate Privacy Report (生成隐私报告)。
- 保存并打开生成的 PDF 文件。
- 检查点:查看 PDF 中是否列出了所有你使用的 SDK?是否有遗漏的 API 类型?
- 如果某个 SDK 使用了 UserDefaults 但报告里的 "User Defaults" 一栏没有它,说明该 SDK 没配置好,或者被你漏掉了。
总结 Checklist
- Info.plist: 检查所有涉及硬件/数据的权限说明文案是否填写。
- SDK 版本: 检查 Podfile,确保 Alamofire, Realm, Firebase 等常用库都是最新版。
- PrivacyInfo.xcprivacy
- 确保工程里有这个文件。
- 确保声明了 NSPrivacyAccessedAPITypeUserDefaults (代码 CA92.1),因为几乎所有 App 都会存点简单的配置。
- App Store Connect: 提交审核前,后台填写的隐私问卷必须与你的代码逻辑(和隐私清单)保持一致。
按照这个流程操作,你的 iOS App 就能顺利通过隐私审核。