npx claudepluginhub thebushidocollective/han --plugin cocoapodsThis skill is limited to using the following tools:
Implement iOS 17+ privacy manifests for App Store compliance and user transparency.
Implements iOS privacy manifests, permission requests, App Tracking Transparency UX, tracking domains, Required Reason APIs, and Nutrition Labels for App Store compliance.
Guides iOS app preparation for App Store review: rejection reasons, PrivacyInfo.xcprivacy manifests, StoreKit IAP rules, ATT flows, HIG checklists, metadata, and submission workflows.
Guides creation and modification of CocoaPods podspec files, covering required attributes, source file patterns, dependencies, and platform specs for iOS, macOS, tvOS, watchOS, visionOS.
Share bugs, ideas, or general feedback.
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>