Apple rejected my privacy manifest. The problem was a CocoaPod I never added.
Apple Review rejected one of my apps last month for the same reason it had
rejected three others before it: a missing NSPrivacyAccessedAPI declaration
in PrivacyInfo.xcprivacy. The reviewer copy was the standard wall of guideline
text, ending with “the following API was used without a declared reason: file
timestamp APIs.”
I didn’t use file timestamp APIs.
$ grep -rn "creationDate\|modificationDate\|attributesOfItem" \
--include="*.swift" --include="*.m" --include="*.mm" .
# (no results)
I went looking in Pods/. Specifically: Pods/<every-pod-name>/**.
$ grep -rn "attributesOfItem\|file.*Date" Pods/ --include="*.m" --include="*.swift"
Pods/SomeAnalyticsSDK/Sources/Diagnostic/FileMetricsCollector.m: ... attributesOfItemAtPath:
There it was. An analytics SDK I’d added two minor versions ago — for
crash-free-session metrics, never to actually use the file APIs. But the SDK
quietly initialized a FileMetricsCollector on launch, and that file was
calling attributesOfItemAtPath: to collect “diagnostic” data.
That call is tracked under NSPrivacyAccessedAPICategoryFileTimestamp.
Apple’s static scanner doesn’t care that I didn’t write the code. The binary
contains the symbol, my privacy manifest needs to declare it.
The fix
Add the entry to my own PrivacyInfo.xcprivacy:
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string> <!-- Inside app or group container -->
</array>
</dict>
</array>
Resubmit. Approved on round two. 36 hours total cycle time.
What I’d tell past me
Three checks I now run before every submission:
- Grep your own code for the API list Apple publishes for each category. If you don’t use it, move to step 2.
- Grep the entire
Pods/directory for the same calls. Find the offending SDK by file path, look up whichNSPrivacyAccessedAPICategory*it maps to. - Cross-reference with the SDK’s own privacy manifest if it ships one
(most do not). If the SDK declares the API in its own
PrivacyInfo.xcprivacy, you don’t need to in yours. If it doesn’t, you do.
This is mechanical. There’s no judgment call. So I automated it as
apple-presubmit-audit —
70+ App Store Review checks before you hit Submit, and the privacy-manifest
crawler walks both your sources and your Pods/ tree.
If you’ve shipped more than ten iOS apps you’ve probably been bitten by this specific class of bug at least twice. It’s the cleanest example of “Apple’s review is a static analyzer, and your CocoaPod tree is in scope.”
If you have a worse one, tell me on Bluesky. I’m collecting these.