Use when implementing iOS 17+ privacy manifests for CocoaPods libraries. Covers PrivacyInfo.xcprivacy file creation, required reasons API declarations, and proper resource bundle integration for App Store compliance.
Limited to specific tools
Additional assets for this skill
This skill is limited to using the following tools:
name: cocoapods-privacy-manifests description: Use when implementing iOS 17+ privacy manifests for CocoaPods libraries. Covers PrivacyInfo.xcprivacy file creation, required reasons API declarations, and proper resource bundle integration for App Store compliance. allowed-tools:
Implement iOS 17+ privacy manifests for App Store compliance and user transparency.
Privacy manifests (PrivacyInfo.xcprivacy) are XML property list files that declare:
Starting with iOS 17 and Xcode 15, Apple requires privacy manifests for:
<?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>
Pod::Spec.new do |spec|
spec.name = 'MyLibrary'
spec.version = '1.0.0'
spec.source_files = 'Source/**/*.swift'
# Include privacy manifest in resource bundle
spec.resource_bundles = {
'MyLibrary' => [
'Resources/**/*.xcprivacy',
'Resources/**/*.{png,jpg,xcassets}'
]
}
end
spec.resources = 'Resources/PrivacyInfo.xcprivacy'
# Or with glob pattern
spec.resources = 'Resources/**/*.xcprivacy'
MyLibrary/
├── MyLibrary.podspec
├── Source/
│ └── MyLibrary/
└── Resources/
├── PrivacyInfo.xcprivacy # Privacy manifest
└── Assets.xcassets
Apple requires declarations for these privacy-sensitive APIs:
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
Reason Codes:
C617.1: Display timestamps to user0A2A.1: Access timestamps of files in app container3B52.1: Access timestamps for app functionalityDDA9.1: Timestamp access for debugging<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
Reason Codes:
CA92.1: Access user defaults in same app group1C8F.1: Access user defaults for app functionalityC56D.1: SDK-specific configuration preferencesAC6B.1: Third-party SDK functionality<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
Reason Codes:
35F9.1: Measure time elapsed for app functionality8FFB.1: Calculate absolute timestamp3D61.1: Measure time for performance testing<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
Reason Codes:
85F4.1: Display disk space to userE174.1: Check disk space before file operations7D9E.1: Health/fitness app disk spaceB728.1: User-initiated file management<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>
NSPrivacyCollectedDataTypeEmailAddressNSPrivacyCollectedDataTypeNameNSPrivacyCollectedDataTypePhoneNumberNSPrivacyCollectedDataTypeDeviceIDNSPrivacyCollectedDataTypeUserIDNSPrivacyCollectedDataTypePreciseLocationNSPrivacyCollectedDataTypeCoarseLocationNSPrivacyCollectedDataTypeSearchHistoryNSPrivacyCollectedDataTypeBrowsingHistoryNSPrivacyCollectedDataTypePurposeThirdPartyAdvertisingNSPrivacyCollectedDataTypePurposeAppFunctionalityNSPrivacyCollectedDataTypePurposeAnalyticsNSPrivacyCollectedDataTypePurposeProductPersonalizationNSPrivacyCollectedDataTypePurposeOther<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>
<?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>
<!-- No tracking -->
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<!-- Data collection -->
<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>
<!-- Required Reasons APIs -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- User Defaults for caching -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
<!-- File timestamps for cache validation -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>3B52.1</string>
</array>
</dict>
</array>
</dict>
</plist>
<?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>
<!-- Tracking enabled -->
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.myservice.com</string>
</array>
<!-- Data collection -->
<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>
<!-- Required Reasons APIs -->
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>
Pod::Spec.new do |spec|
spec.name = 'MyAnalyticsSDK'
spec.version = '1.0.0'
spec.ios.deployment_target = '13.0'
spec.source_files = 'Source/**/*.swift'
# Include privacy manifest
spec.resource_bundles = {
'MyAnalyticsSDK' => [
'Resources/PrivacyInfo.xcprivacy'
]
}
# Platform-specific privacy manifests
spec.ios.resource_bundles = {
'MyAnalyticsSDK_iOS' => ['Resources/iOS/PrivacyInfo.xcprivacy']
}
spec.osx.resource_bundles = {
'MyAnalyticsSDK_macOS' => ['Resources/macOS/PrivacyInfo.xcprivacy']
}
end
# Lint with privacy manifest
pod lib lint
# Validate privacy manifest is included
pod lib lint --verbose | grep -i privacy
# Generate .xcarchive
xcodebuild archive -workspace MyApp.xcworkspace -scheme MyApp
# Validate before submission
xcodebuild -exportArchive -archivePath MyApp.xcarchive -exportPath MyApp.ipa -exportOptionsPlist ExportOptions.plist
<!-- Only declare what you actually use -->
<key>NSPrivacyCollectedDataTypes</key>
<array>
<!-- Only include if you actually collect this data -->
</array>
<!-- Use correct reason codes -->
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string> <!-- Must match actual usage -->
</array>
# Update privacy manifest when adding new APIs
spec.version = '1.1.0' # Bump version
# Update PrivacyInfo.xcprivacy with new declarations
❌ Omit privacy manifest for iOS 17+ apps
# Missing privacy manifest - App Store rejection risk
spec.resource_bundles = {
'MyLibrary' => ['Resources/**/*.png']
# No PrivacyInfo.xcprivacy
}
❌ Use incorrect reason codes
<string>WRONG.1</string> <!-- Invalid code -->
❌ Declare tracking without domains
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array/> <!-- Empty - inconsistent -->
✅ Include privacy manifest for all iOS SDKs
spec.resource_bundles = {
'MyLibrary' => ['Resources/PrivacyInfo.xcprivacy']
}
✅ Use accurate reason codes
<string>CA92.1</string> <!-- Valid, matches usage -->
✅ Be truthful about tracking
<key>NSPrivacyTracking</key>
<true/>
<key>NSPrivacyTrackingDomains</key>
<array>
<string>analytics.example.com</string>
</array>