名称: cocoapods-privacy-manifests 用户可调用: false 描述: 用于为CocoaPods库实现iOS 17+隐私清单。涵盖PrivacyInfo.xcprivacy文件创建、必要原因API声明以及适当的资源包集成以确保App Store合规性。 允许工具:
- 读取
- 写入
- 编辑
- Bash
- Grep
- Glob
CocoaPods - 隐私清单
为App Store合规性和用户透明度实现iOS 17+隐私清单。
什么是隐私清单?
隐私清单(PrivacyInfo.xcprivacy)是XML属性列表文件,声明:
- 数据收集和使用实践
- 必要原因API使用
- 跟踪域名
- 隐私敏感API
为什么需要隐私清单?
从iOS 17和Xcode 15开始,Apple要求隐私清单用于:
- 使用隐私敏感API的应用程序
- 第三方SDK和框架
- 任何访问用户数据的代码
隐私清单文件格式
基本结构
<?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>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array/>
</dict>
</plist>
在Podspec中包含
资源包(推荐)
Pod::Spec.new do |spec|
spec.name = 'MyLibrary'
spec.version = '1.0.0'
spec.source_files = 'Source/**/*.swift'
# 在资源包中包含隐私清单
spec.resource_bundles = {
'MyLibrary' => [
'Resources/**/*.xcprivacy',
'Resources/**/*.{png,jpg,xcassets}'
]
}
end
直接资源(替代)
spec.resources = 'Resources/PrivacyInfo.xcprivacy'
# 或使用glob模式
spec.resources = 'Resources/**/*.xcprivacy'
文件位置
MyLibrary/
├── MyLibrary.podspec
├── Source/
│ └── MyLibrary/
└── Resources/
├── PrivacyInfo.xcprivacy # 隐私清单
└── Assets.xcassets
必要原因API
常见需要原因的API
Apple要求为这些隐私敏感API声明原因:
文件时间戳API
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
原因代码:
C617.1: 向用户显示时间戳0A2A.1: 访问应用容器中文件的时间戳3B52.1: 为应用功能访问时间戳DDA9.1: 为调试访问时间戳
用户默认值API
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
原因代码:
CA92.1: 在同一应用组中访问用户默认值1C8F.1: 为应用功能访问用户默认值C56D.1: SDK特定配置偏好AC6B.1: 第三方SDK功能
系统启动时间API
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
原因代码:
35F9.1: 为应用功能测量经过时间8FFB.1: 计算绝对时间戳3D61.1: 为性能测试测量时间
磁盘空间API
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
原因代码:
85F4.1: 向用户显示磁盘空间E174.1: 在文件操作前检查磁盘空间7D9E.1: 健康/健身应用磁盘空间B728.1: 用户发起的文件管理
数据收集
声明收集的数据
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeEmailAddress</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
常见数据类型
NSPrivacyCollectedDataTypeEmailAddressNSPrivacyCollectedDataTypeNameNSPrivacyCollectedDataTypePhoneNumberNSPrivacyCollectedDataTypeDeviceIDNSPrivacyCollectedDataTypeUserIDNSPrivacyCollectedDataTypePreciseLocationNSPrivacyCollectedDataTypeCoarseLocationNSPrivacyCollectedDataTypeSearchHistoryNSPrivacyCollectedDataTypeBrowsingHistory
收集目的
NSPrivacyCollectedDataTypePurposeThirdPartyAdvertisingNSPrivacyCollectedDataTypePurposeAppFunctionalityNSPrivacyCollectedDataTypePurposeAnalyticsNSPrivacyCollectedDataTypePurposeProductPersonalizationNSPrivacyCollectedDataTypePurposeOther
跟踪配置
无跟踪
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
有跟踪
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.example.com</string>
<string>tracking.example.com</string>
</array>
完整示例
网络SDK隐私清单
<?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>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<!-- 数据收集 -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
<!-- 必要原因API -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- 用户默认值用于缓存 -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<!-- 文件时间戳用于缓存验证 -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>3B52.1</string>
</array>
</dict>
</array>
</dict>
</plist>
分析SDK隐私清单
<?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>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.myservice.com</string>
</array>
<!-- 数据收集 -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeDeviceID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<true/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
</array>
<!-- 必要原因API -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>
CocoaPods集成
Podspec配置
Pod::Spec.new do |spec|
spec.name = 'MyAnalyticsSDK'
spec.version = '1.0.0'
spec.ios.deployment_target = '13.0'
spec.source_files = 'Source/**/*.swift'
# 包含隐私清单
spec.resource_bundles = {
'MyAnalyticsSDK' => [
'Resources/PrivacyInfo.xcprivacy'
]
}
# 平台特定隐私清单
spec.ios.resource_bundles = {
'MyAnalyticsSDK_iOS' => ['Resources/iOS/PrivacyInfo.xcprivacy']
}
spec.osx.resource_bundles = {
'MyAnalyticsSDK_macOS' => ['Resources/macOS/PrivacyInfo.xcprivacy']
}
end
验证
检查隐私清单
# 使用隐私清单进行lint
pod lib lint
# 验证隐私清单是否包含
pod lib lint --verbose | grep -i privacy
Xcode验证
- 在Xcode中构建您的库
- 打开报告导航器
- 检查隐私警告
- 验证捆绑包中的隐私清单
App Store验证
# 生成.xcarchive
xcodebuild archive -workspace MyApp.xcworkspace -scheme MyApp
# 提交前验证
xcodebuild -exportArchive -archivePath MyApp.xcarchive -exportPath MyApp.ipa -exportOptionsPlist ExportOptions.plist
最佳实践
最小披露
<!-- 只声明实际使用的内容 -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<!-- 只有实际收集此数据时才包含 -->
</array>
准确原因
<!-- 使用正确的原因代码 -->
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string> <!-- 必须匹配实际使用 -->
</array>
定期更新
# 当添加新API时更新隐私清单
spec.version = '1.1.0' # 增加版本
# 使用新声明更新PrivacyInfo.xcprivacy
反模式
不要
❌ 为iOS 17+应用程序省略隐私清单
# 缺少隐私清单 - App Store拒绝风险
spec.resource_bundles = {
'MyLibrary' => ['Resources/**/*.png']
# 没有PrivacyInfo.xcprivacy
}
❌ 使用不正确的原因代码
<string>WRONG.1</string> <!-- 无效代码 -->
❌ 声明跟踪但没有域名
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array/> <!-- 空 - 不一致 -->
做
✅ 为所有iOS SDK包含隐私清单
spec.resource_bundles = {
'MyLibrary' => ['Resources/PrivacyInfo.xcprivacy']
}
✅ 使用准确的原因代码
<string>CA92.1</string> <!-- 有效,匹配使用 -->
✅ 真实关于跟踪
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.example.com</string>
</array>
资源
相关技能
- cocoapods-podspec-fundamentals
- cocoapods-subspecs-organization
- cocoapods-publishing-workflow